multioutput indicators #15 + talib custom indicator support

This commit is contained in:
David Brazda
2024-01-16 15:17:14 +01:00
parent 5d47a7ac58
commit c1145fec5b
28 changed files with 598 additions and 141 deletions

View File

@ -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

View File

@ -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())

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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,

View File

@ -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"

View File

@ -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:

View File

@ -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:

View File

@ -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"

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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"

View File

@ -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")

View File

@ -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

View File

@ -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)

View File

@ -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)

View 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

View File

@ -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)

View File

@ -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)

View File

@ -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")

View File

@ -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)

View File

@ -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()):