multioutput indicators #15 + talib custom indicator support
This commit is contained in:
@ -252,10 +252,10 @@ def init(state: StrategyState):
|
||||
# High to Low Range: (high[-1] - low[-1]) / low[-1]
|
||||
|
||||
# Store the ratios in the bars dictionary
|
||||
state.dailyBars['upper_shadow_ratio'] = upper_shadow
|
||||
state.dailyBars['lower_shadow_ratio'] = lower_shadow
|
||||
state.dailyBars['body_size_ratio'] = body_size
|
||||
state.dailyBars['body_position_ratio'] = body_position
|
||||
state.dailyBars['upper_shadow_ratio'] = upper_shadow.tolist()
|
||||
state.dailyBars['lower_shadow_ratio'] = lower_shadow.tolist()
|
||||
state.dailyBars['body_size_ratio'] = body_size.tolist()
|
||||
state.dailyBars['body_position_ratio'] = body_position.tolist()
|
||||
|
||||
#printanyway("daily bars FILLED", state.dailyBars)
|
||||
#zatim ukladame do extData - pro instant indicatory a gui
|
||||
|
||||
@ -1488,6 +1488,8 @@ def preview_indicator_byTOML(id: UUID, indicator: InstantIndicator, save: bool =
|
||||
if output is None:
|
||||
return (-2, "output invalid (bar/tick)")
|
||||
|
||||
returns = safe_get(toml_parsed, 'returns', [])
|
||||
|
||||
custom_params = safe_get(toml_parsed, "cp", None)
|
||||
print("custom params",custom_params)
|
||||
|
||||
@ -1499,7 +1501,7 @@ def preview_indicator_byTOML(id: UUID, indicator: InstantIndicator, save: bool =
|
||||
detail = RunArchiveDetail(**val)
|
||||
#print("toto jsme si dotahnuli", detail.bars)
|
||||
|
||||
#pokud tento indikator jiz je v detailu, tak ho odmazeme
|
||||
#pokud tento indikator jiz je v detailu, tak ho odmazeme - jde o main
|
||||
#BAR indikatory
|
||||
if indicator.name in detail.indicators[0]:
|
||||
del detail.indicators[0][indicator.name]
|
||||
@ -1507,6 +1509,14 @@ def preview_indicator_byTOML(id: UUID, indicator: InstantIndicator, save: bool =
|
||||
elif indicator.name in detail.indicators[1]:
|
||||
del detail.indicators[1][indicator.name]
|
||||
|
||||
#to same i s pripdadnymi multivystupy
|
||||
if len(returns)>0:
|
||||
for ind_name in returns:
|
||||
if ind_name in detail.indicators[0]:
|
||||
del detail.indicators[0][ind_name]
|
||||
#CBAR indikatory
|
||||
elif ind_name in detail.indicators[1]:
|
||||
del detail.indicators[1][ind_name]
|
||||
|
||||
#new dicts
|
||||
new_bars = {key: [] for key in detail.bars.keys()}
|
||||
@ -1532,6 +1542,10 @@ def preview_indicator_byTOML(id: UUID, indicator: InstantIndicator, save: bool =
|
||||
state.cbar_indicators = detail.indicators[1] #mozna toto vubec neopotrebujeme
|
||||
new_inds[indicator.name] = []
|
||||
new_inds[indicator.name] = []
|
||||
#init multiinputu
|
||||
if len(returns)>0:
|
||||
for ind_name in returns:
|
||||
new_inds[ind_name] = []
|
||||
#pro tick, nechavame bary a nechavame volne pouze tickbary, nad kterymi iterujeme
|
||||
else:
|
||||
state.bars = new_bars
|
||||
@ -1539,6 +1553,10 @@ def preview_indicator_byTOML(id: UUID, indicator: InstantIndicator, save: bool =
|
||||
state.cbar_indicators = new_tick_inds
|
||||
new_tick_inds[indicator.name] = []
|
||||
new_tick_inds[indicator.name] = []
|
||||
#init multiinputu
|
||||
if len(returns)>0:
|
||||
for ind_name in returns:
|
||||
new_tick_inds[ind_name] = []
|
||||
|
||||
#pridavame dailyBars z extData
|
||||
if hasattr(detail, "ext_data") and "dailyBars" in detail.ext_data:
|
||||
@ -1577,6 +1595,10 @@ def preview_indicator_byTOML(id: UUID, indicator: InstantIndicator, save: bool =
|
||||
#inicializujeme 0 v novém indikatoru
|
||||
state.indicators[indicator.name].append(0)
|
||||
|
||||
#init pro multipuput
|
||||
for ind_name in returns:
|
||||
state.indicators[ind_name].append(0)
|
||||
|
||||
try:
|
||||
populate_dynamic_indicators(new_data, state)
|
||||
# res_code, new_val = custom_function(state, custom_params)
|
||||
@ -1587,11 +1609,19 @@ def preview_indicator_byTOML(id: UUID, indicator: InstantIndicator, save: bool =
|
||||
|
||||
|
||||
#print("Done", state.indicators[indicator.name])
|
||||
|
||||
output_dict = {}
|
||||
new_inds[indicator.name] = state.indicators[indicator.name]
|
||||
|
||||
#ukládáme do ArchRunneru
|
||||
detail.indicators[0][indicator.name] = new_inds[indicator.name]
|
||||
output_dict[indicator.name] = new_inds[indicator.name]
|
||||
|
||||
#to same s multiinputy:
|
||||
if len(returns)>0:
|
||||
for ind_name in returns:
|
||||
new_inds[ind_name] = state.indicators[ind_name]
|
||||
detail.indicators[0][ind_name] = new_inds[ind_name]
|
||||
output_dict[ind_name] = new_inds[ind_name]
|
||||
|
||||
#TOTOZNE PRO TICK INDICATOR
|
||||
else:
|
||||
@ -1622,6 +1652,10 @@ def preview_indicator_byTOML(id: UUID, indicator: InstantIndicator, save: bool =
|
||||
#inicializujeme 0 v novém indikatoru
|
||||
state.cbar_indicators[indicator.name].append(0)
|
||||
|
||||
#init pro multipuput
|
||||
for ind_name in returns:
|
||||
state.cbar_indicators[ind_name].append(0)
|
||||
|
||||
try:
|
||||
populate_dynamic_indicators(new_data, state)
|
||||
# res_code, new_val = custom_function(state, custom_params)
|
||||
@ -1631,12 +1665,19 @@ def preview_indicator_byTOML(id: UUID, indicator: InstantIndicator, save: bool =
|
||||
print(str(e) + format_exc())
|
||||
|
||||
#print("Done", state.indicators[indicator.name])
|
||||
|
||||
output_dict = {}
|
||||
new_tick_inds[indicator.name] = state.cbar_indicators[indicator.name]
|
||||
|
||||
#ukládáme do ArchRunneru
|
||||
detail.indicators[1][indicator.name] = new_tick_inds[indicator.name]
|
||||
output_dict[indicator.name] = new_tick_inds[indicator.name]
|
||||
|
||||
#to same s multiinputy:
|
||||
if len(returns)>0:
|
||||
for ind_name in returns:
|
||||
new_tick_inds[ind_name] = state.cbar_indicators[ind_name]
|
||||
detail.indicators[1][ind_name] = new_tick_inds[ind_name]
|
||||
output_dict[ind_name] = new_tick_inds[ind_name]
|
||||
|
||||
#do ext dat ukladame jmeno indikatoru (podle toho oznacuje jako zmenene)
|
||||
|
||||
@ -1654,18 +1695,25 @@ def preview_indicator_byTOML(id: UUID, indicator: InstantIndicator, save: bool =
|
||||
print("removed old from EXT_DATA")
|
||||
|
||||
#a pridame aktualni
|
||||
#NOTE - multivystupy tedy nebudou oznacene na GUI
|
||||
detail.ext_data["instantindicators"].append(indicator)
|
||||
print("added to EXT_DATA")
|
||||
|
||||
#updatneme ArchRunner
|
||||
res, val = update_archive_detail(id, detail)
|
||||
if res == 0:
|
||||
print(f"arch runner {id} updated")
|
||||
|
||||
|
||||
#output bude nyni ve formatu {key:list}
|
||||
|
||||
#vracime list, kde pozice 0 je bar indicators, pozice 1 je ticks indicators
|
||||
if output == "bar":
|
||||
return 0, [new_inds[indicator.name], []]
|
||||
return 0, [output_dict, []]
|
||||
#return 0, [new_inds[indicator.name], []]
|
||||
else:
|
||||
return 0, [[], new_tick_inds[indicator.name]]
|
||||
return 0, [[], output_dict]
|
||||
#return 0, [[], new_tick_inds[indicator.name]]
|
||||
|
||||
except Exception as e:
|
||||
print(str(e) + format_exc())
|
||||
|
||||
@ -484,7 +484,7 @@ def _delete_archived_runners_byBatchID(batch_id: str):
|
||||
#return indicator value for archived runner, return values list0 - bar indicators, list1 - ticks indicators
|
||||
#TBD mozna predelat na dict pro prehlednost
|
||||
@app.put("/archived_runners/{runner_id}/previewindicator", dependencies=[Depends(api_key_auth)], status_code=status.HTTP_200_OK)
|
||||
def _preview_indicator_byTOML(runner_id: UUID, indicator: InstantIndicator) -> list[list[float]]:
|
||||
def _preview_indicator_byTOML(runner_id: UUID, indicator: InstantIndicator) -> list[dict]:
|
||||
#mozna pak pridat name
|
||||
res, vals = cs.preview_indicator_byTOML(id=runner_id, indicator=indicator)
|
||||
if res == 0: return vals
|
||||
|
||||
@ -386,7 +386,7 @@ function chart_indicators(data, visible, offset) {
|
||||
//console.log("ZPETNE STRINGIFIED", TOML.stringify(TOML.parse(data.archRecord.stratvars_toml), {newline: '\n'}))
|
||||
//indicatory
|
||||
//console.log("indicatory TOML", stratvars_toml.stratvars.indicators)
|
||||
|
||||
indId = 1
|
||||
indicatorList.forEach((indicators, index, array) => {
|
||||
|
||||
//var indicators = data.indicators
|
||||
@ -401,6 +401,7 @@ function chart_indicators(data, visible, offset) {
|
||||
//pokud je v nastaveni scale, pouzijeme tu
|
||||
var scale = null
|
||||
var instant = null
|
||||
var returns = null
|
||||
//console.log(key)
|
||||
//zkusime zda nejde o instantni indikator z arch runneru
|
||||
if ((data.ext_data !== null) && (data.ext_data.instantindicators)) {
|
||||
@ -410,6 +411,7 @@ function chart_indicators(data, visible, offset) {
|
||||
cnf = instantIndicator.toml
|
||||
scale = TOML.parse(cnf).scale
|
||||
instant = 1
|
||||
returns = TOML.parse(cnf).returns
|
||||
}
|
||||
}
|
||||
//pokud nenalezeno, pak bereme standard
|
||||
@ -418,6 +420,7 @@ function chart_indicators(data, visible, offset) {
|
||||
if (stratvars_toml.stratvars.indicators[key]) {
|
||||
cnf = "#[stratvars.indicators."+key+"]"+TOML.stringify(stratvars_toml.stratvars.indicators[key], {newline: '\n'})
|
||||
scale = stratvars_toml.stratvars.indicators[key].scale
|
||||
returns = stratvars_toml.stratvars.indicators[key].returns
|
||||
}
|
||||
}
|
||||
// //kontriolujeme v addedInds
|
||||
@ -438,7 +441,7 @@ function chart_indicators(data, visible, offset) {
|
||||
// }
|
||||
|
||||
//initialize indicator and store reference to array
|
||||
var obj = {name: key, type: index, series: null, cnf:cnf, instant: instant}
|
||||
var obj = {name: key, type: index, series: null, cnf:cnf, instant: instant, returns: returns, indId:indId++}
|
||||
|
||||
//start
|
||||
//console.log(key)
|
||||
@ -623,23 +626,52 @@ function chart_indicators(data, visible, offset) {
|
||||
}
|
||||
|
||||
//sort by type first (0-bar,1-cbar inds) and then alphabetically
|
||||
indList.sort((a, b) => {
|
||||
if (a.type !== b.type) {
|
||||
return a.type - b.type;
|
||||
} else {
|
||||
let nameA = a.name.toUpperCase();
|
||||
let nameB = b.name.toUpperCase();
|
||||
if (nameA < nameB) {
|
||||
return -1;
|
||||
} else if (nameA > nameB) {
|
||||
return 1;
|
||||
} else {
|
||||
// If uppercase names are equal, compare original names to prioritize uppercase
|
||||
return a.name < b.name ? -1 : 1;
|
||||
}
|
||||
}
|
||||
// indList.sort((a, b) => {
|
||||
// if (a.type !== b.type) {
|
||||
// return a.type - b.type;
|
||||
// } else {
|
||||
// let nameA = a.name.toUpperCase();
|
||||
// let nameB = b.name.toUpperCase();
|
||||
// if (nameA < nameB) {
|
||||
// return -1;
|
||||
// } else if (nameA > nameB) {
|
||||
// return 1;
|
||||
// } else {
|
||||
// // If uppercase names are equal, compare original names to prioritize uppercase
|
||||
// return a.name < b.name ? -1 : 1;
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
|
||||
//SORTING tak, aby multioutputs atributy byly vzdy na konci dane skupiny (tzn. v zobrazeni jsou zpracovany svými rodiči)
|
||||
// Step 1: Create a Set of all names in 'returns' arrays
|
||||
const namesInReturns = new Set();
|
||||
indList.forEach(item => {
|
||||
if (Array.isArray(item.returns)) {
|
||||
item.returns.forEach(name => namesInReturns.add(name));
|
||||
}
|
||||
});
|
||||
|
||||
// Step 2: Custom sort function
|
||||
indList.sort((a, b) => {
|
||||
// First, sort by 'type'
|
||||
if (a.type !== b.type) {
|
||||
return a.type - b.type;
|
||||
}
|
||||
|
||||
// For items with the same 'type', apply secondary sorting
|
||||
const aInReturns = namesInReturns.has(a.name);
|
||||
const bInReturns = namesInReturns.has(b.name);
|
||||
|
||||
if (aInReturns && !bInReturns) return 1; // 'a' goes after 'b'
|
||||
if (!aInReturns && bInReturns) return -1; // 'a' goes before 'b'
|
||||
|
||||
// If both or neither are in 'returns', sort alphabetically by 'name'
|
||||
return a.name.localeCompare(b.name);
|
||||
});
|
||||
|
||||
|
||||
|
||||
//puvodni funkce
|
||||
// indList.sort((a, b) => {
|
||||
// const nameA = a.name.toUpperCase(); // ignore upper and lowercase
|
||||
|
||||
@ -149,10 +149,27 @@ $(document).ready(function () {
|
||||
//indName = $('#indicatorName').val()
|
||||
//updatneme/vytvorime klic v globalni promennou obsahujici vsechny arch data
|
||||
//TBD nebude fungovat az budu mit vic chartů otevřených - předělat
|
||||
if (data[0].length > 0) {
|
||||
archData.indicators[0][indName] = data[0]
|
||||
} else if (data[1].length > 0) {
|
||||
archData.indicators[1][indName] = data[1]
|
||||
|
||||
//v ramci podpory multioutputu je navrat nazevind:timeserie a to
|
||||
//pro indicators [0] nebo cbar_indicators [1] list
|
||||
if (Object.keys(data[0]).length > 0) {
|
||||
for (let key in data[0]) {
|
||||
if (data[0].hasOwnProperty(key)) {
|
||||
archData.indicators[0][key] = data[0][key]
|
||||
console.log("barind updatovan " + key)
|
||||
//console.log(data[0][key]);
|
||||
}
|
||||
}
|
||||
//archData.indicators[0][indName] = data[0]
|
||||
} else if (Object.keys(data[1]).length > 0) {
|
||||
for (let key in data[1]) {
|
||||
if (data[1].hasOwnProperty(key)) {
|
||||
archData.indicators[1][key] = data[1][key]
|
||||
console.log("cbarind updatovan " + key)
|
||||
//console.log(data[1][key]);
|
||||
}
|
||||
}
|
||||
//archData.indicators[1][indName] = data[1]
|
||||
}
|
||||
else {
|
||||
alert("neco spatne s response ", data)
|
||||
|
||||
@ -419,14 +419,16 @@ function remove_indicator_buttons() {
|
||||
}
|
||||
|
||||
//pomocna funkce pro vytvoreni buttonu indiaktoru
|
||||
function create_indicator_button(item, index, def) {
|
||||
function create_indicator_button(item, def, noaction = false) {
|
||||
// //div pro kazdy button
|
||||
// var buttonContainer = document.createElement('div');
|
||||
// buttonContainer.classList.add('button-container');
|
||||
|
||||
index = item.indId
|
||||
|
||||
var itemEl = document.createElement('button');
|
||||
itemEl.innerText = item.name;
|
||||
itemEl.id = "IND"+index;
|
||||
itemEl.id = "IND"+item.indId;
|
||||
itemEl.title = item.cnf
|
||||
itemEl.style.color = item.series.options().color;
|
||||
//pokud jde o pridanou on the fly - vybarvime jinak
|
||||
@ -450,9 +452,12 @@ function create_indicator_button(item, index, def) {
|
||||
// actionShow.id = "actionShow";
|
||||
// actionShow.textContent = "Show";
|
||||
|
||||
itemEl.addEventListener('click', function() {
|
||||
onItemClickedToggle(index);
|
||||
});
|
||||
//nepouzivat pro urcite pripady (napr. u hlavnich multioutputu indikatoru) - pouze nese predpis(right click) a left clickem zobrazi outputy
|
||||
if (!noaction) {
|
||||
itemEl.addEventListener('click', function() {
|
||||
onItemClickedToggle(item.indId);
|
||||
});
|
||||
}
|
||||
|
||||
// const actionEdit = document.createElement("div");
|
||||
// actionEdit.id = "actionEdit";
|
||||
@ -460,7 +465,7 @@ function create_indicator_button(item, index, def) {
|
||||
|
||||
itemEl.addEventListener('contextmenu', function(e) {
|
||||
//edit modal zatim nemame
|
||||
onItemClickedEdit(e, index);
|
||||
onItemClickedEdit(e, item.indId);
|
||||
});
|
||||
|
||||
// // Append the action buttons to the overlay.
|
||||
@ -480,13 +485,13 @@ function create_indicator_button(item, index, def) {
|
||||
function onResetClicked() {
|
||||
indList.forEach(function (item, index) {
|
||||
vis = true;
|
||||
const elem = document.getElementById("IND"+index);
|
||||
const elem = document.getElementById("IND"+item.indId);
|
||||
if (elem.classList.contains("switcher-active-item")) {
|
||||
vis = false;
|
||||
}
|
||||
elem.classList.toggle("switcher-active-item");
|
||||
if (indList[index].series) {
|
||||
indList[index].series.applyOptions({
|
||||
if (obj.series) {
|
||||
obj.series.applyOptions({
|
||||
visible: vis });
|
||||
}
|
||||
})
|
||||
@ -656,6 +661,10 @@ function mrkLineToggle() {
|
||||
}
|
||||
|
||||
|
||||
function get_ind_by_id(indId) {
|
||||
return indList.find(obj => obj.indId === indId);
|
||||
}
|
||||
|
||||
//toggle indiktoru
|
||||
function onItemClickedToggle(index) {
|
||||
vis = true;
|
||||
@ -665,25 +674,80 @@ function onItemClickedToggle(index) {
|
||||
}
|
||||
elem.classList.toggle("switcher-active-item");
|
||||
//v ifu kvuli workaroundu
|
||||
if (indList[index].series) {
|
||||
//console.log(indList[index].name, indList[index].series)
|
||||
indList[index].series.applyOptions({
|
||||
obj = get_ind_by_id(index)
|
||||
if (obj.series) {
|
||||
//console.log(obj.name, obj.series)
|
||||
obj.series.applyOptions({
|
||||
visible: vis });
|
||||
}
|
||||
//zatim takto workaround, pak vymyslet systemove pro vsechny tickbased indikatory
|
||||
tickIndicatorList = ["tick_price", "tick_volume"]
|
||||
if (tickIndicatorList.includes(indList[index].name)) {
|
||||
if (!vis && indList[index].series) {
|
||||
//console.log("pred", indList[index].name, indList[index].series)
|
||||
chart.removeSeries(indList[index].series)
|
||||
if (tickIndicatorList.includes(obj.name)) {
|
||||
if (!vis && obj.series) {
|
||||
//console.log("pred", obj.name, obj.series)
|
||||
chart.removeSeries(obj.series)
|
||||
chart.timeScale().fitContent();
|
||||
indList[index].series = null
|
||||
//console.log("po", indList[index].name, indList[index].series)
|
||||
obj.series = null
|
||||
//console.log("po", obj.name, obj.series)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//obalka pro collapsovatelny multioutput indicator button
|
||||
function create_multioutput_button(item, def, active) {
|
||||
//encapsulating dic
|
||||
var multiOutEl = document.createElement('div');
|
||||
//multiOutEl.id = "tickIndicatorsButtons"
|
||||
multiOutEl.classList.add('multiOut');
|
||||
multiOutEl.classList.add('switcher-item');
|
||||
//pouze def - u main indikatoru nepamatujeme stav a pozadujeme noaction pro leftclick
|
||||
itemEl = create_indicator_button(item, def, true);
|
||||
//hlavni button ridi expand/collapse
|
||||
itemEl.setAttribute('data-bs-toggle', 'collapse');
|
||||
itemEl.setAttribute('data-bs-target', '.'+item.name);
|
||||
itemEl.setAttribute('aria-expanded', 'true');
|
||||
itemEl.setAttribute('role', 'button');
|
||||
//itemEl.setAttribute('aria-controls', 'IND6 IND7 IND8');
|
||||
//itemEl.style.outline = 'dotted';
|
||||
itemEl.style.marginRight = '0px'
|
||||
|
||||
//prirazeni mainu do divu
|
||||
multiOutEl.appendChild(itemEl);
|
||||
|
||||
//pokud nektery z multivstupu je aktivni, pak nastavuju vse expanded
|
||||
const isAnyActive = activatedButtons.some(element => item.returns.includes(element));
|
||||
|
||||
item.returns.forEach(function (output_name,index) {
|
||||
active = false
|
||||
//find and process multioutput parameters
|
||||
const foundObject = indList.find(obj => obj.name == output_name);
|
||||
if (foundObject) {
|
||||
|
||||
//aplikujeme remembered state
|
||||
if ((activatedButtons) && (activatedButtons.includes(output_name))) {
|
||||
active = true
|
||||
}
|
||||
|
||||
console.log(foundObject.content); // Access and use the content
|
||||
itemEl = create_indicator_button(foundObject, def||active);
|
||||
|
||||
itemEl.classList.add('collapse')
|
||||
//pokud je aktivni jakykoliv, expandujeme vsechny
|
||||
if (active || isAnyActive) {
|
||||
itemEl.classList.add('show')
|
||||
}
|
||||
itemEl.classList.add(item.name)
|
||||
itemEl.style.marginRight = '0px'
|
||||
|
||||
multiOutEl.appendChild(itemEl);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
return multiOutEl
|
||||
}
|
||||
|
||||
//funkce pro vytvoreni buttonku indikatoru
|
||||
function populate_indicator_buttons(def) {
|
||||
|
||||
@ -692,37 +756,58 @@ function populate_indicator_buttons(def) {
|
||||
buttonElement.id = "indicatorsButtons"
|
||||
buttonElement.classList.add('switcher');
|
||||
|
||||
//incializujeme i bar pro cbar indikator sekci
|
||||
//incializujeme i div pro cbar indikator sekci
|
||||
var tickButtonElement = document.createElement('div');
|
||||
tickButtonElement.id = "tickIndicatorsButtons"
|
||||
tickButtonElement.classList.add('tickButtons');
|
||||
|
||||
already_processed = [];
|
||||
//iterace nad indikatory a vytvareni buttonků
|
||||
indList.forEach(function (item, index) {
|
||||
index_ind = index
|
||||
active = false
|
||||
index_ind = item.indId
|
||||
if (!already_processed.includes(item.name)) {
|
||||
active = false
|
||||
|
||||
//console.log("activatedButtons", activatedButtons)
|
||||
//console.log("obsahuje item.name", activatedButtons.includes(item.name), item.name)
|
||||
//pokud existuje v aktivnich pak
|
||||
//console.log("vytvarime button",item.name,activatedButtons)
|
||||
if ((activatedButtons) && (activatedButtons.includes(item.name))) {
|
||||
active = true
|
||||
}
|
||||
//bar indikatory jsou serazeny na zacarku
|
||||
if (item.type == 0) {
|
||||
//vytvoreni buttonku
|
||||
itemEl = create_indicator_button(item, index, def||active);
|
||||
//prirazeni do divu
|
||||
buttonElement.appendChild(itemEl);
|
||||
}
|
||||
//ted zbyvaji tick barové a ty dáme do separátního divu
|
||||
else
|
||||
{
|
||||
//vytvoreni buttonku
|
||||
itemEl = create_indicator_button(item, index, def||active);
|
||||
tickButtonElement.appendChild(itemEl)
|
||||
if ((activatedButtons) && (activatedButtons.includes(item.name))) {
|
||||
active = true
|
||||
}
|
||||
//bar indikatory jsou serazeny na zacarku
|
||||
if (item.type == 0) {
|
||||
//pokud jde o multiinput, pridame ihned souvisejici mutiinputy a vse dame do stejneho divu
|
||||
//(Object.keys(data[0]).length > 0)
|
||||
if (item.returns && item.returns.length > 0) {
|
||||
//prirazeni multiOut do buttonu
|
||||
multiOutEl = create_multioutput_button(item, def, active)
|
||||
|
||||
buttonElement.appendChild(multiOutEl);
|
||||
already_processed = already_processed.concat(item.returns)
|
||||
}
|
||||
else {
|
||||
//vytvoreni buttonku
|
||||
itemEl = create_indicator_button(item, def||active);
|
||||
//prirazeni do divu
|
||||
buttonElement.appendChild(itemEl);
|
||||
}
|
||||
}
|
||||
//ted zbyvaji tick barové a ty dáme do separátního divu
|
||||
else
|
||||
{
|
||||
//oper nejdriv multiinput
|
||||
if (item.returns && item.returns.length > 0) {
|
||||
|
||||
//prirazeni multiOut do buttonu
|
||||
multiOutEl = create_multioutput_button(item, def, active)
|
||||
tickButtonElement.appendChild(multiOutEl);
|
||||
already_processed = already_processed.concat(item.returns)
|
||||
}
|
||||
//standardni non multiinput
|
||||
else {
|
||||
//vytvoreni buttonku
|
||||
itemEl = create_indicator_button(item, def||active);
|
||||
tickButtonElement.appendChild(itemEl)
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
//nakonec pripojime cely div s tick based indicatory
|
||||
|
||||
@ -828,6 +828,53 @@ pre {
|
||||
background-color: #e1eff94d;;
|
||||
}
|
||||
|
||||
.multiOut {
|
||||
height: 20px;
|
||||
position: relative;
|
||||
/* background-color: rgb(174, 170, 163); */
|
||||
padding: 0px 0px 0px 0px;
|
||||
margin-right: 6px;
|
||||
margin-bottom: -6px;
|
||||
/* position: relative; */
|
||||
z-index: 1;
|
||||
/* cursor: pointer; */
|
||||
text-decoration: double;
|
||||
display: inline-block;
|
||||
/* padding: 1px 6px; */
|
||||
/* font-size: 14px; */
|
||||
/* color: #262b3e; */
|
||||
/* background-color: #818581; */
|
||||
background-color: #0202022e;
|
||||
margin-right: 8px;
|
||||
/* margin-bottom: 6px; */
|
||||
/* border: 1px; */
|
||||
border-radius: 4px;
|
||||
/* outline: solid 1px;
|
||||
outline-color: #323232; */
|
||||
/* outline-width: 1px; */
|
||||
border-style: none;
|
||||
outline-width: thin;
|
||||
outline-color: #5a5a5a;
|
||||
}
|
||||
|
||||
.multiOut.switcher-item::after {
|
||||
content: '';
|
||||
display: inline-block;
|
||||
margin-left: 5px;
|
||||
border-top: 5px solid transparent;
|
||||
border-bottom: 5px solid transparent;
|
||||
border-left: 5px solid; /* Arrow pointing right for collapsed state */
|
||||
}
|
||||
|
||||
.multiOut.switcher-item[aria-expanded="true"]::after {
|
||||
border-top: 5px solid transparent;
|
||||
border-bottom: 5px solid transparent;
|
||||
border-right: 5px solid; /* Arrow pointing left for expanded state */
|
||||
border-left: none;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.material-symbols-outlined {
|
||||
font-variation-settings:
|
||||
'FILL' 0,
|
||||
|
||||
@ -10,7 +10,7 @@ import math
|
||||
from collections import defaultdict
|
||||
|
||||
#indicator allowing to be based on any bar parameter (index, high,open,close,trades,volume, etc.)
|
||||
def barparams(state, params, name):
|
||||
def barparams(state, params, name, returns):
|
||||
funcName = "barparams"
|
||||
if params is None:
|
||||
return -2, "params required"
|
||||
|
||||
@ -9,22 +9,25 @@ from collections import defaultdict
|
||||
from scipy.stats import linregress
|
||||
from scipy.fft import fft
|
||||
from v2realbot.strategyblocks.indicators.helpers import value_or_indicator
|
||||
import pywt
|
||||
|
||||
#vstupem je bud indicator nebo bar parametr
|
||||
#na tomto vstupu dokaze provest zakladni statisticke funkce pro subpole X hodnot zpatky
|
||||
#podporovane functions: min, max, mean
|
||||
def basestats(state, params, name):
|
||||
def basestats(state, params, name, returns):
|
||||
funcName = "basestats"
|
||||
#name of indicator or
|
||||
source = safe_get(params, "source", None)
|
||||
lookback = safe_get(params, "lookback", None)
|
||||
func = safe_get(params, "function", None)
|
||||
returns = safe_get(params, "returns", None)
|
||||
|
||||
source_dict = defaultdict(list)
|
||||
source_dict[source] = get_source_series(state, source)
|
||||
|
||||
self = state.indicators[name]
|
||||
try:
|
||||
self = state.indicators[name]
|
||||
except KeyError:
|
||||
self = state.cbar_indicators[name]
|
||||
|
||||
if lookback is None:
|
||||
source_array = source_dict[source]
|
||||
|
||||
@ -69,7 +72,23 @@ def basestats(state, params, name):
|
||||
#val = 2 * (angle_deg / 180) - 1
|
||||
elif func =="stdev":
|
||||
val = np.std(source_array)
|
||||
#linregres slope
|
||||
#linregress mutlioutput
|
||||
# slope : float, Slope of the regression line.
|
||||
# intercept : float, Intercept of the regression line.
|
||||
# rvalue : float, The Pearson correlation coefficient. The square of rvalue is equal to the coefficient of determination.
|
||||
# pvalue : float, The p-value for a hypothesis test whose null hypothesis is that the slope is zero, using Wald Test with t-distribution of the test statistic. See alternative above for alternative hypotheses.
|
||||
# stderr : float
|
||||
elif func == "linregress":
|
||||
if len(source_array) < 4:
|
||||
return -2, "less than 4 elmnts"
|
||||
try:
|
||||
val = []
|
||||
np.seterr(all="raise")
|
||||
slope, intercept, rvalue, pvalue, stderr = linregress(np.arange(len(source_array)), source_array)
|
||||
val = [slope*1000, intercept,rvalue, pvalue, stderr]
|
||||
except FloatingPointError:
|
||||
return -2, "FloatingPointError"
|
||||
#linregres slope DECOMM
|
||||
elif func == "slope":
|
||||
if len(source_array) < 4:
|
||||
return -2, "less than 4 elmnts"
|
||||
@ -79,17 +98,82 @@ def basestats(state, params, name):
|
||||
val = val*1000
|
||||
except FloatingPointError:
|
||||
return -2, "FloatingPointError"
|
||||
#zatim takto, dokud nebudou podporovany indikatory s vice vystupnimi
|
||||
#zatim takto, dokud nebudou podporovany indikatory s vice vystupnimi - DECOMM
|
||||
elif func == "intercept":
|
||||
if len(source_array) < 4:
|
||||
return -2, "less than 4 elmnts"
|
||||
try:
|
||||
np.seterr(all="raise")
|
||||
_, val, _, _, _ = linregress(np.arange(len(source_array)), source_array)
|
||||
|
||||
val = round(val, 4)
|
||||
except FloatingPointError:
|
||||
return -2, "FloatingPointError"
|
||||
|
||||
#work with different wavelet names and change max_scale
|
||||
#https://chat.openai.com/c/44b917d7-43df-4d80-be2f-01a5ee92158b
|
||||
elif func == "wavelet":
|
||||
def extract_wavelet_features(time_series, wavelet_name='morl', max_scale=64):
|
||||
scales = np.arange(1, max_scale + 1)
|
||||
coefficients, frequencies = pywt.cwt(time_series, scales, wavelet_name)
|
||||
|
||||
# Extract features - for instance, mean and variance of coefficients at each scale
|
||||
mean_coeffs = np.mean(coefficients, axis=1)[-1] # Last value of mean coefficients
|
||||
var_coeffs = np.var(coefficients, axis=1)[-1] # Last value of variance of coefficients
|
||||
# Energy distribution for the latest segment
|
||||
energy = np.sum(coefficients**2, axis=1)[-1]
|
||||
|
||||
# Entropy for the latest segment
|
||||
entropy = -np.sum((coefficients**2) * np.log(coefficients**2), axis=1)[-1]
|
||||
|
||||
# Dominant and mean frequency for the latest segment
|
||||
dominant_frequency = frequencies[np.argmax(energy)]
|
||||
mean_frequency = 0 # np.average(frequencies, weights=energy)
|
||||
|
||||
return [energy, entropy, dominant_frequency, mean_frequency,mean_coeffs, var_coeffs]
|
||||
|
||||
time_series = np.array(source_array)
|
||||
|
||||
wavelet_name = "morl"
|
||||
max_scale = 64
|
||||
features = extract_wavelet_features(time_series)
|
||||
return 0, features
|
||||
|
||||
#better fourier for frequency bins as suggested here https://chat.openai.com/c/44b917d7-43df-4d80-be2f-01a5ee92158b
|
||||
elif func == "fourier":
|
||||
def compute_fft_features(time_series, num_bins):
|
||||
n = len(time_series)
|
||||
yf = fft(time_series)
|
||||
|
||||
# Frequency values for FFT output
|
||||
xf = np.linspace(0.0, 1.0/(2.0), n//2)
|
||||
|
||||
# Compute power spectrum
|
||||
power_spectrum = np.abs(yf[:n//2])**2
|
||||
|
||||
# Define frequency bins
|
||||
max_freq = 1.0 / 2.0
|
||||
bin_edges = np.linspace(0, max_freq, num_bins + 1)
|
||||
|
||||
# Initialize feature array
|
||||
features = np.zeros(num_bins)
|
||||
|
||||
# Compute power in each bin
|
||||
for i in range(num_bins):
|
||||
# Find indices of frequencies in this bin
|
||||
indices = np.where((xf >= bin_edges[i]) & (xf < bin_edges[i+1]))[0]
|
||||
features[i] = np.sum(power_spectrum[indices])
|
||||
|
||||
return features
|
||||
|
||||
# Example usage
|
||||
time_series = np.array(source_array) # Replace with your data
|
||||
num_bins = 20 # Example: 10 frequency bins
|
||||
features = compute_fft_features(time_series, num_bins)
|
||||
return 0, features.tolist()
|
||||
|
||||
#returns X frequencies
|
||||
elif func == "fourier_old":
|
||||
time_series = np.array(source_array)
|
||||
n = len(time_series)
|
||||
|
||||
@ -97,30 +181,50 @@ def basestats(state, params, name):
|
||||
yf = fft(time_series)
|
||||
xf = np.linspace(0.0, 1.0/(2.0), n//2)
|
||||
|
||||
#three most dominant frequencies
|
||||
dominant_frequencies = xf[np.argsort(np.abs(yf[:n//2]))[-3:]]
|
||||
state.ilog(lvl=1,e=f"IND {name}:{funcName} 3 dominant freq are {str(dominant_frequencies)}", **params)
|
||||
#rt = dict(zip(returns, dominant_frequencies.tolist()))
|
||||
return 0, dominant_frequencies.tolist()
|
||||
|
||||
if returns is not None:
|
||||
#vracime druhou
|
||||
if returns == "second":
|
||||
if len(dominant_frequencies) > 1:
|
||||
val = dominant_frequencies[-2]
|
||||
else:
|
||||
val = 0
|
||||
else:
|
||||
#vracime most dominant
|
||||
val = float(np.max(dominant_frequencies))
|
||||
return 0, val
|
||||
|
||||
# if returns is not None:
|
||||
# #vracime druhou
|
||||
# if returns == "second":
|
||||
# if len(dominant_frequencies) > 1:
|
||||
# val = dominant_frequencies[-2]
|
||||
# else:
|
||||
# val = 0
|
||||
# else:
|
||||
# #vracime most dominant
|
||||
# val = float(np.max(dominant_frequencies))
|
||||
# return 0, val
|
||||
|
||||
#returns histogram bins https://chat.openai.com/share/034f8742-b091-4859-8c3e-570edb9c1006
|
||||
# pocet vyskytu v danem binu
|
||||
elif func == "histogram":
|
||||
#takes only first N - items
|
||||
|
||||
# Convert to numpy array
|
||||
dt = np.array(source_array)
|
||||
#creates 4 buckets
|
||||
bins = 4
|
||||
mean_of_4th_bin = np.mean(dt[np.where(np.histogram(dt, bins)[1][3] <= dt)[0]])
|
||||
if not np.isfinite(mean_of_4th_bin):
|
||||
mean_of_4th_bin = 0
|
||||
return 0, float(mean_of_4th_bin)
|
||||
|
||||
# Create 4 bins
|
||||
bins = np.histogram_bin_edges(dt, bins=4)
|
||||
|
||||
# Assign elements to bins
|
||||
bin_indices = np.digitize(dt, bins)
|
||||
|
||||
# Calculate mean for each bin
|
||||
means = [dt[bin_indices == i].mean() if dt[bin_indices == i].size > 0 else 0 for i in range(1, len(bins))]
|
||||
return 0, dict(zip(returns, means))
|
||||
|
||||
# #takes only first N - items
|
||||
# dt = np.array(source_array)
|
||||
# #creates 4 buckets
|
||||
# bins = 4
|
||||
# mean_of_4th_bin = np.mean(dt[np.where(np.histogram(dt, bins)[1][3] <= dt)[0]])
|
||||
# if not np.isfinite(mean_of_4th_bin):
|
||||
# mean_of_4th_bin = 0
|
||||
# return 0, float(mean_of_4th_bin)
|
||||
|
||||
elif func == "maxima":
|
||||
if len(source_array) < 3:
|
||||
|
||||
@ -22,7 +22,7 @@ import importlib
|
||||
|
||||
#OBECNA trida pro statefull indicators - realized by class with the same name, deriving from parent IndicatorBase class
|
||||
#todo v initu inicializovat state.classed_indicators a ve stopu uklidit - resetovat
|
||||
def classed(state, params, name):
|
||||
def classed(state, params, name, returns):
|
||||
try:
|
||||
funcName = "classed"
|
||||
if params is None:
|
||||
|
||||
@ -23,7 +23,7 @@ from collections import defaultdict
|
||||
#novy podminkovy indikator, muze obsahovat az N podminek ve stejne syntaxy jako u signalu
|
||||
#u kazde podminky je hodnota, ktera se vraci pokud je true
|
||||
#hodi se pro vytvareni binarnich targetu pro ML
|
||||
def conditional(state, params, name):
|
||||
def conditional(state, params, name, returns):
|
||||
funcName = "conditional"
|
||||
if params is None:
|
||||
return -2, "params required"
|
||||
|
||||
@ -9,7 +9,7 @@ from collections import defaultdict
|
||||
|
||||
#strength, absolute change of parameter between current value and lookback value (n-past)
|
||||
#used for example to measure unusual peaks
|
||||
def delta(state, params, name):
|
||||
def delta(state, params, name, returns):
|
||||
funcName = "delta"
|
||||
source = safe_get(params, "source", None)
|
||||
lookback = safe_get(params, "lookback",1)
|
||||
|
||||
@ -8,7 +8,7 @@ import numpy as np
|
||||
from collections import defaultdict
|
||||
|
||||
#abs/rel divergence of two indicators
|
||||
def divergence(state, params, name):
|
||||
def divergence(state, params, name, returns):
|
||||
funcName = "indicatorDivergence"
|
||||
source1 = safe_get(params, "source1", None)
|
||||
source1_series = get_source_series(state, source1)
|
||||
|
||||
@ -9,7 +9,7 @@ from collections import defaultdict
|
||||
from v2realbot.strategyblocks.indicators.helpers import value_or_indicator
|
||||
#strength, absolute change of parameter between current value and lookback value (n-past)
|
||||
#used for example to measure unusual peaks
|
||||
def ema(state, params, name):
|
||||
def ema(state, params, name, returns):
|
||||
funcName = "ema"
|
||||
source = safe_get(params, "source", None)
|
||||
lookback = safe_get(params, "lookback",14)
|
||||
|
||||
@ -15,7 +15,7 @@ from copy import deepcopy
|
||||
#eval nyni umi i user-defined function, string operation and control statements
|
||||
|
||||
#teroeticky se dá pouzit i SYMPY - kde se daji vytvorit jednotlive symboly s urcitou funkcni
|
||||
def expression(state: StrategyState, params, name):
|
||||
def expression(state: StrategyState, params, name, returns):
|
||||
try:
|
||||
funcName = "expression"
|
||||
#indicator name
|
||||
@ -56,7 +56,17 @@ def expression(state: StrategyState, params, name):
|
||||
val = eval(operation, {'state': state, 'np': np, 'utls': utls, 'math' : math}, temp_ind_mapping)
|
||||
|
||||
#printanyway(val)
|
||||
val = 0 if not np.isfinite(val) else val
|
||||
|
||||
#toto dát nejspíš do custom_hubu asi te automaticky aplikovalo na vše
|
||||
if isinstance(val, list):
|
||||
for index, value in enumerate(val):
|
||||
val[index] = 0 if not np.isfinite(value) else value
|
||||
elif isinstance(val, dict):
|
||||
for key, value in val.items():
|
||||
val[key] = 0 if not np.isfinite(value) else value
|
||||
else:
|
||||
val = 0 if not np.isfinite(val) else val
|
||||
|
||||
#val = ne.evaluate(operation, state.ind_mapping)
|
||||
|
||||
state.ilog(lvl=1,e=f"IND {name}:{funcName} {operation=} res:{val}", **params)
|
||||
|
||||
@ -8,10 +8,11 @@ import numpy as np
|
||||
from collections import defaultdict
|
||||
from v2realbot.strategyblocks.indicators.helpers import value_or_indicator
|
||||
# from talib import BBANDS, MACD, RSI, MA_Type
|
||||
from talib import BBANDS
|
||||
|
||||
|
||||
#IMPLEMENTS different types of moving averages in package v2realbot.indicators.moving_averages
|
||||
def ma(state, params, name):
|
||||
def ma(state, params, name, returns):
|
||||
funcName = "ma"
|
||||
type = safe_get(params, "type", "ema")
|
||||
source = safe_get(params, "source", None)
|
||||
|
||||
@ -4,7 +4,7 @@ from v2realbot.strategyblocks.indicators.helpers import get_source_series, value
|
||||
|
||||
#allows basic mathematical operators to one or more indicators (add two indicator, add value to a indicator etc.)
|
||||
#REPLACED by EXPRESSION
|
||||
def mathop(state, params, name):
|
||||
def mathop(state, params, name, returns):
|
||||
funcName = "mathop"
|
||||
#indicator name
|
||||
source1 = safe_get(params, "source1", None)
|
||||
|
||||
@ -10,7 +10,7 @@ from collections import defaultdict
|
||||
"""
|
||||
|
||||
"""
|
||||
def model(state, params, ind_name):
|
||||
def model(state, params, ind_name, returns):
|
||||
funcName = "model"
|
||||
if params is None:
|
||||
return -2, "params required"
|
||||
|
||||
@ -9,7 +9,7 @@ from collections import defaultdict
|
||||
|
||||
#WIP -
|
||||
#testing custom indicator CODE
|
||||
def opengap(state, params, name):
|
||||
def opengap(state, params, name, returns):
|
||||
funcName = "opengap"
|
||||
param1 = safe_get(params, "param1")
|
||||
param2 = safe_get(params, "param2")
|
||||
|
||||
@ -10,7 +10,7 @@ from collections import defaultdict
|
||||
from v2realbot.strategyblocks.indicators.helpers import value_or_indicator
|
||||
#strength, absolute change of parameter between current value and lookback value (n-past)
|
||||
#used for example to measure unusual peaks
|
||||
def rsi(state, params, name):
|
||||
def rsi(state, params, name, returns):
|
||||
req_source = safe_get(params, "source", "vwap")
|
||||
rsi_length = safe_get(params, "length",14)
|
||||
start = safe_get(params, "start","linear") #linear/sharp
|
||||
|
||||
@ -10,7 +10,7 @@ import bisect
|
||||
|
||||
#strength, absolute change of parameter between current value and lookback value (n-past)
|
||||
#used for example to measure unusual peaks
|
||||
def sameprice(state, params, name):
|
||||
def sameprice(state, params, name, returns):
|
||||
funcName = "sameprice"
|
||||
typ = safe_get(params, "type", None)
|
||||
|
||||
|
||||
@ -8,7 +8,7 @@ import numpy as np
|
||||
from collections import defaultdict
|
||||
|
||||
#rate of change - last value of source indicator vs lookback value of lookback_priceline indicator
|
||||
def slope(state, params, name):
|
||||
def slope(state, params, name, returns):
|
||||
funcName = "slope"
|
||||
source = safe_get(params, "source", None)
|
||||
source_series = get_source_series(state, source)
|
||||
|
||||
77
v2realbot/strategyblocks/indicators/custom/talib_ind.py
Normal file
77
v2realbot/strategyblocks/indicators/custom/talib_ind.py
Normal file
@ -0,0 +1,77 @@
|
||||
from v2realbot.utils.utils import isrising, isfalling,zoneNY, price2dec, print, safe_get, is_still, is_window_open, eval_cond_dict, crossed_down, crossed_up, crossed, is_pivot, json_serial, pct_diff, create_new_bars, slice_dict_lists
|
||||
from v2realbot.strategy.base import StrategyState
|
||||
import v2realbot.indicators.moving_averages as mi
|
||||
from v2realbot.strategyblocks.indicators.helpers import get_source_series
|
||||
from rich import print as printanyway
|
||||
from traceback import format_exc
|
||||
import numpy as np
|
||||
from collections import defaultdict
|
||||
from v2realbot.strategyblocks.indicators.helpers import value_or_indicator
|
||||
# from talib import BBANDS, MACD, RSI, MA_Type
|
||||
import talib
|
||||
|
||||
|
||||
# příklad toml pro indikátor ATR(high, low, close, timeperiod=14)
|
||||
# POSITION MATTERS
|
||||
# params.series.high = "high" //series key určuje, že jde o série
|
||||
# params.series.low = "low"
|
||||
# params.series.low = "close"
|
||||
# params.val.timeperiod = 14 //val key určuje, že jde o konkrétní hodnotu, tzn. buď hodnotu nebo název série, ze které vezmu poslední hodnotu (v tom případě by to byl string)
|
||||
|
||||
|
||||
# params.series = ["high","low","close"] #pozicni parametry
|
||||
# params.keys.timeperiod = 14 #keyword argumenty
|
||||
|
||||
#TA-lib prijma positional arguments (zejmena teda ty series)m tzn. series musi byt pozicni
|
||||
|
||||
# lookback se aplikuje na vsechy ?
|
||||
|
||||
|
||||
#IMPLEMENTS usiong of any indicator from TA-lib library
|
||||
def talib_ind(state, params, name, returns):
|
||||
funcName = "ma"
|
||||
type = safe_get(params, "type", "SMA")
|
||||
#ßsource = safe_get(params, "source", None)
|
||||
lookback = safe_get(params, "lookback",None) #celkovy lookback pro vsechny vstupni serie
|
||||
start = safe_get(params, "start","linear") #linear/sharp
|
||||
defval = safe_get(params, "defval",0)
|
||||
|
||||
params = safe_get(params, "params", dict(series=[], keys=[]))
|
||||
#lookback muze byt odkaz na indikator, pak berem jeho hodnotu
|
||||
lookback = int(value_or_indicator(state, lookback))
|
||||
defval = int(value_or_indicator(state, defval))
|
||||
|
||||
|
||||
#TODO dopracovat caching, tzn. jen jednou pri inicializaci (linkuje se list) nicmene pri kazde iteraci musime prevest na numpy
|
||||
#NOTE doresit, kdyz je val indiaktor, aby se i po inicializaci bral z indikatoru (doresit az pokud bude treba)
|
||||
#NOTE doresit lookback, zda se aplikuje na vsechny pred volanim funkce nebo kdy?
|
||||
series_list = []
|
||||
keyArgs = {}
|
||||
for index, item in enumerate(params.get("series",[])):
|
||||
source_series = get_source_series(state, item)
|
||||
#upravujeme lookback pokud not enough values (staci jen pro prvni - jsou vsechny stejne)
|
||||
if index == 0 and lookback is not None:
|
||||
akt_pocet = len(source_series)
|
||||
if akt_pocet < lookback and start == "linear":
|
||||
lookback = akt_pocet
|
||||
|
||||
series_list.append(np.array(source_series[-lookback:] if lookback is not None else source_series))
|
||||
|
||||
for key, val in params.get("keys",{}).items():
|
||||
keyArgs[key] = int(value_or_indicator(state, val))
|
||||
|
||||
type = "talib."+type
|
||||
talib_function = eval(type)
|
||||
|
||||
ma_value = talib_function(*series_list, **keyArgs)
|
||||
|
||||
if not np.isfinite(ma_value[-1]):
|
||||
val = defval
|
||||
else:
|
||||
val = round(ma_value[-1],4)
|
||||
|
||||
if val == 0:
|
||||
val = defval
|
||||
|
||||
state.ilog(lvl=1,e=f"INSIDE {name}:{funcName} {val} {type=} {lookback=}", **params)
|
||||
return 0, val
|
||||
@ -20,7 +20,7 @@ pct_change_full_scale = #pct change that is considered 1, used in scaler to dete
|
||||
|
||||
TODO musi se signal trochu tahnout az kde se opravdu rozjede, aby si to model spojil
|
||||
"""""
|
||||
def target(state, params, name):
|
||||
def target(state, params, name, returns):
|
||||
funcName = "target"
|
||||
source = safe_get(params, "source", "vwap")
|
||||
source_series = get_source_series(state, source)
|
||||
|
||||
@ -17,7 +17,7 @@ Where
|
||||
- start is last crossing of source with ema and
|
||||
- end is the current position -1
|
||||
"""""
|
||||
def targetema(state, params, name):
|
||||
def targetema(state, params, name, returns):
|
||||
try:
|
||||
funcName = "targetema"
|
||||
window_length_value = safe_get(params, "window_length_value", None)
|
||||
|
||||
@ -10,7 +10,7 @@ from collections import defaultdict
|
||||
from v2realbot.strategyblocks.indicators.helpers import value_or_indicator
|
||||
|
||||
# Volume(or reference_source) Weighted moving Average
|
||||
def vwma(state, params, name):
|
||||
def vwma(state, params, name, returns):
|
||||
funcName = "vwma"
|
||||
source = safe_get(params, "source", None)
|
||||
ref_source = safe_get(params, "ref_source", "volume")
|
||||
|
||||
@ -46,6 +46,8 @@ def populate_dynamic_custom_indicator(data, state: StrategyState, name):
|
||||
save_to_past = int(safe_get(options, "save_to_past", 0))
|
||||
save_to_past_unit = safe_get(options, "save_to_past_unit", "position")
|
||||
|
||||
#pokud neni multioutput, davame vystup do stejnojmenne serie
|
||||
returns = safe_get(options, 'returns', [name])
|
||||
|
||||
def is_time_to_run():
|
||||
# on_confirmed_only = true (def. False)
|
||||
@ -139,15 +141,17 @@ def populate_dynamic_custom_indicator(data, state: StrategyState, name):
|
||||
state.vars.indicators[name]["last_run_index"] = data["index"]
|
||||
|
||||
|
||||
#pomocna funkce
|
||||
def save_to_past_func(indicators_dict,name,save_to_past_unit, steps, new_val):
|
||||
#pomocna funkce (returns je pole toho , co indikator vraci a ret_val je dictionary, kde key je item z pole a val hodnota)
|
||||
def save_to_past_func(indicators_dict,name,save_to_past_unit, steps, ret_val):
|
||||
if save_to_past_unit == "position":
|
||||
indicators_dict[name][-1-steps]=new_val
|
||||
for ind_name, ind_value in ret_val.items():
|
||||
indicators_dict[ind_name][-1-steps]=ind_value
|
||||
#time
|
||||
else:
|
||||
##find index X seconds ago
|
||||
lookback_idx = find_index_optimized(time_list=indicators_dict["time"], seconds=steps)
|
||||
indicators_dict[name][lookback_idx]=new_val
|
||||
for ind_name, ind_value in ret_val.items():
|
||||
indicators_dict[ind_name][lookback_idx]=ind_value
|
||||
|
||||
# - volame custom funkci pro ziskani hodnoty indikatoru
|
||||
# - tu ulozime jako novou hodnotu indikatoru a prepocteme MAcka pokud je pozadovane
|
||||
@ -157,40 +161,61 @@ def populate_dynamic_custom_indicator(data, state: StrategyState, name):
|
||||
|
||||
subtype = "ci."+subtype+"."+subtype
|
||||
custom_function = eval(subtype)
|
||||
res_code, new_val = custom_function(state, custom_params, name)
|
||||
res_code, ret_val = custom_function(state, custom_params, name, returns)
|
||||
if res_code == 0:
|
||||
save_to_past_func(indicators_dict,name,save_to_past_unit, save_to_past, new_val)
|
||||
state.ilog(lvl=1,e=f"IND {name} {subtype} VAL FROM FUNCTION: {new_val}", lastruntime=state.vars.indicators[name]["last_run_time"], lastrunindex=state.vars.indicators[name]["last_run_index"], save_to_past=save_to_past)
|
||||
#prepocitame MA if required
|
||||
if MA_length is not None:
|
||||
src = indicators_dict[name][-MA_length:]
|
||||
MA_res = ema(src, MA_length)
|
||||
MA_value = round(MA_res[-1],7)
|
||||
#ret_val byl puvodne jedna hodnota
|
||||
#nyni podporujeme multi output ve format dict(indName:value, indName2:value2...)
|
||||
|
||||
save_to_past_func(indicators_dict,name+"MA",save_to_past_unit, save_to_past, MA_value)
|
||||
state.ilog(lvl=0,e=f"IND {name}MA {subtype} {MA_value}",save_to_past=save_to_past)
|
||||
#podporujeme vystup (list, dict a single value) - vse se transformuje do dict formatu
|
||||
# pri listu zipneme s return) a vytvorime dict (v pripade mismatch sizes se matchnou jen kratsi)
|
||||
if isinstance(ret_val, list):
|
||||
ret_val = dict(zip(returns, ret_val))
|
||||
#pokud je to neco jineho nez dict (float,int..) jde o puvodni single output udelame z toho dict s hlavnim jmenem as key
|
||||
elif not isinstance(ret_val, dict):
|
||||
ret_val = {name: ret_val}
|
||||
#v ostatnich pripadech predpokladame jiz dict
|
||||
|
||||
save_to_past_func(indicators_dict,name,save_to_past_unit, save_to_past, ret_val)
|
||||
state.ilog(lvl=1,e=f"IND {name} {subtype} VAL FROM FUNCTION: {ret_val}", lastruntime=state.vars.indicators[name]["last_run_time"], lastrunindex=state.vars.indicators[name]["last_run_index"], save_to_past=save_to_past)
|
||||
#prepocitame MA if required
|
||||
#pokud je MA nastaveno, tak pocitame MAcka pro vsechny multiouputy, tzn. vytvorime novem multioutput dict (ma_val)
|
||||
if MA_length is not None:
|
||||
ma_val = {}
|
||||
for ind_name, ind_val in ret_val.items():
|
||||
src = indicators_dict[ind_name][-MA_length:]
|
||||
MA_res = ema(src, MA_length)
|
||||
MA_value = round(MA_res[-1],7)
|
||||
ma_val[ind_name+"MA"] = MA_value
|
||||
|
||||
save_to_past_func(indicators_dict,name+"MA",save_to_past_unit, save_to_past, ma_val)
|
||||
state.ilog(lvl=0,e=f"IND {name}MA {subtype} {ma_val}",save_to_past=save_to_past)
|
||||
|
||||
return
|
||||
|
||||
else:
|
||||
err = f"IND ERROR {name} {subtype}Funkce {custom_function} vratila {res_code} {new_val}."
|
||||
err = f"IND ERROR {name} {subtype}Funkce {custom_function} vratila {res_code} {ret_val}."
|
||||
raise Exception(err)
|
||||
|
||||
except Exception as e:
|
||||
if len(indicators_dict[name]) >= 2:
|
||||
indicators_dict[name][-1]=indicators_dict[name][-2]
|
||||
if MA_length is not None and len(indicators_dict[name+"MA"])>=2:
|
||||
indicators_dict[name+"MA"][-1]=indicators_dict[name+"MA"][-2]
|
||||
state.ilog(lvl=1,e=f"IND ERROR {name} {subtype} necháváme původní", message=str(e)+format_exc())
|
||||
use_last_values(indicators_dict, name, returns, MA_length)
|
||||
state.ilog(lvl=1,e=f"IND ERROR {name} {subtype} necháváme původní u vsech z returns", returns=str(returns), message=str(e)+format_exc())
|
||||
|
||||
else:
|
||||
state.ilog(lvl=0,e=f"IND {name} {subtype} COND NOT READY: {msg}")
|
||||
|
||||
state.ilog(lvl=0,e=f"IND {name} {subtype} COND NOT READY: {msg}", returns=returns)
|
||||
#not time to run - copy last value
|
||||
use_last_values(indicators_dict, name, returns, MA_length)
|
||||
state.ilog(lvl=0,e=f"IND {name} {subtype} NOT TIME TO RUN - value(and MA) still original", returns=returns)
|
||||
|
||||
#zde nechavame puvodni (pri multiinputu nastavime predchozi hodnoty u vsech vystupu v defaultnim returns)
|
||||
def use_last_values(indicators_dict, name, returns, MA_length):
|
||||
def use_last_values_(indicators_dict, name, MA_length):
|
||||
if len(indicators_dict[name]) >= 2:
|
||||
indicators_dict[name][-1]=indicators_dict[name][-2]
|
||||
|
||||
if MA_length is not None and len(indicators_dict[name+"MA"])>=2:
|
||||
indicators_dict[name+"MA"][-1]=indicators_dict[name+"MA"][-2]
|
||||
|
||||
state.ilog(lvl=0,e=f"IND {name} {subtype} NOT TIME TO RUN - value(and MA) still original")
|
||||
if returns is not None and len(returns)>0:
|
||||
for ind_name in returns:
|
||||
use_last_values_(indicators_dict, ind_name, MA_length)
|
||||
else:
|
||||
use_last_values_(indicators_dict, name, MA_length)
|
||||
|
||||
@ -32,10 +32,21 @@ def initialize_dynamic_indicators(state):
|
||||
case _:
|
||||
raise(f"ind output must be bar or tick {indname}")
|
||||
|
||||
#inicializujeme vzdy main
|
||||
indicators_dict[indname] = []
|
||||
#inicializujeme multioutputs
|
||||
returns = safe_get(indsettings, 'returns', [])
|
||||
for ind_name in returns:
|
||||
indicators_dict[ind_name] = []
|
||||
#pokud ma MA_length incializujeme i MA variantu
|
||||
if safe_get(indsettings, 'MA_length', False):
|
||||
indicators_dict[indname+"MA"] = []
|
||||
#inicializujeme bud v hlavni serii
|
||||
if len(returns)==0:
|
||||
indicators_dict[indname+"MA"] = []
|
||||
#nebo v multivystupech
|
||||
else:
|
||||
for ind_name in returns:
|
||||
indicators_dict[ind_name+"MA"] = []
|
||||
|
||||
#Specifické Inicializace dle type
|
||||
for option,value in list(indsettings.items()):
|
||||
|
||||
Reference in New Issue
Block a user