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]
|
# High to Low Range: (high[-1] - low[-1]) / low[-1]
|
||||||
|
|
||||||
# Store the ratios in the bars dictionary
|
# Store the ratios in the bars dictionary
|
||||||
state.dailyBars['upper_shadow_ratio'] = upper_shadow
|
state.dailyBars['upper_shadow_ratio'] = upper_shadow.tolist()
|
||||||
state.dailyBars['lower_shadow_ratio'] = lower_shadow
|
state.dailyBars['lower_shadow_ratio'] = lower_shadow.tolist()
|
||||||
state.dailyBars['body_size_ratio'] = body_size
|
state.dailyBars['body_size_ratio'] = body_size.tolist()
|
||||||
state.dailyBars['body_position_ratio'] = body_position
|
state.dailyBars['body_position_ratio'] = body_position.tolist()
|
||||||
|
|
||||||
#printanyway("daily bars FILLED", state.dailyBars)
|
#printanyway("daily bars FILLED", state.dailyBars)
|
||||||
#zatim ukladame do extData - pro instant indicatory a gui
|
#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:
|
if output is None:
|
||||||
return (-2, "output invalid (bar/tick)")
|
return (-2, "output invalid (bar/tick)")
|
||||||
|
|
||||||
|
returns = safe_get(toml_parsed, 'returns', [])
|
||||||
|
|
||||||
custom_params = safe_get(toml_parsed, "cp", None)
|
custom_params = safe_get(toml_parsed, "cp", None)
|
||||||
print("custom params",custom_params)
|
print("custom params",custom_params)
|
||||||
|
|
||||||
@ -1499,7 +1501,7 @@ def preview_indicator_byTOML(id: UUID, indicator: InstantIndicator, save: bool =
|
|||||||
detail = RunArchiveDetail(**val)
|
detail = RunArchiveDetail(**val)
|
||||||
#print("toto jsme si dotahnuli", detail.bars)
|
#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
|
#BAR indikatory
|
||||||
if indicator.name in detail.indicators[0]:
|
if indicator.name in detail.indicators[0]:
|
||||||
del detail.indicators[0][indicator.name]
|
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]:
|
elif indicator.name in detail.indicators[1]:
|
||||||
del detail.indicators[1][indicator.name]
|
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 dicts
|
||||||
new_bars = {key: [] for key in detail.bars.keys()}
|
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
|
state.cbar_indicators = detail.indicators[1] #mozna toto vubec neopotrebujeme
|
||||||
new_inds[indicator.name] = []
|
new_inds[indicator.name] = []
|
||||||
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
|
#pro tick, nechavame bary a nechavame volne pouze tickbary, nad kterymi iterujeme
|
||||||
else:
|
else:
|
||||||
state.bars = new_bars
|
state.bars = new_bars
|
||||||
@ -1539,6 +1553,10 @@ def preview_indicator_byTOML(id: UUID, indicator: InstantIndicator, save: bool =
|
|||||||
state.cbar_indicators = new_tick_inds
|
state.cbar_indicators = new_tick_inds
|
||||||
new_tick_inds[indicator.name] = []
|
new_tick_inds[indicator.name] = []
|
||||||
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
|
#pridavame dailyBars z extData
|
||||||
if hasattr(detail, "ext_data") and "dailyBars" in detail.ext_data:
|
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
|
#inicializujeme 0 v novém indikatoru
|
||||||
state.indicators[indicator.name].append(0)
|
state.indicators[indicator.name].append(0)
|
||||||
|
|
||||||
|
#init pro multipuput
|
||||||
|
for ind_name in returns:
|
||||||
|
state.indicators[ind_name].append(0)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
populate_dynamic_indicators(new_data, state)
|
populate_dynamic_indicators(new_data, state)
|
||||||
# res_code, new_val = custom_function(state, custom_params)
|
# 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])
|
#print("Done", state.indicators[indicator.name])
|
||||||
|
output_dict = {}
|
||||||
new_inds[indicator.name] = state.indicators[indicator.name]
|
new_inds[indicator.name] = state.indicators[indicator.name]
|
||||||
|
|
||||||
#ukládáme do ArchRunneru
|
#ukládáme do ArchRunneru
|
||||||
detail.indicators[0][indicator.name] = new_inds[indicator.name]
|
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
|
#TOTOZNE PRO TICK INDICATOR
|
||||||
else:
|
else:
|
||||||
@ -1622,6 +1652,10 @@ def preview_indicator_byTOML(id: UUID, indicator: InstantIndicator, save: bool =
|
|||||||
#inicializujeme 0 v novém indikatoru
|
#inicializujeme 0 v novém indikatoru
|
||||||
state.cbar_indicators[indicator.name].append(0)
|
state.cbar_indicators[indicator.name].append(0)
|
||||||
|
|
||||||
|
#init pro multipuput
|
||||||
|
for ind_name in returns:
|
||||||
|
state.cbar_indicators[ind_name].append(0)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
populate_dynamic_indicators(new_data, state)
|
populate_dynamic_indicators(new_data, state)
|
||||||
# res_code, new_val = custom_function(state, custom_params)
|
# 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(str(e) + format_exc())
|
||||||
|
|
||||||
#print("Done", state.indicators[indicator.name])
|
#print("Done", state.indicators[indicator.name])
|
||||||
|
output_dict = {}
|
||||||
new_tick_inds[indicator.name] = state.cbar_indicators[indicator.name]
|
new_tick_inds[indicator.name] = state.cbar_indicators[indicator.name]
|
||||||
|
|
||||||
#ukládáme do ArchRunneru
|
#ukládáme do ArchRunneru
|
||||||
detail.indicators[1][indicator.name] = new_tick_inds[indicator.name]
|
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)
|
#do ext dat ukladame jmeno indikatoru (podle toho oznacuje jako zmenene)
|
||||||
|
|
||||||
@ -1653,19 +1694,26 @@ def preview_indicator_byTOML(id: UUID, indicator: InstantIndicator, save: bool =
|
|||||||
detail.ext_data["instantindicators"].remove(ind)
|
detail.ext_data["instantindicators"].remove(ind)
|
||||||
print("removed old from EXT_DATA")
|
print("removed old from EXT_DATA")
|
||||||
|
|
||||||
#a pridame aktualni
|
#a pridame aktualni
|
||||||
|
#NOTE - multivystupy tedy nebudou oznacene na GUI
|
||||||
detail.ext_data["instantindicators"].append(indicator)
|
detail.ext_data["instantindicators"].append(indicator)
|
||||||
print("added to EXT_DATA")
|
print("added to EXT_DATA")
|
||||||
|
|
||||||
#updatneme ArchRunner
|
#updatneme ArchRunner
|
||||||
res, val = update_archive_detail(id, detail)
|
res, val = update_archive_detail(id, detail)
|
||||||
if res == 0:
|
if res == 0:
|
||||||
print(f"arch runner {id} updated")
|
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
|
#vracime list, kde pozice 0 je bar indicators, pozice 1 je ticks indicators
|
||||||
if output == "bar":
|
if output == "bar":
|
||||||
return 0, [new_inds[indicator.name], []]
|
return 0, [output_dict, []]
|
||||||
|
#return 0, [new_inds[indicator.name], []]
|
||||||
else:
|
else:
|
||||||
return 0, [[], new_tick_inds[indicator.name]]
|
return 0, [[], output_dict]
|
||||||
|
#return 0, [[], new_tick_inds[indicator.name]]
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(str(e) + format_exc())
|
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
|
#return indicator value for archived runner, return values list0 - bar indicators, list1 - ticks indicators
|
||||||
#TBD mozna predelat na dict pro prehlednost
|
#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)
|
@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
|
#mozna pak pridat name
|
||||||
res, vals = cs.preview_indicator_byTOML(id=runner_id, indicator=indicator)
|
res, vals = cs.preview_indicator_byTOML(id=runner_id, indicator=indicator)
|
||||||
if res == 0: return vals
|
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'}))
|
//console.log("ZPETNE STRINGIFIED", TOML.stringify(TOML.parse(data.archRecord.stratvars_toml), {newline: '\n'}))
|
||||||
//indicatory
|
//indicatory
|
||||||
//console.log("indicatory TOML", stratvars_toml.stratvars.indicators)
|
//console.log("indicatory TOML", stratvars_toml.stratvars.indicators)
|
||||||
|
indId = 1
|
||||||
indicatorList.forEach((indicators, index, array) => {
|
indicatorList.forEach((indicators, index, array) => {
|
||||||
|
|
||||||
//var indicators = data.indicators
|
//var indicators = data.indicators
|
||||||
@ -401,6 +401,7 @@ function chart_indicators(data, visible, offset) {
|
|||||||
//pokud je v nastaveni scale, pouzijeme tu
|
//pokud je v nastaveni scale, pouzijeme tu
|
||||||
var scale = null
|
var scale = null
|
||||||
var instant = null
|
var instant = null
|
||||||
|
var returns = null
|
||||||
//console.log(key)
|
//console.log(key)
|
||||||
//zkusime zda nejde o instantni indikator z arch runneru
|
//zkusime zda nejde o instantni indikator z arch runneru
|
||||||
if ((data.ext_data !== null) && (data.ext_data.instantindicators)) {
|
if ((data.ext_data !== null) && (data.ext_data.instantindicators)) {
|
||||||
@ -410,6 +411,7 @@ function chart_indicators(data, visible, offset) {
|
|||||||
cnf = instantIndicator.toml
|
cnf = instantIndicator.toml
|
||||||
scale = TOML.parse(cnf).scale
|
scale = TOML.parse(cnf).scale
|
||||||
instant = 1
|
instant = 1
|
||||||
|
returns = TOML.parse(cnf).returns
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//pokud nenalezeno, pak bereme standard
|
//pokud nenalezeno, pak bereme standard
|
||||||
@ -418,6 +420,7 @@ function chart_indicators(data, visible, offset) {
|
|||||||
if (stratvars_toml.stratvars.indicators[key]) {
|
if (stratvars_toml.stratvars.indicators[key]) {
|
||||||
cnf = "#[stratvars.indicators."+key+"]"+TOML.stringify(stratvars_toml.stratvars.indicators[key], {newline: '\n'})
|
cnf = "#[stratvars.indicators."+key+"]"+TOML.stringify(stratvars_toml.stratvars.indicators[key], {newline: '\n'})
|
||||||
scale = stratvars_toml.stratvars.indicators[key].scale
|
scale = stratvars_toml.stratvars.indicators[key].scale
|
||||||
|
returns = stratvars_toml.stratvars.indicators[key].returns
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// //kontriolujeme v addedInds
|
// //kontriolujeme v addedInds
|
||||||
@ -438,7 +441,7 @@ function chart_indicators(data, visible, offset) {
|
|||||||
// }
|
// }
|
||||||
|
|
||||||
//initialize indicator and store reference to array
|
//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
|
//start
|
||||||
//console.log(key)
|
//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
|
//sort by type first (0-bar,1-cbar inds) and then alphabetically
|
||||||
indList.sort((a, b) => {
|
// indList.sort((a, b) => {
|
||||||
if (a.type !== b.type) {
|
// if (a.type !== b.type) {
|
||||||
return a.type - b.type;
|
// return a.type - b.type;
|
||||||
} else {
|
// } else {
|
||||||
let nameA = a.name.toUpperCase();
|
// let nameA = a.name.toUpperCase();
|
||||||
let nameB = b.name.toUpperCase();
|
// let nameB = b.name.toUpperCase();
|
||||||
if (nameA < nameB) {
|
// if (nameA < nameB) {
|
||||||
return -1;
|
// return -1;
|
||||||
} else if (nameA > nameB) {
|
// } else if (nameA > nameB) {
|
||||||
return 1;
|
// return 1;
|
||||||
} else {
|
// } else {
|
||||||
// If uppercase names are equal, compare original names to prioritize uppercase
|
// // If uppercase names are equal, compare original names to prioritize uppercase
|
||||||
return a.name < b.name ? -1 : 1;
|
// 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
|
//puvodni funkce
|
||||||
// indList.sort((a, b) => {
|
// indList.sort((a, b) => {
|
||||||
// const nameA = a.name.toUpperCase(); // ignore upper and lowercase
|
// const nameA = a.name.toUpperCase(); // ignore upper and lowercase
|
||||||
|
|||||||
@ -149,10 +149,27 @@ $(document).ready(function () {
|
|||||||
//indName = $('#indicatorName').val()
|
//indName = $('#indicatorName').val()
|
||||||
//updatneme/vytvorime klic v globalni promennou obsahujici vsechny arch data
|
//updatneme/vytvorime klic v globalni promennou obsahujici vsechny arch data
|
||||||
//TBD nebude fungovat az budu mit vic chartů otevřených - předělat
|
//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]
|
//v ramci podpory multioutputu je navrat nazevind:timeserie a to
|
||||||
} else if (data[1].length > 0) {
|
//pro indicators [0] nebo cbar_indicators [1] list
|
||||||
archData.indicators[1][indName] = data[1]
|
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 {
|
else {
|
||||||
alert("neco spatne s response ", data)
|
alert("neco spatne s response ", data)
|
||||||
|
|||||||
@ -419,14 +419,16 @@ function remove_indicator_buttons() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//pomocna funkce pro vytvoreni buttonu indiaktoru
|
//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
|
// //div pro kazdy button
|
||||||
// var buttonContainer = document.createElement('div');
|
// var buttonContainer = document.createElement('div');
|
||||||
// buttonContainer.classList.add('button-container');
|
// buttonContainer.classList.add('button-container');
|
||||||
|
|
||||||
|
index = item.indId
|
||||||
|
|
||||||
var itemEl = document.createElement('button');
|
var itemEl = document.createElement('button');
|
||||||
itemEl.innerText = item.name;
|
itemEl.innerText = item.name;
|
||||||
itemEl.id = "IND"+index;
|
itemEl.id = "IND"+item.indId;
|
||||||
itemEl.title = item.cnf
|
itemEl.title = item.cnf
|
||||||
itemEl.style.color = item.series.options().color;
|
itemEl.style.color = item.series.options().color;
|
||||||
//pokud jde o pridanou on the fly - vybarvime jinak
|
//pokud jde o pridanou on the fly - vybarvime jinak
|
||||||
@ -450,9 +452,12 @@ function create_indicator_button(item, index, def) {
|
|||||||
// actionShow.id = "actionShow";
|
// actionShow.id = "actionShow";
|
||||||
// actionShow.textContent = "Show";
|
// actionShow.textContent = "Show";
|
||||||
|
|
||||||
itemEl.addEventListener('click', function() {
|
//nepouzivat pro urcite pripady (napr. u hlavnich multioutputu indikatoru) - pouze nese predpis(right click) a left clickem zobrazi outputy
|
||||||
onItemClickedToggle(index);
|
if (!noaction) {
|
||||||
});
|
itemEl.addEventListener('click', function() {
|
||||||
|
onItemClickedToggle(item.indId);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// const actionEdit = document.createElement("div");
|
// const actionEdit = document.createElement("div");
|
||||||
// actionEdit.id = "actionEdit";
|
// actionEdit.id = "actionEdit";
|
||||||
@ -460,7 +465,7 @@ function create_indicator_button(item, index, def) {
|
|||||||
|
|
||||||
itemEl.addEventListener('contextmenu', function(e) {
|
itemEl.addEventListener('contextmenu', function(e) {
|
||||||
//edit modal zatim nemame
|
//edit modal zatim nemame
|
||||||
onItemClickedEdit(e, index);
|
onItemClickedEdit(e, item.indId);
|
||||||
});
|
});
|
||||||
|
|
||||||
// // Append the action buttons to the overlay.
|
// // Append the action buttons to the overlay.
|
||||||
@ -480,13 +485,13 @@ function create_indicator_button(item, index, def) {
|
|||||||
function onResetClicked() {
|
function onResetClicked() {
|
||||||
indList.forEach(function (item, index) {
|
indList.forEach(function (item, index) {
|
||||||
vis = true;
|
vis = true;
|
||||||
const elem = document.getElementById("IND"+index);
|
const elem = document.getElementById("IND"+item.indId);
|
||||||
if (elem.classList.contains("switcher-active-item")) {
|
if (elem.classList.contains("switcher-active-item")) {
|
||||||
vis = false;
|
vis = false;
|
||||||
}
|
}
|
||||||
elem.classList.toggle("switcher-active-item");
|
elem.classList.toggle("switcher-active-item");
|
||||||
if (indList[index].series) {
|
if (obj.series) {
|
||||||
indList[index].series.applyOptions({
|
obj.series.applyOptions({
|
||||||
visible: vis });
|
visible: vis });
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -656,6 +661,10 @@ function mrkLineToggle() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function get_ind_by_id(indId) {
|
||||||
|
return indList.find(obj => obj.indId === indId);
|
||||||
|
}
|
||||||
|
|
||||||
//toggle indiktoru
|
//toggle indiktoru
|
||||||
function onItemClickedToggle(index) {
|
function onItemClickedToggle(index) {
|
||||||
vis = true;
|
vis = true;
|
||||||
@ -665,25 +674,80 @@ function onItemClickedToggle(index) {
|
|||||||
}
|
}
|
||||||
elem.classList.toggle("switcher-active-item");
|
elem.classList.toggle("switcher-active-item");
|
||||||
//v ifu kvuli workaroundu
|
//v ifu kvuli workaroundu
|
||||||
if (indList[index].series) {
|
obj = get_ind_by_id(index)
|
||||||
//console.log(indList[index].name, indList[index].series)
|
if (obj.series) {
|
||||||
indList[index].series.applyOptions({
|
//console.log(obj.name, obj.series)
|
||||||
|
obj.series.applyOptions({
|
||||||
visible: vis });
|
visible: vis });
|
||||||
}
|
}
|
||||||
//zatim takto workaround, pak vymyslet systemove pro vsechny tickbased indikatory
|
//zatim takto workaround, pak vymyslet systemove pro vsechny tickbased indikatory
|
||||||
tickIndicatorList = ["tick_price", "tick_volume"]
|
tickIndicatorList = ["tick_price", "tick_volume"]
|
||||||
if (tickIndicatorList.includes(indList[index].name)) {
|
if (tickIndicatorList.includes(obj.name)) {
|
||||||
if (!vis && indList[index].series) {
|
if (!vis && obj.series) {
|
||||||
//console.log("pred", indList[index].name, indList[index].series)
|
//console.log("pred", obj.name, obj.series)
|
||||||
chart.removeSeries(indList[index].series)
|
chart.removeSeries(obj.series)
|
||||||
chart.timeScale().fitContent();
|
chart.timeScale().fitContent();
|
||||||
indList[index].series = null
|
obj.series = null
|
||||||
//console.log("po", indList[index].name, indList[index].series)
|
//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
|
//funkce pro vytvoreni buttonku indikatoru
|
||||||
function populate_indicator_buttons(def) {
|
function populate_indicator_buttons(def) {
|
||||||
|
|
||||||
@ -692,37 +756,58 @@ function populate_indicator_buttons(def) {
|
|||||||
buttonElement.id = "indicatorsButtons"
|
buttonElement.id = "indicatorsButtons"
|
||||||
buttonElement.classList.add('switcher');
|
buttonElement.classList.add('switcher');
|
||||||
|
|
||||||
//incializujeme i bar pro cbar indikator sekci
|
//incializujeme i div pro cbar indikator sekci
|
||||||
var tickButtonElement = document.createElement('div');
|
var tickButtonElement = document.createElement('div');
|
||||||
tickButtonElement.id = "tickIndicatorsButtons"
|
tickButtonElement.id = "tickIndicatorsButtons"
|
||||||
tickButtonElement.classList.add('tickButtons');
|
tickButtonElement.classList.add('tickButtons');
|
||||||
|
|
||||||
|
already_processed = [];
|
||||||
//iterace nad indikatory a vytvareni buttonků
|
//iterace nad indikatory a vytvareni buttonků
|
||||||
indList.forEach(function (item, index) {
|
indList.forEach(function (item, index) {
|
||||||
index_ind = index
|
index_ind = item.indId
|
||||||
active = false
|
if (!already_processed.includes(item.name)) {
|
||||||
|
active = false
|
||||||
|
|
||||||
//console.log("activatedButtons", activatedButtons)
|
if ((activatedButtons) && (activatedButtons.includes(item.name))) {
|
||||||
//console.log("obsahuje item.name", activatedButtons.includes(item.name), item.name)
|
active = true
|
||||||
//pokud existuje v aktivnich pak
|
}
|
||||||
//console.log("vytvarime button",item.name,activatedButtons)
|
//bar indikatory jsou serazeny na zacarku
|
||||||
if ((activatedButtons) && (activatedButtons.includes(item.name))) {
|
if (item.type == 0) {
|
||||||
active = true
|
//pokud jde o multiinput, pridame ihned souvisejici mutiinputy a vse dame do stejneho divu
|
||||||
}
|
//(Object.keys(data[0]).length > 0)
|
||||||
//bar indikatory jsou serazeny na zacarku
|
if (item.returns && item.returns.length > 0) {
|
||||||
if (item.type == 0) {
|
//prirazeni multiOut do buttonu
|
||||||
//vytvoreni buttonku
|
multiOutEl = create_multioutput_button(item, def, active)
|
||||||
itemEl = create_indicator_button(item, index, def||active);
|
|
||||||
//prirazeni do divu
|
buttonElement.appendChild(multiOutEl);
|
||||||
buttonElement.appendChild(itemEl);
|
already_processed = already_processed.concat(item.returns)
|
||||||
}
|
}
|
||||||
//ted zbyvaji tick barové a ty dáme do separátního divu
|
else {
|
||||||
else
|
//vytvoreni buttonku
|
||||||
{
|
itemEl = create_indicator_button(item, def||active);
|
||||||
//vytvoreni buttonku
|
//prirazeni do divu
|
||||||
itemEl = create_indicator_button(item, index, def||active);
|
buttonElement.appendChild(itemEl);
|
||||||
tickButtonElement.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
|
//nakonec pripojime cely div s tick based indicatory
|
||||||
|
|||||||
@ -828,6 +828,53 @@ pre {
|
|||||||
background-color: #e1eff94d;;
|
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 {
|
.material-symbols-outlined {
|
||||||
font-variation-settings:
|
font-variation-settings:
|
||||||
'FILL' 0,
|
'FILL' 0,
|
||||||
|
|||||||
@ -10,7 +10,7 @@ import math
|
|||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
|
|
||||||
#indicator allowing to be based on any bar parameter (index, high,open,close,trades,volume, etc.)
|
#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"
|
funcName = "barparams"
|
||||||
if params is None:
|
if params is None:
|
||||||
return -2, "params required"
|
return -2, "params required"
|
||||||
|
|||||||
@ -9,22 +9,25 @@ from collections import defaultdict
|
|||||||
from scipy.stats import linregress
|
from scipy.stats import linregress
|
||||||
from scipy.fft import fft
|
from scipy.fft import fft
|
||||||
from v2realbot.strategyblocks.indicators.helpers import value_or_indicator
|
from v2realbot.strategyblocks.indicators.helpers import value_or_indicator
|
||||||
|
import pywt
|
||||||
|
|
||||||
#vstupem je bud indicator nebo bar parametr
|
#vstupem je bud indicator nebo bar parametr
|
||||||
#na tomto vstupu dokaze provest zakladni statisticke funkce pro subpole X hodnot zpatky
|
#na tomto vstupu dokaze provest zakladni statisticke funkce pro subpole X hodnot zpatky
|
||||||
#podporovane functions: min, max, mean
|
#podporovane functions: min, max, mean
|
||||||
def basestats(state, params, name):
|
def basestats(state, params, name, returns):
|
||||||
funcName = "basestats"
|
funcName = "basestats"
|
||||||
#name of indicator or
|
#name of indicator or
|
||||||
source = safe_get(params, "source", None)
|
source = safe_get(params, "source", None)
|
||||||
lookback = safe_get(params, "lookback", None)
|
lookback = safe_get(params, "lookback", None)
|
||||||
func = safe_get(params, "function", None)
|
func = safe_get(params, "function", None)
|
||||||
returns = safe_get(params, "returns", None)
|
|
||||||
|
|
||||||
source_dict = defaultdict(list)
|
source_dict = defaultdict(list)
|
||||||
source_dict[source] = get_source_series(state, source)
|
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:
|
if lookback is None:
|
||||||
source_array = source_dict[source]
|
source_array = source_dict[source]
|
||||||
|
|
||||||
@ -69,7 +72,23 @@ def basestats(state, params, name):
|
|||||||
#val = 2 * (angle_deg / 180) - 1
|
#val = 2 * (angle_deg / 180) - 1
|
||||||
elif func =="stdev":
|
elif func =="stdev":
|
||||||
val = np.std(source_array)
|
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":
|
elif func == "slope":
|
||||||
if len(source_array) < 4:
|
if len(source_array) < 4:
|
||||||
return -2, "less than 4 elmnts"
|
return -2, "less than 4 elmnts"
|
||||||
@ -79,17 +98,82 @@ def basestats(state, params, name):
|
|||||||
val = val*1000
|
val = val*1000
|
||||||
except FloatingPointError:
|
except FloatingPointError:
|
||||||
return -2, "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":
|
elif func == "intercept":
|
||||||
if len(source_array) < 4:
|
if len(source_array) < 4:
|
||||||
return -2, "less than 4 elmnts"
|
return -2, "less than 4 elmnts"
|
||||||
try:
|
try:
|
||||||
np.seterr(all="raise")
|
np.seterr(all="raise")
|
||||||
_, val, _, _, _ = linregress(np.arange(len(source_array)), source_array)
|
_, val, _, _, _ = linregress(np.arange(len(source_array)), source_array)
|
||||||
|
|
||||||
val = round(val, 4)
|
val = round(val, 4)
|
||||||
except FloatingPointError:
|
except FloatingPointError:
|
||||||
return -2, "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":
|
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)
|
time_series = np.array(source_array)
|
||||||
n = len(time_series)
|
n = len(time_series)
|
||||||
|
|
||||||
@ -97,30 +181,50 @@ def basestats(state, params, name):
|
|||||||
yf = fft(time_series)
|
yf = fft(time_series)
|
||||||
xf = np.linspace(0.0, 1.0/(2.0), n//2)
|
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:]]
|
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)
|
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 is not None:
|
||||||
if returns == "second":
|
# #vracime druhou
|
||||||
if len(dominant_frequencies) > 1:
|
# if returns == "second":
|
||||||
val = dominant_frequencies[-2]
|
# if len(dominant_frequencies) > 1:
|
||||||
else:
|
# val = dominant_frequencies[-2]
|
||||||
val = 0
|
# else:
|
||||||
else:
|
# val = 0
|
||||||
#vracime most dominant
|
# else:
|
||||||
val = float(np.max(dominant_frequencies))
|
# #vracime most dominant
|
||||||
return 0, val
|
# 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":
|
elif func == "histogram":
|
||||||
#takes only first N - items
|
|
||||||
|
# Convert to numpy array
|
||||||
dt = np.array(source_array)
|
dt = np.array(source_array)
|
||||||
#creates 4 buckets
|
|
||||||
bins = 4
|
# Create 4 bins
|
||||||
mean_of_4th_bin = np.mean(dt[np.where(np.histogram(dt, bins)[1][3] <= dt)[0]])
|
bins = np.histogram_bin_edges(dt, bins=4)
|
||||||
if not np.isfinite(mean_of_4th_bin):
|
|
||||||
mean_of_4th_bin = 0
|
# Assign elements to bins
|
||||||
return 0, float(mean_of_4th_bin)
|
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":
|
elif func == "maxima":
|
||||||
if len(source_array) < 3:
|
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
|
#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
|
#todo v initu inicializovat state.classed_indicators a ve stopu uklidit - resetovat
|
||||||
def classed(state, params, name):
|
def classed(state, params, name, returns):
|
||||||
try:
|
try:
|
||||||
funcName = "classed"
|
funcName = "classed"
|
||||||
if params is None:
|
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
|
#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
|
#u kazde podminky je hodnota, ktera se vraci pokud je true
|
||||||
#hodi se pro vytvareni binarnich targetu pro ML
|
#hodi se pro vytvareni binarnich targetu pro ML
|
||||||
def conditional(state, params, name):
|
def conditional(state, params, name, returns):
|
||||||
funcName = "conditional"
|
funcName = "conditional"
|
||||||
if params is None:
|
if params is None:
|
||||||
return -2, "params required"
|
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)
|
#strength, absolute change of parameter between current value and lookback value (n-past)
|
||||||
#used for example to measure unusual peaks
|
#used for example to measure unusual peaks
|
||||||
def delta(state, params, name):
|
def delta(state, params, name, returns):
|
||||||
funcName = "delta"
|
funcName = "delta"
|
||||||
source = safe_get(params, "source", None)
|
source = safe_get(params, "source", None)
|
||||||
lookback = safe_get(params, "lookback",1)
|
lookback = safe_get(params, "lookback",1)
|
||||||
|
|||||||
@ -8,7 +8,7 @@ import numpy as np
|
|||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
|
|
||||||
#abs/rel divergence of two indicators
|
#abs/rel divergence of two indicators
|
||||||
def divergence(state, params, name):
|
def divergence(state, params, name, returns):
|
||||||
funcName = "indicatorDivergence"
|
funcName = "indicatorDivergence"
|
||||||
source1 = safe_get(params, "source1", None)
|
source1 = safe_get(params, "source1", None)
|
||||||
source1_series = get_source_series(state, source1)
|
source1_series = get_source_series(state, source1)
|
||||||
|
|||||||
@ -9,7 +9,7 @@ from collections import defaultdict
|
|||||||
from v2realbot.strategyblocks.indicators.helpers import value_or_indicator
|
from v2realbot.strategyblocks.indicators.helpers import value_or_indicator
|
||||||
#strength, absolute change of parameter between current value and lookback value (n-past)
|
#strength, absolute change of parameter between current value and lookback value (n-past)
|
||||||
#used for example to measure unusual peaks
|
#used for example to measure unusual peaks
|
||||||
def ema(state, params, name):
|
def ema(state, params, name, returns):
|
||||||
funcName = "ema"
|
funcName = "ema"
|
||||||
source = safe_get(params, "source", None)
|
source = safe_get(params, "source", None)
|
||||||
lookback = safe_get(params, "lookback",14)
|
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
|
#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
|
#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:
|
try:
|
||||||
funcName = "expression"
|
funcName = "expression"
|
||||||
#indicator name
|
#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)
|
val = eval(operation, {'state': state, 'np': np, 'utls': utls, 'math' : math}, temp_ind_mapping)
|
||||||
|
|
||||||
#printanyway(val)
|
#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)
|
#val = ne.evaluate(operation, state.ind_mapping)
|
||||||
|
|
||||||
state.ilog(lvl=1,e=f"IND {name}:{funcName} {operation=} res:{val}", **params)
|
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 collections import defaultdict
|
||||||
from v2realbot.strategyblocks.indicators.helpers import value_or_indicator
|
from v2realbot.strategyblocks.indicators.helpers import value_or_indicator
|
||||||
# from talib import BBANDS, MACD, RSI, MA_Type
|
# from talib import BBANDS, MACD, RSI, MA_Type
|
||||||
|
from talib import BBANDS
|
||||||
|
|
||||||
|
|
||||||
#IMPLEMENTS different types of moving averages in package v2realbot.indicators.moving_averages
|
#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"
|
funcName = "ma"
|
||||||
type = safe_get(params, "type", "ema")
|
type = safe_get(params, "type", "ema")
|
||||||
source = safe_get(params, "source", None)
|
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.)
|
#allows basic mathematical operators to one or more indicators (add two indicator, add value to a indicator etc.)
|
||||||
#REPLACED by EXPRESSION
|
#REPLACED by EXPRESSION
|
||||||
def mathop(state, params, name):
|
def mathop(state, params, name, returns):
|
||||||
funcName = "mathop"
|
funcName = "mathop"
|
||||||
#indicator name
|
#indicator name
|
||||||
source1 = safe_get(params, "source1", None)
|
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"
|
funcName = "model"
|
||||||
if params is None:
|
if params is None:
|
||||||
return -2, "params required"
|
return -2, "params required"
|
||||||
|
|||||||
@ -9,7 +9,7 @@ from collections import defaultdict
|
|||||||
|
|
||||||
#WIP -
|
#WIP -
|
||||||
#testing custom indicator CODE
|
#testing custom indicator CODE
|
||||||
def opengap(state, params, name):
|
def opengap(state, params, name, returns):
|
||||||
funcName = "opengap"
|
funcName = "opengap"
|
||||||
param1 = safe_get(params, "param1")
|
param1 = safe_get(params, "param1")
|
||||||
param2 = safe_get(params, "param2")
|
param2 = safe_get(params, "param2")
|
||||||
|
|||||||
@ -10,7 +10,7 @@ from collections import defaultdict
|
|||||||
from v2realbot.strategyblocks.indicators.helpers import value_or_indicator
|
from v2realbot.strategyblocks.indicators.helpers import value_or_indicator
|
||||||
#strength, absolute change of parameter between current value and lookback value (n-past)
|
#strength, absolute change of parameter between current value and lookback value (n-past)
|
||||||
#used for example to measure unusual peaks
|
#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")
|
req_source = safe_get(params, "source", "vwap")
|
||||||
rsi_length = safe_get(params, "length",14)
|
rsi_length = safe_get(params, "length",14)
|
||||||
start = safe_get(params, "start","linear") #linear/sharp
|
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)
|
#strength, absolute change of parameter between current value and lookback value (n-past)
|
||||||
#used for example to measure unusual peaks
|
#used for example to measure unusual peaks
|
||||||
def sameprice(state, params, name):
|
def sameprice(state, params, name, returns):
|
||||||
funcName = "sameprice"
|
funcName = "sameprice"
|
||||||
typ = safe_get(params, "type", None)
|
typ = safe_get(params, "type", None)
|
||||||
|
|
||||||
|
|||||||
@ -8,7 +8,7 @@ import numpy as np
|
|||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
|
|
||||||
#rate of change - last value of source indicator vs lookback value of lookback_priceline indicator
|
#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"
|
funcName = "slope"
|
||||||
source = safe_get(params, "source", None)
|
source = safe_get(params, "source", None)
|
||||||
source_series = get_source_series(state, source)
|
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
|
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"
|
funcName = "target"
|
||||||
source = safe_get(params, "source", "vwap")
|
source = safe_get(params, "source", "vwap")
|
||||||
source_series = get_source_series(state, source)
|
source_series = get_source_series(state, source)
|
||||||
|
|||||||
@ -17,7 +17,7 @@ Where
|
|||||||
- start is last crossing of source with ema and
|
- start is last crossing of source with ema and
|
||||||
- end is the current position -1
|
- end is the current position -1
|
||||||
"""""
|
"""""
|
||||||
def targetema(state, params, name):
|
def targetema(state, params, name, returns):
|
||||||
try:
|
try:
|
||||||
funcName = "targetema"
|
funcName = "targetema"
|
||||||
window_length_value = safe_get(params, "window_length_value", None)
|
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
|
from v2realbot.strategyblocks.indicators.helpers import value_or_indicator
|
||||||
|
|
||||||
# Volume(or reference_source) Weighted moving Average
|
# Volume(or reference_source) Weighted moving Average
|
||||||
def vwma(state, params, name):
|
def vwma(state, params, name, returns):
|
||||||
funcName = "vwma"
|
funcName = "vwma"
|
||||||
source = safe_get(params, "source", None)
|
source = safe_get(params, "source", None)
|
||||||
ref_source = safe_get(params, "ref_source", "volume")
|
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 = int(safe_get(options, "save_to_past", 0))
|
||||||
save_to_past_unit = safe_get(options, "save_to_past_unit", "position")
|
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():
|
def is_time_to_run():
|
||||||
# on_confirmed_only = true (def. False)
|
# 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"]
|
state.vars.indicators[name]["last_run_index"] = data["index"]
|
||||||
|
|
||||||
|
|
||||||
#pomocna funkce
|
#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, new_val):
|
def save_to_past_func(indicators_dict,name,save_to_past_unit, steps, ret_val):
|
||||||
if save_to_past_unit == "position":
|
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
|
#time
|
||||||
else:
|
else:
|
||||||
##find index X seconds ago
|
##find index X seconds ago
|
||||||
lookback_idx = find_index_optimized(time_list=indicators_dict["time"], seconds=steps)
|
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
|
# - volame custom funkci pro ziskani hodnoty indikatoru
|
||||||
# - tu ulozime jako novou hodnotu indikatoru a prepocteme MAcka pokud je pozadovane
|
# - 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
|
subtype = "ci."+subtype+"."+subtype
|
||||||
custom_function = eval(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:
|
if res_code == 0:
|
||||||
save_to_past_func(indicators_dict,name,save_to_past_unit, save_to_past, new_val)
|
#ret_val byl puvodne jedna hodnota
|
||||||
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)
|
#nyni podporujeme multi output ve format dict(indName:value, indName2:value2...)
|
||||||
#prepocitame MA if required
|
|
||||||
if MA_length is not None:
|
#podporujeme vystup (list, dict a single value) - vse se transformuje do dict formatu
|
||||||
src = indicators_dict[name][-MA_length:]
|
# pri listu zipneme s return) a vytvorime dict (v pripade mismatch sizes se matchnou jen kratsi)
|
||||||
MA_res = ema(src, MA_length)
|
if isinstance(ret_val, list):
|
||||||
MA_value = round(MA_res[-1],7)
|
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+"MA",save_to_past_unit, save_to_past, MA_value)
|
save_to_past_func(indicators_dict,name,save_to_past_unit, save_to_past, ret_val)
|
||||||
state.ilog(lvl=0,e=f"IND {name}MA {subtype} {MA_value}",save_to_past=save_to_past)
|
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
|
return
|
||||||
|
|
||||||
else:
|
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)
|
raise Exception(err)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
if len(indicators_dict[name]) >= 2:
|
use_last_values(indicators_dict, name, returns, MA_length)
|
||||||
indicators_dict[name][-1]=indicators_dict[name][-2]
|
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())
|
||||||
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())
|
|
||||||
|
|
||||||
else:
|
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
|
#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:
|
if len(indicators_dict[name]) >= 2:
|
||||||
indicators_dict[name][-1]=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:
|
if MA_length is not None and len(indicators_dict[name+"MA"])>=2:
|
||||||
indicators_dict[name+"MA"][-1]=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 _:
|
case _:
|
||||||
raise(f"ind output must be bar or tick {indname}")
|
raise(f"ind output must be bar or tick {indname}")
|
||||||
|
|
||||||
|
#inicializujeme vzdy main
|
||||||
indicators_dict[indname] = []
|
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
|
#pokud ma MA_length incializujeme i MA variantu
|
||||||
if safe_get(indsettings, 'MA_length', False):
|
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
|
#Specifické Inicializace dle type
|
||||||
for option,value in list(indsettings.items()):
|
for option,value in list(indsettings.items()):
|
||||||
|
|||||||
Reference in New Issue
Block a user