tick based support including gui preview, custom suppoer, new classed tickbased inds,#85
This commit is contained in:
@ -123,10 +123,11 @@ def init(state: StrategyState):
|
|||||||
intialize_directive_conditions(state)
|
intialize_directive_conditions(state)
|
||||||
|
|
||||||
#intitialize indicator mapping (for use in operation) - mozna presunout do samostatne funkce prip dat do base kdyz se osvedci
|
#intitialize indicator mapping (for use in operation) - mozna presunout do samostatne funkce prip dat do base kdyz se osvedci
|
||||||
|
local_dict_cbar_inds = {key: state.cbar_indicators[key] for key in state.cbar_indicators.keys() if key != "time"}
|
||||||
local_dict_inds = {key: state.indicators[key] for key in state.indicators.keys() if key != "time"}
|
local_dict_inds = {key: state.indicators[key] for key in state.indicators.keys() if key != "time"}
|
||||||
local_dict_bars = {key: state.bars[key] for key in state.bars.keys() if key != "time"}
|
local_dict_bars = {key: state.bars[key] for key in state.bars.keys() if key != "time"}
|
||||||
|
|
||||||
state.ind_mapping = {**local_dict_inds, **local_dict_bars}
|
state.ind_mapping = {**local_dict_inds, **local_dict_bars, **local_dict_cbar_inds}
|
||||||
print("IND MAPPING DONE:", state.ind_mapping)
|
print("IND MAPPING DONE:", state.ind_mapping)
|
||||||
|
|
||||||
#30 DAYS historicall data fill - pridat do base pokud se osvedci
|
#30 DAYS historicall data fill - pridat do base pokud se osvedci
|
||||||
|
|||||||
@ -1453,6 +1453,10 @@ def preview_indicator_byTOML(id: UUID, indicator: InstantIndicator, save: bool =
|
|||||||
subtype = safe_get(toml_parsed, 'subtype', False)
|
subtype = safe_get(toml_parsed, 'subtype', False)
|
||||||
if subtype is None:
|
if subtype is None:
|
||||||
return (-2, "subtype invalid")
|
return (-2, "subtype invalid")
|
||||||
|
|
||||||
|
output = safe_get(toml_parsed, 'output', "bar")
|
||||||
|
if output is None:
|
||||||
|
return (-2, "output invalid (bar/tick)")
|
||||||
|
|
||||||
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)
|
||||||
@ -1466,8 +1470,12 @@ def preview_indicator_byTOML(id: UUID, indicator: InstantIndicator, save: bool =
|
|||||||
#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
|
||||||
|
#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]
|
||||||
|
#CBAR indikatory
|
||||||
|
elif indicator.name in detail.indicators[1]:
|
||||||
|
del detail.indicators[1][indicator.name]
|
||||||
|
|
||||||
|
|
||||||
#new dicts
|
#new dicts
|
||||||
@ -1477,6 +1485,8 @@ def preview_indicator_byTOML(id: UUID, indicator: InstantIndicator, save: bool =
|
|||||||
new_data= AttributeDict(**new_data)
|
new_data= AttributeDict(**new_data)
|
||||||
new_inds = {key: [] for key in detail.indicators[0].keys()}
|
new_inds = {key: [] for key in detail.indicators[0].keys()}
|
||||||
new_inds = AttributeDict(**new_inds)
|
new_inds = AttributeDict(**new_inds)
|
||||||
|
new_tick_inds = {key: [] for key in detail.indicators[1].keys()}
|
||||||
|
new_tick_inds = AttributeDict(**new_tick_inds)
|
||||||
interface = BacktestInterface(symbol="X", bt=None)
|
interface = BacktestInterface(symbol="X", bt=None)
|
||||||
|
|
||||||
##dame nastaveni indikatoru do tvaru, ktery stratvars ocekava (pro dynmaicke inicializace)
|
##dame nastaveni indikatoru do tvaru, ktery stratvars ocekava (pro dynmaicke inicializace)
|
||||||
@ -1485,12 +1495,20 @@ def preview_indicator_byTOML(id: UUID, indicator: InstantIndicator, save: bool =
|
|||||||
|
|
||||||
state = StrategyState(name="XX", symbol = "X", stratvars = AttributeDict(**stratvars), interface=interface)
|
state = StrategyState(name="XX", symbol = "X", stratvars = AttributeDict(**stratvars), interface=interface)
|
||||||
|
|
||||||
#inicializujeme novy indikator v cilovem dict a stavovem inds.
|
#inicializujeme stavove promenne a novy indikator v cilovem dict
|
||||||
new_inds[indicator.name] = []
|
if output == "bar":
|
||||||
new_inds[indicator.name] = []
|
state.bars = new_bars
|
||||||
|
state.indicators = new_inds
|
||||||
state.bars = new_bars
|
state.cbar_indicators = detail.indicators[1] #mozna toto vubec neopotrebujeme
|
||||||
state.indicators = new_inds
|
new_inds[indicator.name] = []
|
||||||
|
new_inds[indicator.name] = []
|
||||||
|
#pro tick, nechavame bary a nechavame volne pouze tickbary, nad kterymi iterujeme
|
||||||
|
else:
|
||||||
|
state.bars = new_bars
|
||||||
|
state.indicators = new_inds
|
||||||
|
state.cbar_indicators = new_tick_inds
|
||||||
|
new_tick_inds[indicator.name] = []
|
||||||
|
new_tick_inds[indicator.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:
|
||||||
@ -1499,9 +1517,10 @@ def preview_indicator_byTOML(id: UUID, indicator: InstantIndicator, save: bool =
|
|||||||
print("delka",len(detail.bars["close"]))
|
print("delka",len(detail.bars["close"]))
|
||||||
|
|
||||||
#intitialize indicator mapping - in order to use eval in expression
|
#intitialize indicator mapping - in order to use eval in expression
|
||||||
|
local_dict_cbar_inds = {key: state.cbar_indicators[key] for key in state.cbar_indicators.keys() if key != "time"}
|
||||||
local_dict_inds = {key: state.indicators[key] for key in state.indicators.keys() if key != "time"}
|
local_dict_inds = {key: state.indicators[key] for key in state.indicators.keys() if key != "time"}
|
||||||
local_dict_bars = {key: state.bars[key] for key in state.bars.keys() if key != "time"}
|
local_dict_bars = {key: state.bars[key] for key in state.bars.keys() if key != "time"}
|
||||||
state.ind_mapping = {**local_dict_inds, **local_dict_bars}
|
state.ind_mapping = {**local_dict_inds, **local_dict_bars, **local_dict_cbar_inds}
|
||||||
print("IND MAPPING DONE:", state.ind_mapping)
|
print("IND MAPPING DONE:", state.ind_mapping)
|
||||||
|
|
||||||
##intialize dynamic indicators
|
##intialize dynamic indicators
|
||||||
@ -1513,34 +1532,81 @@ def preview_indicator_byTOML(id: UUID, indicator: InstantIndicator, save: bool =
|
|||||||
# print("funkce", function)
|
# print("funkce", function)
|
||||||
# custom_function = eval(function)
|
# custom_function = eval(function)
|
||||||
|
|
||||||
#iterujeme nad bary a on the fly pridavame novou hodnotu do vsech indikatoru a nakonec nad tim spustime indikator
|
#pokud jde o bar, tak cbary nemennime, nechavame je inicializovane plnou hodnotou pro pripadne dotazeni
|
||||||
#tak muzeme v toml pouzit i hodnoty ostatnich indikatoru
|
if output == "bar":
|
||||||
for i in range(len(detail.bars["close"])):
|
#iterujeme nad bary a on the fly pridavame novou hodnotu do vsech indikatoru a nakonec nad tim spustime indikator
|
||||||
for key in detail.bars:
|
#tak muzeme v toml pouzit i hodnoty ostatnich indikatoru
|
||||||
state.bars[key].append(detail.bars[key][i])
|
for i in range(len(detail.bars["close"])):
|
||||||
#naplnime i data aktualne
|
for key in detail.bars:
|
||||||
new_data[key] = state.bars[key][-1]
|
state.bars[key].append(detail.bars[key][i])
|
||||||
for key in detail.indicators[0]:
|
#naplnime i data aktualne
|
||||||
state.indicators[key].append(detail.indicators[0][key][i])
|
new_data[key] = state.bars[key][-1]
|
||||||
|
for key in detail.indicators[0]:
|
||||||
|
state.indicators[key].append(detail.indicators[0][key][i])
|
||||||
|
|
||||||
#inicializujeme 0 v novém indikatoru
|
#inicializujeme 0 v novém indikatoru
|
||||||
state.indicators[indicator.name].append(0)
|
state.indicators[indicator.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)
|
||||||
# if res_code == 0:
|
# if res_code == 0:
|
||||||
# new_inds[indicator.name][-1]=new_val
|
# new_inds[indicator.name][-1]=new_val
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(str(e) + format_exc())
|
print(str(e) + format_exc())
|
||||||
|
|
||||||
|
|
||||||
#print("Done", state.indicators[indicator.name])
|
#print("Done", state.indicators[indicator.name])
|
||||||
|
|
||||||
new_inds[indicator.name] = state.indicators[indicator.name]
|
|
||||||
|
|
||||||
#ukládáme do ArchRunneru
|
new_inds[indicator.name] = state.indicators[indicator.name]
|
||||||
detail.indicators[0][indicator.name] = new_inds[indicator.name]
|
|
||||||
|
#ukládáme do ArchRunneru
|
||||||
|
detail.indicators[0][indicator.name] = new_inds[indicator.name]
|
||||||
|
|
||||||
|
#TOTOZNE PRO TICK INDICATOR
|
||||||
|
else:
|
||||||
|
#iterujeme nad bary a on the fly pridavame novou hodnotu do vsech indikatoru a nakonec nad tim spustime indikator
|
||||||
|
#OMEZENI ZATIM pro preview jde velmi omezeně používat bary - OTESTOVAT poradne
|
||||||
|
new_data = dict(close=0,confirmed=0,high=0,hlcc4=0,index=0,low=0,open=0,resolution=0,time=0,trades=0,updated=0,volume=0,vwap=0)
|
||||||
|
bar_idx = 0
|
||||||
|
max_bar_idx = len(detail.bars["time"])
|
||||||
|
for i in range(len(detail.indicators[1]["time"])):
|
||||||
|
for key in detail.indicators[1]:
|
||||||
|
state.cbar_indicators[key].append(detail.indicators[1][key][i])
|
||||||
|
match key:
|
||||||
|
case "time":
|
||||||
|
#pokud existuje bar a indikator s mensim casem vkladame je
|
||||||
|
if bar_idx < max_bar_idx and detail.indicators[1][key][i] >= detail.bars[key][bar_idx]:
|
||||||
|
for bar_key in detail.bars:
|
||||||
|
state.bars[bar_key].append(detail.bars[bar_key][bar_idx])
|
||||||
|
#naplnime i data aktualne
|
||||||
|
new_data[bar_key] = state.bars[bar_key][-1]
|
||||||
|
for ind_key in detail.indicators[0]:
|
||||||
|
state.indicators[ind_key].append(detail.indicators[0][ind_key][bar_idx])
|
||||||
|
bar_idx += 1
|
||||||
|
case "tick_price":
|
||||||
|
new_data['close'] = detail.indicators[1][key][i]
|
||||||
|
# case "tick_volume":
|
||||||
|
# new_data['volume'] = detail.indicators[1][key][i]
|
||||||
|
|
||||||
|
#inicializujeme 0 v novém indikatoru
|
||||||
|
state.cbar_indicators[indicator.name].append(0)
|
||||||
|
|
||||||
|
try:
|
||||||
|
populate_dynamic_indicators(new_data, state)
|
||||||
|
# res_code, new_val = custom_function(state, custom_params)
|
||||||
|
# if res_code == 0:
|
||||||
|
# new_inds[indicator.name][-1]=new_val
|
||||||
|
except Exception as e:
|
||||||
|
print(str(e) + format_exc())
|
||||||
|
|
||||||
|
#print("Done", state.indicators[indicator.name])
|
||||||
|
|
||||||
|
new_tick_inds[indicator.name] = state.cbar_indicators[indicator.name]
|
||||||
|
|
||||||
|
#ukládáme do ArchRunneru
|
||||||
|
detail.indicators[1][indicator.name] = new_tick_inds[indicator.name]
|
||||||
|
|
||||||
|
|
||||||
#do ext dat ukladame jmeno indikatoru (podle toho oznacuje jako zmenene)
|
#do ext dat ukladame jmeno indikatoru (podle toho oznacuje jako zmenene)
|
||||||
|
|
||||||
@ -1565,7 +1631,11 @@ def preview_indicator_byTOML(id: UUID, indicator: InstantIndicator, save: bool =
|
|||||||
if res == 0:
|
if res == 0:
|
||||||
print(f"arch runner {id} updated")
|
print(f"arch runner {id} updated")
|
||||||
|
|
||||||
return 0, new_inds[indicator.name]
|
#vracime list, kde pozice 0 je bar indicators, pozice 1 je ticks indicators
|
||||||
|
if output == "bar":
|
||||||
|
return 0, [new_inds[indicator.name], []]
|
||||||
|
else:
|
||||||
|
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())
|
||||||
|
|||||||
@ -480,10 +480,11 @@ def _delete_archived_runners_byBatchID(batch_id: str):
|
|||||||
raise HTTPException(status_code=status.HTTP_406_NOT_ACCEPTABLE, detail=f"Error not changed: {res}:{batch_id}:{id}")
|
raise HTTPException(status_code=status.HTTP_406_NOT_ACCEPTABLE, detail=f"Error not changed: {res}:{batch_id}:{id}")
|
||||||
|
|
||||||
|
|
||||||
#WIP - TOM indicator preview from frontend
|
#WIP - TOM indicator preview from frontend f
|
||||||
#return indicator value for archived runner
|
#return indicator value for archived runner, return values list0 - bar indicators, list1 - ticks indicators
|
||||||
|
#TBD mozna predelat na dict pro prehlednost
|
||||||
@app.put("/archived_runners/{runner_id}/previewindicator", dependencies=[Depends(api_key_auth)], status_code=status.HTTP_200_OK)
|
@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[float]:
|
def _preview_indicator_byTOML(runner_id: UUID, indicator: InstantIndicator) -> list[list[float]]:
|
||||||
#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
|
||||||
@ -927,10 +928,5 @@ if __name__ == "__main__":
|
|||||||
print("closing insert_conn connection")
|
print("closing insert_conn connection")
|
||||||
insert_conn.close()
|
insert_conn.close()
|
||||||
print("closed")
|
print("closed")
|
||||||
##TODO pridat moznost behu na PAPER a LIVE per strategie
|
|
||||||
|
|
||||||
# zjistit zda order notification websocket muze bezet na obou soucasne
|
|
||||||
# pokud ne, mohl bych vyuzivat jen zive data
|
|
||||||
# a pro paper trading(live interface) a notifications bych pouzival separatni paper ucet
|
|
||||||
# to by asi slo
|
|
||||||
|
|
||||||
|
|||||||
@ -367,6 +367,7 @@ function prepare_data(archRunner, timeframe_amount, timeframe_unit, archivedRunn
|
|||||||
|
|
||||||
//pomocna sluzba pro naplneni indListu a charting indikatoru
|
//pomocna sluzba pro naplneni indListu a charting indikatoru
|
||||||
function chart_indicators(data, visible, offset) {
|
function chart_indicators(data, visible, offset) {
|
||||||
|
console.log(data)
|
||||||
//console.log("indikatory", JSON.stringify(data.indicators,null,2))
|
//console.log("indikatory", JSON.stringify(data.indicators,null,2))
|
||||||
//podobne v livewebsokcets.js - dat do jedne funkce
|
//podobne v livewebsokcets.js - dat do jedne funkce
|
||||||
if (data.hasOwnProperty("indicators")) {
|
if (data.hasOwnProperty("indicators")) {
|
||||||
@ -389,6 +390,8 @@ function chart_indicators(data, visible, offset) {
|
|||||||
indicatorList.forEach((indicators, index, array) => {
|
indicatorList.forEach((indicators, index, array) => {
|
||||||
|
|
||||||
//var indicators = data.indicators
|
//var indicators = data.indicators
|
||||||
|
//index 0 - bar indikatory
|
||||||
|
//index 1 - tick based indikatory
|
||||||
//if there are indicators it means there must be at least two keys (time which is always present)
|
//if there are indicators it means there must be at least two keys (time which is always present)
|
||||||
if (Object.keys(indicators).length > 1) {
|
if (Object.keys(indicators).length > 1) {
|
||||||
for (const [key, value] of Object.entries(indicators)) {
|
for (const [key, value] of Object.entries(indicators)) {
|
||||||
@ -435,7 +438,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, series: null, cnf:cnf, instant: instant}
|
var obj = {name: key, type: index, series: null, cnf:cnf, instant: instant}
|
||||||
|
|
||||||
//start
|
//start
|
||||||
//console.log(key)
|
//console.log(key)
|
||||||
@ -619,19 +622,38 @@ function chart_indicators(data, visible, offset) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//sort by type first (0-bar,1-cbar inds) and then alphabetically
|
||||||
indList.sort((a, b) => {
|
indList.sort((a, b) => {
|
||||||
const nameA = a.name.toUpperCase(); // ignore upper and lowercase
|
if (a.type !== b.type) {
|
||||||
const nameB = b.name.toUpperCase(); // ignore upper and lowercase
|
return a.type - b.type;
|
||||||
if (nameA < nameB) {
|
} else {
|
||||||
return -1;
|
let nameA = a.name.toUpperCase();
|
||||||
|
let nameB = b.name.toUpperCase();
|
||||||
|
if (nameA < nameB) {
|
||||||
|
return -1;
|
||||||
|
} else if (nameA > nameB) {
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
// If uppercase names are equal, compare original names to prioritize uppercase
|
||||||
|
return a.name < b.name ? -1 : 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (nameA > nameB) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
// names must be equal
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
//puvodni funkce
|
||||||
|
// indList.sort((a, b) => {
|
||||||
|
// const nameA = a.name.toUpperCase(); // ignore upper and lowercase
|
||||||
|
// const nameB = b.name.toUpperCase(); // ignore upper and lowercase
|
||||||
|
// if (nameA < nameB) {
|
||||||
|
// return -1;
|
||||||
|
// }
|
||||||
|
// if (nameA > nameB) {
|
||||||
|
// return 1;
|
||||||
|
// }
|
||||||
|
// // names must be equal
|
||||||
|
// return 0;
|
||||||
|
|
||||||
|
// });
|
||||||
//vwap a volume zatim jen v detailnim zobrazeni
|
//vwap a volume zatim jen v detailnim zobrazeni
|
||||||
if (!offset) {
|
if (!offset) {
|
||||||
//display vwap and volume
|
//display vwap and volume
|
||||||
|
|||||||
@ -56,13 +56,16 @@ $(document).ready(function () {
|
|||||||
|
|
||||||
if (archData.indicators[0][indname]) {
|
if (archData.indicators[0][indname]) {
|
||||||
delete archData.indicators[0][indname]
|
delete archData.indicators[0][indname]
|
||||||
//delete addedInds[indname]
|
|
||||||
//get active resolution
|
|
||||||
const element = document.querySelector('.switcher-active-item');
|
|
||||||
resolution = element.textContent
|
|
||||||
//console.log("aktivni rozliseni", resolution)
|
|
||||||
switch_to_interval(resolution, archData)
|
|
||||||
}
|
}
|
||||||
|
else if (archData.indicators[1][indname]) {
|
||||||
|
delete archData.indicators[1][indname]
|
||||||
|
}
|
||||||
|
//delete addedInds[indname]
|
||||||
|
//get active resolution
|
||||||
|
const element = document.querySelector('.switcher-active-item');
|
||||||
|
resolution = element.textContent
|
||||||
|
//console.log("aktivni rozliseni", resolution)
|
||||||
|
switch_to_interval(resolution, archData)
|
||||||
},
|
},
|
||||||
error: function(xhr, status, error) {
|
error: function(xhr, status, error) {
|
||||||
var err = eval("(" + xhr.responseText + ")");
|
var err = eval("(" + xhr.responseText + ")");
|
||||||
@ -142,11 +145,18 @@ $(document).ready(function () {
|
|||||||
success:function(data){
|
success:function(data){
|
||||||
//kod pro update/vytvoreni je zde stejny - updatujeme jen zdrojove dictionary
|
//kod pro update/vytvoreni je zde stejny - updatujeme jen zdrojove dictionary
|
||||||
window.$('#indicatorModal').modal('hide');
|
window.$('#indicatorModal').modal('hide');
|
||||||
//console.log(data)
|
console.log("navrat",data)
|
||||||
//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
|
||||||
archData.indicators[0][indName] = data
|
if (data[0].length > 0) {
|
||||||
|
archData.indicators[0][indName] = data[0]
|
||||||
|
} else if (data[1].length > 0) {
|
||||||
|
archData.indicators[1][indName] = data[1]
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
alert("neco spatne s response ", data)
|
||||||
|
}
|
||||||
|
|
||||||
//pridame pripadne upatneme v ext_data
|
//pridame pripadne upatneme v ext_data
|
||||||
|
|
||||||
|
|||||||
@ -657,24 +657,41 @@ 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
|
||||||
|
var tickButtonElement = document.createElement('div');
|
||||||
|
tickButtonElement.id = "tickIndicatorsButtons"
|
||||||
|
tickButtonElement.classList.add('tickButtons');
|
||||||
|
|
||||||
//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 = index
|
||||||
active = false
|
active = false
|
||||||
|
|
||||||
//console.log("activatedButtons", activatedButtons)
|
//console.log("activatedButtons", activatedButtons)
|
||||||
//console.log("obsahuje item.name", activatedButtons.includes(item.name), item.name)
|
//console.log("obsahuje item.name", activatedButtons.includes(item.name), item.name)
|
||||||
//pokud existuje v aktivnich pak
|
//pokud existuje v aktivnich pak
|
||||||
//console.log("vytvarime button",item.name,activatedButtons)
|
//console.log("vytvarime button",item.name,activatedButtons)
|
||||||
if ((activatedButtons) && (activatedButtons.includes(item.name))) {
|
if ((activatedButtons) && (activatedButtons.includes(item.name))) {
|
||||||
active = true
|
active = true
|
||||||
}
|
}
|
||||||
//vytvoreni buttonku
|
//bar indikatory jsou serazeny na zacarku
|
||||||
itemEl = create_indicator_button(item, index, def||active);
|
if (item.type == 0) {
|
||||||
//prirazeni do divu
|
//vytvoreni buttonku
|
||||||
buttonElement.appendChild(itemEl); ;
|
itemEl = create_indicator_button(item, index, def||active);
|
||||||
});
|
//prirazeni do divu
|
||||||
|
buttonElement.appendChild(itemEl);
|
||||||
|
}
|
||||||
|
//ted zbyvaji tick barové a ty dáme do separátního divu
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//vytvoreni buttonku
|
||||||
|
itemEl = create_indicator_button(item, index, def||active);
|
||||||
|
tickButtonElement.appendChild(itemEl)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
//nakonec pripojime cely div s tick based indicatory
|
||||||
|
buttonElement.appendChild(tickButtonElement);
|
||||||
|
|
||||||
var funcButtonElement = document.createElement('div');
|
var funcButtonElement = document.createElement('div');
|
||||||
funcButtonElement.id = "funcIndicatorsButtons"
|
funcButtonElement.id = "funcIndicatorsButtons"
|
||||||
|
|||||||
@ -30,12 +30,26 @@ def classed(state, params, name):
|
|||||||
init_params = safe_get(params, "init", None) #napr sekce obcahuje threshold = 1222, ktere jdou kwargs do initu fce
|
init_params = safe_get(params, "init", None) #napr sekce obcahuje threshold = 1222, ktere jdou kwargs do initu fce
|
||||||
#next_params = safe_get(params, "next", None)
|
#next_params = safe_get(params, "next", None)
|
||||||
|
|
||||||
source = safe_get(params, "source", None) #source, ktery jde do initu
|
#List of sources, ktere jde do nextu (muze jit i vice serie)
|
||||||
source = get_source_series(state, source)
|
#Do nextu jde ve stejnojmenném parametru
|
||||||
#lookback = int(value_or_indicator(state, lookback))
|
next_sources = safe_get(params, "next", []) #this will map to the sources_dict
|
||||||
|
next_mapping = safe_get(params, "next_mapping", next_sources) #this will dictate the final name of the key in sources_dict
|
||||||
|
|
||||||
|
#ukládáme si do cache incializaci
|
||||||
|
cache = safe_get(params, "CACHE", None)
|
||||||
|
if cache is None:
|
||||||
|
if len(next_sources) != len(next_mapping):
|
||||||
|
return -2, "next and next_mapping length must be the same"
|
||||||
|
# Vytvorime dictionary pro kazdy source a priradime serii
|
||||||
|
#source_dict = {name: get_source_series(state, name) for name in next_sources}
|
||||||
|
#TBD toto optimalizovat aby se nevolalo pri kazde iteraci
|
||||||
|
source_dict = {new_key: get_source_series(state, name)
|
||||||
|
for name, new_key in zip(next_sources, next_mapping)}
|
||||||
|
params["CACHE"] = {}
|
||||||
|
params["CACHE"]["source_dict"] = source_dict
|
||||||
|
else:
|
||||||
|
source_dict = params["CACHE"]["source_dict"]
|
||||||
|
|
||||||
#class_next_params = safe_get(params, "class_next_params", None)
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if name not in state.classed_indicators:
|
if name not in state.classed_indicators:
|
||||||
classname = name
|
classname = name
|
||||||
@ -46,8 +60,8 @@ def classed(state, params, name):
|
|||||||
state.classed_indicators[name] = instance
|
state.classed_indicators[name] = instance
|
||||||
state.ilog(lvl=1,e=f"IND CLASS {name} INITIALIZED", **params)
|
state.ilog(lvl=1,e=f"IND CLASS {name} INITIALIZED", **params)
|
||||||
|
|
||||||
if source is not None:
|
if len(source_dict) >0:
|
||||||
val = state.classed_indicators[name].next(source[-1])
|
val = state.classed_indicators[name].next(**source_dict)
|
||||||
else:
|
else:
|
||||||
val = state.classed_indicators[name].next()
|
val = state.classed_indicators[name].next()
|
||||||
|
|
||||||
@ -56,5 +70,4 @@ def classed(state, params, name):
|
|||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
printanyway(str(e)+format_exc())
|
printanyway(str(e)+format_exc())
|
||||||
return -2, str(e)+format_exc()
|
return -2, str(e)+format_exc()
|
||||||
|
|
||||||
@ -7,7 +7,8 @@ class CUSUM(IndicatorBase):
|
|||||||
self.cumulative_sum = 0
|
self.cumulative_sum = 0
|
||||||
self.previous_price = None
|
self.previous_price = None
|
||||||
|
|
||||||
def next(self, new_price):
|
def next(self, close):
|
||||||
|
new_price = close[-1]
|
||||||
if self.previous_price is None:
|
if self.previous_price is None:
|
||||||
# First data point, no previous price to compare with
|
# First data point, no previous price to compare with
|
||||||
self.previous_price = new_price
|
self.previous_price = new_price
|
||||||
|
|||||||
@ -0,0 +1,37 @@
|
|||||||
|
from collections import deque
|
||||||
|
#import time
|
||||||
|
from v2realbot.strategyblocks.indicators.custom.classes.indicatorbase import IndicatorBase
|
||||||
|
|
||||||
|
class TickTimeBasedROC(IndicatorBase):
|
||||||
|
def __init__(self, state, window_size_seconds=5):
|
||||||
|
"""
|
||||||
|
Initialize the TimeBasedROC class.
|
||||||
|
:param window_size_seconds: Window size in seconds for the rate of change.
|
||||||
|
"""
|
||||||
|
super().__init__(state)
|
||||||
|
self.window_size_seconds = window_size_seconds
|
||||||
|
self.tick_data = deque() # Efficient deque for (timestamp, price)
|
||||||
|
|
||||||
|
def next(self, time, close):
|
||||||
|
"""
|
||||||
|
Update the ROC with a new tick time and price.
|
||||||
|
:param new_time: Timestamp of the new tick (float with up to 6 decimals).
|
||||||
|
:param new_price: Price of the new tick.
|
||||||
|
:return: The updated ROC value, or None if the window is not yet full.
|
||||||
|
"""
|
||||||
|
new_time = time[-1]
|
||||||
|
new_price = close[-1]
|
||||||
|
# Add new tick data
|
||||||
|
self.tick_data.append((new_time, new_price))
|
||||||
|
|
||||||
|
# Remove old data outside the time window efficiently
|
||||||
|
while self.tick_data and new_time - self.tick_data[0][0] > self.window_size_seconds:
|
||||||
|
self.tick_data.popleft()
|
||||||
|
|
||||||
|
if len(self.tick_data) >= 2:
|
||||||
|
# Compute ROC using the earliest and latest prices in the window
|
||||||
|
old_time, old_price = self.tick_data[0]
|
||||||
|
roc = ((new_price - old_price) / old_price) * 100 if old_price != 0 else 0
|
||||||
|
return round(float(roc),5)
|
||||||
|
else:
|
||||||
|
return 0 # ROC is undefined until the window has enough data
|
||||||
@ -0,0 +1,34 @@
|
|||||||
|
import numpy as np
|
||||||
|
from v2realbot.strategyblocks.indicators.custom.classes.indicatorbase import IndicatorBase
|
||||||
|
|
||||||
|
#usecase - pocitat variance ticku
|
||||||
|
# v ramci BARu - posilame sem index a resetujeme pri naslednem indxu
|
||||||
|
# do budoucna mo
|
||||||
|
class TickVariance(IndicatorBase):
|
||||||
|
def __init__(self, state, window_size=1):
|
||||||
|
"""
|
||||||
|
Initialize the TickPriceVariance class.
|
||||||
|
|
||||||
|
:param window_size: The size of the window for calculating variance - zatim mame jeden bar, do budoucna X
|
||||||
|
"""
|
||||||
|
super().__init__(state)
|
||||||
|
self.window_size = window_size
|
||||||
|
self.window_prices = []
|
||||||
|
self.prev_index = None
|
||||||
|
|
||||||
|
def next(self, close, index):
|
||||||
|
close = close[-1]
|
||||||
|
index = index[-1]
|
||||||
|
# Add new price to the window
|
||||||
|
self.window_prices.append(close)
|
||||||
|
|
||||||
|
if self.prev_index is not None and self.prev_index != index:
|
||||||
|
self.window_prices = []
|
||||||
|
|
||||||
|
self.prev_index = index
|
||||||
|
# Calculate the variance for the current window
|
||||||
|
if len(self.window_prices) > 1:
|
||||||
|
return round(float(np.var(self.window_prices)),5)
|
||||||
|
else:
|
||||||
|
return 0 # Variance is undefined for a single data point
|
||||||
|
|
||||||
33
v2realbot/strategyblocks/indicators/custom/rsi.py
Normal file
33
v2realbot/strategyblocks/indicators/custom/rsi.py
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
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
|
||||||
|
from v2realbot.indicators.indicators import ema as ext_ema
|
||||||
|
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 v2realbot.indicators.oscillators import rsi as ind_rsi
|
||||||
|
from collections import defaultdict
|
||||||
|
from v2realbot.strategyblocks.indicators.helpers import value_or_indicator
|
||||||
|
#strength, absolute change of parameter between current value and lookback value (n-past)
|
||||||
|
#used for example to measure unusual peaks
|
||||||
|
def rsi(state, params, name):
|
||||||
|
req_source = safe_get(params, "source", "vwap")
|
||||||
|
rsi_length = safe_get(params, "length",14)
|
||||||
|
start = safe_get(params, "start","linear") #linear/sharp
|
||||||
|
|
||||||
|
#lookback muze byt odkaz na indikator, pak berem jeho hodnotu
|
||||||
|
rsi_length = int(value_or_indicator(state, rsi_length))
|
||||||
|
source = get_source_series(state, req_source)
|
||||||
|
delka = len(source)
|
||||||
|
|
||||||
|
if delka > rsi_length or start == "linear":
|
||||||
|
if delka <= rsi_length and start == "linear":
|
||||||
|
rsi_length = delka
|
||||||
|
|
||||||
|
rsi_res = ind_rsi(source, rsi_length)
|
||||||
|
val = rsi_res[-1] if np.isfinite(rsi_res[-1]) else 0
|
||||||
|
return 0, round(val,4)
|
||||||
|
|
||||||
|
else:
|
||||||
|
state.ilog(lvl=0,e=f"IND {name} RSI necháváme 0", message="not enough source data", source=source, rsi_length=rsi_length)
|
||||||
|
return -2, "necháváma 0 nedostatek hodnot"
|
||||||
@ -13,17 +13,31 @@ def slope(state, params, name):
|
|||||||
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)
|
||||||
|
|
||||||
|
lookback_type = safe_get(params, "lookback_type", "positions")
|
||||||
lookback = safe_get(params, "lookback", 5)
|
lookback = safe_get(params, "lookback", 5)
|
||||||
lookback_priceline = safe_get(params, "lookback_priceline", None)
|
lookback_priceline = safe_get(params, "lookback_priceline", None) #bars|close
|
||||||
lookback_series = get_source_series(state, lookback_priceline)
|
lookback_series = get_source_series(state, lookback_priceline)
|
||||||
|
|
||||||
try:
|
match lookback_type:
|
||||||
lookbackprice = lookback_series[-lookback-1]
|
case "positions":
|
||||||
lookbacktime = state.bars.updated[-lookback-1]
|
try:
|
||||||
except IndexError:
|
lookbackprice = lookback_series[-lookback-1]
|
||||||
max_delka = len(lookback_series)
|
lookbacktime = state.bars.updated[-lookback-1]
|
||||||
lookbackprice =lookback_series[-max_delka]
|
except IndexError:
|
||||||
lookbacktime = state.bars.updated[-max_delka]
|
max_delka = len(lookback_series)
|
||||||
|
lookbackprice =lookback_series[-max_delka]
|
||||||
|
lookbacktime = state.bars.updated[-max_delka]
|
||||||
|
case "seconds":
|
||||||
|
#předpokládáme, že lookback_priceline je ve formě #bars|close
|
||||||
|
#abychom ziskali relevantní time
|
||||||
|
split_index = lookback_priceline.find("|")
|
||||||
|
if split_index == -1:
|
||||||
|
return -2, "for time it is required in format bars|close"
|
||||||
|
dict_name = lookback_priceline[:split_index]
|
||||||
|
time_series = getattr(state, dict_name)["time"]
|
||||||
|
lookback_idx = find_index_optimized(time_list=time_series, seconds=lookback)
|
||||||
|
lookbackprice = lookback_series[lookback_idx]
|
||||||
|
lookbacktime = time_series[lookback_idx]
|
||||||
|
|
||||||
#výpočet úhlu - a jeho normalizace
|
#výpočet úhlu - a jeho normalizace
|
||||||
currval = source_series[-1]
|
currval = source_series[-1]
|
||||||
@ -32,3 +46,24 @@ def slope(state, params, name):
|
|||||||
|
|
||||||
state.ilog(lvl=1,e=f"INSIDE {name}:{funcName} {slope} {source=} {lookback=}", currval_source=currval, lookbackprice=lookbackprice, lookbacktime=lookbacktime, **params)
|
state.ilog(lvl=1,e=f"INSIDE {name}:{funcName} {slope} {source=} {lookback=}", currval_source=currval, lookbackprice=lookbackprice, lookbacktime=lookbacktime, **params)
|
||||||
return 0, slope
|
return 0, slope
|
||||||
|
|
||||||
|
"""
|
||||||
|
TODO pripadne dat do
|
||||||
|
Finds index of first value less than X seconds
|
||||||
|
This version assumes:
|
||||||
|
time_list is always non-empty and sorted.
|
||||||
|
There's always a timestamp at least 5 seconds before the current time.
|
||||||
|
"""
|
||||||
|
def find_index_optimized(time_list, seconds):
|
||||||
|
current_time = time_list[-1]
|
||||||
|
threshold = current_time - seconds
|
||||||
|
left, right = 0, len(time_list) - 1
|
||||||
|
|
||||||
|
while left < right:
|
||||||
|
mid = (left + right) // 2
|
||||||
|
if time_list[mid] < threshold:
|
||||||
|
left = mid + 1
|
||||||
|
else:
|
||||||
|
right = mid
|
||||||
|
|
||||||
|
return left if time_list[left] >= threshold else None
|
||||||
@ -27,6 +27,16 @@ def populate_dynamic_custom_indicator(data, state: StrategyState, name):
|
|||||||
#if MA is required
|
#if MA is required
|
||||||
MA_length = safe_get(options, "MA_length", None)
|
MA_length = safe_get(options, "MA_length", None)
|
||||||
|
|
||||||
|
output = safe_get(options, "output", "bar")
|
||||||
|
match output:
|
||||||
|
case "bar":
|
||||||
|
indicators_dict = state.indicators
|
||||||
|
case "tick":
|
||||||
|
indicators_dict = state.cbar_indicators
|
||||||
|
case _:
|
||||||
|
state.ilog(lvl=1,e=f"Output must be bar or tick for {name} in stratvars")
|
||||||
|
return
|
||||||
|
|
||||||
active = safe_get(options, 'active', True)
|
active = safe_get(options, 'active', True)
|
||||||
if not active:
|
if not active:
|
||||||
return
|
return
|
||||||
@ -121,7 +131,7 @@ def populate_dynamic_custom_indicator(data, state: StrategyState, name):
|
|||||||
if should_run:
|
if should_run:
|
||||||
#TODO get custom params
|
#TODO get custom params
|
||||||
custom_params = safe_get(options, "cp", None)
|
custom_params = safe_get(options, "cp", None)
|
||||||
#vyplnime last_run_time a last_run_index
|
#vyplnime last_run_time a last_run_index do stratvars
|
||||||
state.vars.indicators[name]["last_run_time"] = datetime.fromtimestamp(data["updated"]).astimezone(zoneNY)
|
state.vars.indicators[name]["last_run_time"] = datetime.fromtimestamp(data["updated"]).astimezone(zoneNY)
|
||||||
state.vars.indicators[name]["last_run_index"] = data["index"]
|
state.vars.indicators[name]["last_run_index"] = data["index"]
|
||||||
|
|
||||||
@ -135,14 +145,14 @@ def populate_dynamic_custom_indicator(data, state: StrategyState, name):
|
|||||||
custom_function = eval(subtype)
|
custom_function = eval(subtype)
|
||||||
res_code, new_val = custom_function(state, custom_params, name)
|
res_code, new_val = custom_function(state, custom_params, name)
|
||||||
if res_code == 0:
|
if res_code == 0:
|
||||||
state.indicators[name][-1-save_to_past]=new_val
|
indicators_dict[name][-1-save_to_past]=new_val
|
||||||
state.ilog(lvl=1,e=f"IND {name} {subtype} VAL FROM FUNCTION: {new_val}", lastruntime=state.vars.indicators[name]["last_run_time"], lastrunindex=state.vars.indicators[name]["last_run_index"], save_to_past=save_to_past)
|
state.ilog(lvl=1,e=f"IND {name} {subtype} VAL FROM FUNCTION: {new_val}", lastruntime=state.vars.indicators[name]["last_run_time"], lastrunindex=state.vars.indicators[name]["last_run_index"], save_to_past=save_to_past)
|
||||||
#prepocitame MA if required
|
#prepocitame MA if required
|
||||||
if MA_length is not None:
|
if MA_length is not None:
|
||||||
src = state.indicators[name][-MA_length:]
|
src = indicators_dict[name][-MA_length:]
|
||||||
MA_res = ema(src, MA_length)
|
MA_res = ema(src, MA_length)
|
||||||
MA_value = round(MA_res[-1],7)
|
MA_value = round(MA_res[-1],7)
|
||||||
state.indicators[name+"MA"][-1-save_to_past]=MA_value
|
indicators_dict[name+"MA"][-1-save_to_past]=MA_value
|
||||||
state.ilog(lvl=0,e=f"IND {name}MA {subtype} {MA_value}",save_to_past=save_to_past)
|
state.ilog(lvl=0,e=f"IND {name}MA {subtype} {MA_value}",save_to_past=save_to_past)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
@ -150,20 +160,20 @@ def populate_dynamic_custom_indicator(data, state: StrategyState, name):
|
|||||||
raise Exception(err)
|
raise Exception(err)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
if len(state.indicators[name]) >= 2:
|
if len(indicators_dict[name]) >= 2:
|
||||||
state.indicators[name][-1]=state.indicators[name][-2]
|
indicators_dict[name][-1]=indicators_dict[name][-2]
|
||||||
if MA_length is not None and len(state.indicators[name+"MA"])>=2:
|
if MA_length is not None and len(indicators_dict[name+"MA"])>=2:
|
||||||
state.indicators[name+"MA"][-1]=state.indicators[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())
|
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}")
|
||||||
|
|
||||||
#not time to run - copy last value
|
#not time to run - copy last value
|
||||||
if len(state.indicators[name]) >= 2:
|
if len(indicators_dict[name]) >= 2:
|
||||||
state.indicators[name][-1]=state.indicators[name][-2]
|
indicators_dict[name][-1]=indicators_dict[name][-2]
|
||||||
|
|
||||||
if MA_length is not None and len(state.indicators[name+"MA"])>=2:
|
if MA_length is not None and len(indicators_dict[name+"MA"])>=2:
|
||||||
state.indicators[name+"MA"][-1]=state.indicators[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")
|
state.ilog(lvl=0,e=f"IND {name} {subtype} NOT TIME TO RUN - value(and MA) still original")
|
||||||
|
|||||||
@ -60,6 +60,8 @@ def evaluate_directive_conditions(state, work_dict, cond_type):
|
|||||||
|
|
||||||
return eval_cond_dict(cond)
|
return eval_cond_dict(cond)
|
||||||
|
|
||||||
|
#TODO toto pripadne sloucit s get_source_series - revidovat dopady
|
||||||
|
|
||||||
def get_source_or_MA(state, indicator):
|
def get_source_or_MA(state, indicator):
|
||||||
#pokud ma, pouzije MAcko, pokud ne tak standardni indikator
|
#pokud ma, pouzije MAcko, pokud ne tak standardni indikator
|
||||||
#pokud to jmeno neexistuje, tak pripadne bere z barů (close,open,hlcc4, vwap atp.)
|
#pokud to jmeno neexistuje, tak pripadne bere z barů (close,open,hlcc4, vwap atp.)
|
||||||
@ -69,7 +71,10 @@ def get_source_or_MA(state, indicator):
|
|||||||
try:
|
try:
|
||||||
return state.indicators[indicator]
|
return state.indicators[indicator]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
return state.bars[indicator]
|
try:
|
||||||
|
return state.bars[indicator]
|
||||||
|
except KeyError:
|
||||||
|
return state.cbar_indicators[indicator]
|
||||||
|
|
||||||
def get_source_series(state, source: str):
|
def get_source_series(state, source: str):
|
||||||
"""
|
"""
|
||||||
@ -85,7 +90,10 @@ def get_source_series(state, source: str):
|
|||||||
try:
|
try:
|
||||||
return state.indicators[source]
|
return state.indicators[source]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
return None
|
try:
|
||||||
|
return state.cbar_indicators[source]
|
||||||
|
except KeyError:
|
||||||
|
return None
|
||||||
else:
|
else:
|
||||||
dict_name = source[:split_index]
|
dict_name = source[:split_index]
|
||||||
key = source[split_index + 1:]
|
key = source[split_index + 1:]
|
||||||
|
|||||||
@ -63,12 +63,11 @@ def populate_all_indicators(data, state: StrategyState):
|
|||||||
else:
|
else:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
#toto je spíše interní ukládání tick_price a tick_volume - s tím pak mohou pracovat jak bar based tak tick based indikatory
|
||||||
|
#TODO do budoucna prejmenovat state.cbar_indicators na state.tick_indicators
|
||||||
populate_cbar_tick_price_indicator(data, state)
|
populate_cbar_tick_price_indicator(data, state)
|
||||||
|
|
||||||
#TBD nize predelat na typizovane RSI (a to jak na urovni CBAR tak confirmed)
|
#populate indicators, that have type in stratvars.indicators - pridana podpora i pro CBAR typu CUSTOM
|
||||||
#populate_cbar_rsi_indicator()
|
|
||||||
|
|
||||||
#populate indicators, that have type in stratvars.indicators
|
|
||||||
populate_dynamic_indicators(data, state)
|
populate_dynamic_indicators(data, state)
|
||||||
|
|
||||||
#vytiskneme si indikatory
|
#vytiskneme si indikatory
|
||||||
|
|||||||
@ -23,13 +23,23 @@ def initialize_dynamic_indicators(state):
|
|||||||
##ßprintanyway(state.vars, state)
|
##ßprintanyway(state.vars, state)
|
||||||
dict_copy = state.vars.indicators.copy()
|
dict_copy = state.vars.indicators.copy()
|
||||||
for indname, indsettings in dict_copy.items():
|
for indname, indsettings in dict_copy.items():
|
||||||
|
#inicializace indikatoru na dane urovni
|
||||||
|
output = safe_get(indsettings, 'output', "bar")
|
||||||
|
match output:
|
||||||
|
case "bar":
|
||||||
|
indicators_dict = state.indicators
|
||||||
|
case "tick":
|
||||||
|
indicators_dict = state.cbar_indicators
|
||||||
|
case _:
|
||||||
|
raise(f"ind output must be bar or tick {indname}")
|
||||||
|
|
||||||
|
indicators_dict[indname] = []
|
||||||
|
#pokud ma MA_length incializujeme i MA variantu
|
||||||
|
if safe_get(indsettings, 'MA_length', False):
|
||||||
|
indicators_dict[indname+"MA"] = []
|
||||||
|
|
||||||
|
#Specifické Inicializace dle type
|
||||||
for option,value in list(indsettings.items()):
|
for option,value in list(indsettings.items()):
|
||||||
#inicializujeme nejenom typizovane
|
|
||||||
#if option == "type":
|
|
||||||
state.indicators[indname] = []
|
|
||||||
#pokud ma MA_length incializujeme i MA variantu
|
|
||||||
if safe_get(indsettings, 'MA_length', False):
|
|
||||||
state.indicators[indname+"MA"] = []
|
|
||||||
#specifika pro slope
|
#specifika pro slope
|
||||||
if option == "type":
|
if option == "type":
|
||||||
if value == "slope":
|
if value == "slope":
|
||||||
|
|||||||
@ -302,21 +302,34 @@ def eval_cond_dict(cond: dict) -> tuple[bool, str]:
|
|||||||
def Average(lst):
|
def Average(lst):
|
||||||
return sum(lst) / len(lst)
|
return sum(lst) / len(lst)
|
||||||
|
|
||||||
|
#OPTIMIZED by CHATGPT
|
||||||
def safe_get(collection, key, default=None):
|
def safe_get(collection, key, default=None):
|
||||||
"""Get values from a collection without raising errors"""
|
"""Get values from a collection without raising errors"""
|
||||||
|
# Check if the collection supports the .get method (like dict)
|
||||||
try:
|
if hasattr(collection, 'get'):
|
||||||
return collection.get(key, default)
|
return collection.get(key, default)
|
||||||
except TypeError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
try:
|
# Check if the key is within the bounds for list-like collections
|
||||||
|
if isinstance(collection, (list, tuple)) and 0 <= key < len(collection):
|
||||||
return collection[key]
|
return collection[key]
|
||||||
except (IndexError, TypeError):
|
|
||||||
pass
|
|
||||||
|
|
||||||
return default
|
return default
|
||||||
|
|
||||||
|
# def safe_get(collection, key, default=None):
|
||||||
|
# """Get values from a collection without raising errors"""
|
||||||
|
|
||||||
|
# try:
|
||||||
|
# return collection.get(key, default)
|
||||||
|
# except TypeError:
|
||||||
|
# pass
|
||||||
|
|
||||||
|
# try:
|
||||||
|
# return collection[key]
|
||||||
|
# except (IndexError, TypeError):
|
||||||
|
# pass
|
||||||
|
|
||||||
|
# return default
|
||||||
|
|
||||||
def send_to_telegram(message):
|
def send_to_telegram(message):
|
||||||
apiToken = '5836666362:AAGPuzwp03tczMQTwTBiHW6VsZZ-1RCMAEE'
|
apiToken = '5836666362:AAGPuzwp03tczMQTwTBiHW6VsZZ-1RCMAEE'
|
||||||
chatID = '5029424778'
|
chatID = '5029424778'
|
||||||
|
|||||||
Reference in New Issue
Block a user