migrace z tinydb, nove direktivy
This commit is contained in:
@ -6,7 +6,7 @@ from v2realbot.enums.enums import RecordType, StartBarAlign, Mode, Account, Orde
|
|||||||
from v2realbot.indicators.indicators import ema
|
from v2realbot.indicators.indicators import ema
|
||||||
from v2realbot.indicators.oscillators import rsi
|
from v2realbot.indicators.oscillators import rsi
|
||||||
from v2realbot.common.PrescribedTradeModel import Trade, TradeDirection, TradeStatus, TradeStoplossType
|
from v2realbot.common.PrescribedTradeModel import Trade, TradeDirection, TradeStatus, TradeStoplossType
|
||||||
from v2realbot.utils.utils import ltp, isrising, isfalling,trunc,AttributeDict, zoneNY, price2dec, print, safe_get, round2five, is_open_rush, is_close_rush, is_window_open, eval_cond_dict, Average, crossed_down, crossed_up, crossed, is_pivot, json_serial
|
from v2realbot.utils.utils import ltp, isrising, isfalling,trunc,AttributeDict, zoneNY, price2dec, print, safe_get, round2five, is_open_rush, is_close_rush, is_still, is_window_open, eval_cond_dict, Average, crossed_down, crossed_up, crossed, is_pivot, json_serial
|
||||||
from v2realbot.utils.directive_utils import get_conditions_from_configuration
|
from v2realbot.utils.directive_utils import get_conditions_from_configuration
|
||||||
from v2realbot.common.model import SLHistory
|
from v2realbot.common.model import SLHistory
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
@ -130,6 +130,9 @@ def next(data, state: StrategyState):
|
|||||||
cond[cond_type][directive+"_"+indname+"_"+str(value)] = is_pivot(source=get_source_or_MA(indname), leg_number=value, type="A")
|
cond[cond_type][directive+"_"+indname+"_"+str(value)] = is_pivot(source=get_source_or_MA(indname), leg_number=value, type="A")
|
||||||
elif directive.endswith("pivot_v"):
|
elif directive.endswith("pivot_v"):
|
||||||
cond[cond_type][directive+"_"+indname+"_"+str(value)] = is_pivot(source=get_source_or_MA(indname), leg_number=value, type="V")
|
cond[cond_type][directive+"_"+indname+"_"+str(value)] = is_pivot(source=get_source_or_MA(indname), leg_number=value, type="V")
|
||||||
|
elif directive.endswith("still_for"):
|
||||||
|
#for 2 decimals
|
||||||
|
cond[cond_type][directive+"_"+indname+"_"+str(value)] = is_still(get_source_or_MA(indname),value, 2)
|
||||||
|
|
||||||
#PRIPADNE DALSI SPECIFICKE ZDE
|
#PRIPADNE DALSI SPECIFICKE ZDE
|
||||||
# elif directive == "buy_if_necospecifckeho":
|
# elif directive == "buy_if_necospecifckeho":
|
||||||
@ -389,8 +392,8 @@ def next(data, state: StrategyState):
|
|||||||
|
|
||||||
#pokud mame aktivni pozice, nastavime lookbackprice a time podle posledniho tradu
|
#pokud mame aktivni pozice, nastavime lookbackprice a time podle posledniho tradu
|
||||||
#pokud se ale dlouho nenakupuje (uplynulo od posledniho nakupu vic nez back_to_standard_after baru), tak se vracime k prumeru
|
#pokud se ale dlouho nenakupuje (uplynulo od posledniho nakupu vic nez back_to_standard_after baru), tak se vracime k prumeru
|
||||||
if state.avgp > 0 and state.bars.index[-1] < int(state.vars.lastbuyindex)+back_to_standard_after:
|
if state.avgp > 0 and state.bars.index[-1] < int(state.vars.last_buy_index)+back_to_standard_after:
|
||||||
lb_index = -1 - (state.bars.index[-1] - int(state.vars.lastbuyindex))
|
lb_index = -1 - (state.bars.index[-1] - int(state.vars.last_buy_index))
|
||||||
lookbackprice = state.bars.vwap[lb_index]
|
lookbackprice = state.bars.vwap[lb_index]
|
||||||
state.ilog(e=f"IND {name} slope {leftpoint}- LEFT POINT OVERRIDE bereme ajko cenu lastbuy {lookbackprice=} {lookbacktime=} {lb_index=}")
|
state.ilog(e=f"IND {name} slope {leftpoint}- LEFT POINT OVERRIDE bereme ajko cenu lastbuy {lookbackprice=} {lookbacktime=} {lb_index=}")
|
||||||
else:
|
else:
|
||||||
@ -719,7 +722,7 @@ def next(data, state: StrategyState):
|
|||||||
|
|
||||||
state.ilog(e=f"PROFIT {def_profit=} {normalized_def_profit=}")
|
state.ilog(e=f"PROFIT {def_profit=} {normalized_def_profit=}")
|
||||||
|
|
||||||
return price2dec(data["close"]+normalized_def_profit,3) if int(state.positions) > 0 else price2dec(data["close"]-normalized_def_profit,3)
|
return price2dec(float(state.avgp)+normalized_def_profit,3) if int(state.positions) > 0 else price2dec(float(state.avgp)-normalized_def_profit,3)
|
||||||
|
|
||||||
def get_max_profit_price():
|
def get_max_profit_price():
|
||||||
directive_name = "max_profit"
|
directive_name = "max_profit"
|
||||||
@ -729,7 +732,7 @@ def next(data, state: StrategyState):
|
|||||||
|
|
||||||
state.ilog(e=f"MAX PROFIT {max_profit=} {normalized_max_profit=}")
|
state.ilog(e=f"MAX PROFIT {max_profit=} {normalized_max_profit=}")
|
||||||
|
|
||||||
return price2dec(data["close"]+normalized_max_profit,3) if int(state.positions) > 0 else price2dec(data["close"]-normalized_max_profit,3)
|
return price2dec(float(state.avgp)+normalized_max_profit,3) if int(state.positions) > 0 else price2dec(float(state.avgp)-normalized_max_profit,3)
|
||||||
|
|
||||||
#TBD pripadne opet dat parsovani pole do INITu
|
#TBD pripadne opet dat parsovani pole do INITu
|
||||||
|
|
||||||
@ -739,6 +742,18 @@ def next(data, state: StrategyState):
|
|||||||
else:
|
else:
|
||||||
smer = "short"
|
smer = "short"
|
||||||
|
|
||||||
|
#get name of strategy
|
||||||
|
signal_originator = state.vars.activeTrade.generated_by
|
||||||
|
|
||||||
|
if signal_originator is not None:
|
||||||
|
exit_cond_only_on_confirmed = safe_get(state.vars.signals[signal_originator], "exit_cond_only_on_confirmed", safe_get(state.vars, "exit_cond_only_on_confirmed", False))
|
||||||
|
else:
|
||||||
|
exit_cond_only_on_confirmed = safe_get(state.vars, "exit_cond_only_on_confirmed", False)
|
||||||
|
|
||||||
|
if exit_cond_only_on_confirmed and data['confirmed'] == 0:
|
||||||
|
state.ilog("EXIT COND ONLY ON CONFIRMED BAR")
|
||||||
|
return False
|
||||||
|
|
||||||
#TOTO ZATIM NEMA VYZNAM
|
#TOTO ZATIM NEMA VYZNAM
|
||||||
# options = safe_get(state.vars, 'exit_conditions', None)
|
# options = safe_get(state.vars, 'exit_conditions', None)
|
||||||
# if options is None:
|
# if options is None:
|
||||||
@ -912,8 +927,6 @@ def next(data, state: StrategyState):
|
|||||||
|
|
||||||
if int(state.positions) != 0 and float(state.avgp)>0 and state.vars.pending is None:
|
if int(state.positions) != 0 and float(state.avgp)>0 and state.vars.pending is None:
|
||||||
|
|
||||||
#podivam se zda dana
|
|
||||||
|
|
||||||
#pevny target - presunout toto do INIT a pak jen pristupovat
|
#pevny target - presunout toto do INIT a pak jen pristupovat
|
||||||
goal_price = get_profit_target_price()
|
goal_price = get_profit_target_price()
|
||||||
max_price = get_max_profit_price()
|
max_price = get_max_profit_price()
|
||||||
@ -984,6 +997,7 @@ def next(data, state: StrategyState):
|
|||||||
trade.last_update = datetime.fromtimestamp(state.time).astimezone(zoneNY)
|
trade.last_update = datetime.fromtimestamp(state.time).astimezone(zoneNY)
|
||||||
state.ilog(e=f"evaluated LONG", trade=json.loads(json.dumps(trade, default=json_serial)), prescrTrades=json.loads(json.dumps(state.vars.prescribedTrades, default=json_serial)))
|
state.ilog(e=f"evaluated LONG", trade=json.loads(json.dumps(trade, default=json_serial)), prescrTrades=json.loads(json.dumps(state.vars.prescribedTrades, default=json_serial)))
|
||||||
state.vars.activeTrade = trade
|
state.vars.activeTrade = trade
|
||||||
|
state.vars.last_buy_index = data["index"]
|
||||||
break
|
break
|
||||||
#evaluate shorts
|
#evaluate shorts
|
||||||
if not state.vars.activeTrade:
|
if not state.vars.activeTrade:
|
||||||
@ -993,6 +1007,7 @@ def next(data, state: StrategyState):
|
|||||||
trade.status = TradeStatus.ACTIVATED
|
trade.status = TradeStatus.ACTIVATED
|
||||||
trade.last_update = datetime.fromtimestamp(state.time).astimezone(zoneNY)
|
trade.last_update = datetime.fromtimestamp(state.time).astimezone(zoneNY)
|
||||||
state.vars.activeTrade = trade
|
state.vars.activeTrade = trade
|
||||||
|
state.vars.last_buy_index = data["index"]
|
||||||
break
|
break
|
||||||
|
|
||||||
#odeslani ORDER + NASTAVENI STOPLOSS (zatim hardcoded)
|
#odeslani ORDER + NASTAVENI STOPLOSS (zatim hardcoded)
|
||||||
@ -1109,6 +1124,15 @@ def next(data, state: StrategyState):
|
|||||||
def common_go_preconditions_check(signalname: str, options: dict):
|
def common_go_preconditions_check(signalname: str, options: dict):
|
||||||
#ZAKLADNI KONTROLY ATRIBUTU s fallbackem na obecné
|
#ZAKLADNI KONTROLY ATRIBUTU s fallbackem na obecné
|
||||||
#check working windows (open - close, in minutes from the start of marker)
|
#check working windows (open - close, in minutes from the start of marker)
|
||||||
|
|
||||||
|
next_signal_offset = safe_get(options, "next_signal_offset_from_last",safe_get(state.vars, "next_signal_offset_from_last",0))
|
||||||
|
|
||||||
|
if state.vars.last_buy_index is not None:
|
||||||
|
index_to_compare = int(state.vars.last_buy_index)+int(next_signal_offset)
|
||||||
|
if index_to_compare > int(data["index"]):
|
||||||
|
state.ilog(e=f"NEXT SIGNAL OFFSET {next_signal_offset} waiting - TOO SOON", currindex=data["index"], index_to_compare=index_to_compare)
|
||||||
|
return False
|
||||||
|
|
||||||
window_open = safe_get(options, "window_open",safe_get(state.vars, "window_open",0))
|
window_open = safe_get(options, "window_open",safe_get(state.vars, "window_open",0))
|
||||||
window_close = safe_get(options, "window_close",safe_get(state.vars, "window_close",390))
|
window_close = safe_get(options, "window_close",safe_get(state.vars, "window_close",390))
|
||||||
|
|
||||||
@ -1390,7 +1414,7 @@ def init(state: StrategyState):
|
|||||||
state.vars.last_50_deltas = []
|
state.vars.last_50_deltas = []
|
||||||
state.vars.last_tick_volume = 0
|
state.vars.last_tick_volume = 0
|
||||||
state.vars.next_new = 0
|
state.vars.next_new = 0
|
||||||
state.vars.lastbuyindex = 0
|
state.vars.last_buy_index = None
|
||||||
state.vars.last_update_time = 0
|
state.vars.last_update_time = 0
|
||||||
state.vars.reverse_position_waiting_amount = 0
|
state.vars.reverse_position_waiting_amount = 0
|
||||||
#INIT promenne, ktere byly zbytecne ve stratvars
|
#INIT promenne, ktere byly zbytecne ve stratvars
|
||||||
|
|||||||
@ -279,7 +279,7 @@ def save_history(id: UUID, st: object, runner: Runner, reason: str = None):
|
|||||||
db.save()
|
db.save()
|
||||||
|
|
||||||
#Capsule to run the thread in. Needed in order to update db after strat ends for any reason#
|
#Capsule to run the thread in. Needed in order to update db after strat ends for any reason#
|
||||||
def capsule(target: object, db: object):
|
def capsule(target: object, db: object, inter_batch_params: dict = None):
|
||||||
|
|
||||||
#TODO zde odchytit pripadnou exceptionu a zapsat do history
|
#TODO zde odchytit pripadnou exceptionu a zapsat do history
|
||||||
#cil aby padnuti jedne nezpusobilo pad enginu
|
#cil aby padnuti jedne nezpusobilo pad enginu
|
||||||
@ -305,7 +305,7 @@ def capsule(target: object, db: object):
|
|||||||
#ukladame radek do historie (pozdeji refactor)
|
#ukladame radek do historie (pozdeji refactor)
|
||||||
save_history(id=i.strat_id, st=target, runner=i, reason=reason)
|
save_history(id=i.strat_id, st=target, runner=i, reason=reason)
|
||||||
#store in archive header and archive detail
|
#store in archive header and archive detail
|
||||||
archive_runner(runner=i, strat=target)
|
archive_runner(runner=i, strat=target, inter_batch_params=inter_batch_params)
|
||||||
#mazeme runner po skonceni instance
|
#mazeme runner po skonceni instance
|
||||||
db.runners.remove(i)
|
db.runners.remove(i)
|
||||||
|
|
||||||
@ -373,6 +373,9 @@ def batch_run_manager(id: UUID, runReq: RunRequest, testlist: TestList):
|
|||||||
interval: Intervals
|
interval: Intervals
|
||||||
cnt_max = len(testlist.dates)
|
cnt_max = len(testlist.dates)
|
||||||
cnt = 0
|
cnt = 0
|
||||||
|
#promenna pro sdileni mezi runy jednotlivych batchů (např. daily profit)
|
||||||
|
inter_batch_params = dict(batch_profit=0)
|
||||||
|
note_from_run_request = runReq.note
|
||||||
for intrvl in testlist.dates:
|
for intrvl in testlist.dates:
|
||||||
cnt += 1
|
cnt += 1
|
||||||
interval = intrvl
|
interval = intrvl
|
||||||
@ -385,10 +388,10 @@ def batch_run_manager(id: UUID, runReq: RunRequest, testlist: TestList):
|
|||||||
#předání atributů datetime.fromisoformat
|
#předání atributů datetime.fromisoformat
|
||||||
runReq.bt_from = datetime.fromisoformat(interval.start)
|
runReq.bt_from = datetime.fromisoformat(interval.start)
|
||||||
runReq.bt_to = datetime.fromisoformat(interval.end)
|
runReq.bt_to = datetime.fromisoformat(interval.end)
|
||||||
runReq.note = f"Batch {batch_id} run #{cnt}/{cnt_max} Note:{interval.note}"
|
runReq.note = f"Batch {batch_id} #{cnt}/{cnt_max} {testlist.name} N:{interval.note} {note_from_run_request}"
|
||||||
|
|
||||||
#protoze jsme v ridicim vlaknu, poustime za sebou jednotlive stratiny v synchronnim modu
|
#protoze jsme v ridicim vlaknu, poustime za sebou jednotlive stratiny v synchronnim modu
|
||||||
res, id_val = run_stratin(id=id, runReq=runReq, synchronous=True)
|
res, id_val = run_stratin(id=id, runReq=runReq, synchronous=True, inter_batch_params=inter_batch_params)
|
||||||
if res < 0:
|
if res < 0:
|
||||||
print(f"CHyba v runu #{cnt} od:{runReq.bt_from} do {runReq.bt_to} -> {id_val}")
|
print(f"CHyba v runu #{cnt} od:{runReq.bt_from} do {runReq.bt_to} -> {id_val}")
|
||||||
break
|
break
|
||||||
@ -397,7 +400,7 @@ def batch_run_manager(id: UUID, runReq: RunRequest, testlist: TestList):
|
|||||||
|
|
||||||
|
|
||||||
#stratin run
|
#stratin run
|
||||||
def run_stratin(id: UUID, runReq: RunRequest, synchronous: bool = False):
|
def run_stratin(id: UUID, runReq: RunRequest, synchronous: bool = False, inter_batch_params: dict = None):
|
||||||
if runReq.mode == Mode.BT:
|
if runReq.mode == Mode.BT:
|
||||||
if runReq.bt_from is None:
|
if runReq.bt_from is None:
|
||||||
return (-1, "start date required for BT")
|
return (-1, "start date required for BT")
|
||||||
@ -469,7 +472,7 @@ def run_stratin(id: UUID, runReq: RunRequest, synchronous: bool = False):
|
|||||||
print("Starting strategy", instance.name)
|
print("Starting strategy", instance.name)
|
||||||
#vlakno = Thread(target=instance.start, name=instance.name)
|
#vlakno = Thread(target=instance.start, name=instance.name)
|
||||||
#pokus na spusteni v kapsli, abychom po skonceni mohli updatnout stratin
|
#pokus na spusteni v kapsli, abychom po skonceni mohli updatnout stratin
|
||||||
vlakno = Thread(target=capsule, args=(instance,db), name=instance.name)
|
vlakno = Thread(target=capsule, args=(instance,db, inter_batch_params), name=instance.name)
|
||||||
vlakno.start()
|
vlakno.start()
|
||||||
print("Spuštěna", instance.name)
|
print("Spuštěna", instance.name)
|
||||||
##storing the attributtes - pozor pri stopu je zase odstranit
|
##storing the attributtes - pozor pri stopu je zase odstranit
|
||||||
@ -498,7 +501,10 @@ def run_stratin(id: UUID, runReq: RunRequest, synchronous: bool = False):
|
|||||||
print(f"waiting for thread {vlakno} to finish")
|
print(f"waiting for thread {vlakno} to finish")
|
||||||
vlakno.join()
|
vlakno.join()
|
||||||
|
|
||||||
return (0, id)
|
if inter_batch_params is not None:
|
||||||
|
return (0, inter_batch_params)
|
||||||
|
else:
|
||||||
|
return (0, id)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
return (-2, "Exception: "+str(e)+format_exc())
|
return (-2, "Exception: "+str(e)+format_exc())
|
||||||
return (-2, "not found")
|
return (-2, "not found")
|
||||||
@ -517,7 +523,7 @@ def get_trade_history(symbol: str, timestamp_from: float, timestamp_to:float):
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
return (-2, f"problem {e}")
|
return (-2, f"problem {e}")
|
||||||
|
|
||||||
def populate_metrics_output_directory(strat: StrategyInstance):
|
def populate_metrics_output_directory(strat: StrategyInstance, inter_batch_params: dict = None):
|
||||||
"""
|
"""
|
||||||
WIP
|
WIP
|
||||||
Spocte zakladni metriky pred ulozenim do archivu
|
Spocte zakladni metriky pred ulozenim do archivu
|
||||||
@ -560,6 +566,10 @@ def populate_metrics_output_directory(strat: StrategyInstance):
|
|||||||
#filt = max_positions['side'] == 'OrderSide.BUY'
|
#filt = max_positions['side'] == 'OrderSide.BUY'
|
||||||
res = dict(zip(max_positions['qty'], max_positions['count']))
|
res = dict(zip(max_positions['qty'], max_positions['count']))
|
||||||
|
|
||||||
|
#naplneni batch sum profitu
|
||||||
|
if inter_batch_params is not None:
|
||||||
|
res["batch_sum_profit"] = inter_batch_params["batch_profit"]
|
||||||
|
|
||||||
#metrikz z prescribedTrades, pokud existuji
|
#metrikz z prescribedTrades, pokud existuji
|
||||||
try:
|
try:
|
||||||
long_profit = 0
|
long_profit = 0
|
||||||
@ -605,7 +615,7 @@ def populate_metrics_output_directory(strat: StrategyInstance):
|
|||||||
return res
|
return res
|
||||||
|
|
||||||
#archives runner and details
|
#archives runner and details
|
||||||
def archive_runner(runner: Runner, strat: StrategyInstance):
|
def archive_runner(runner: Runner, strat: StrategyInstance, inter_batch_params: dict = None):
|
||||||
results_metrics = dict()
|
results_metrics = dict()
|
||||||
print("inside archive_runner")
|
print("inside archive_runner")
|
||||||
try:
|
try:
|
||||||
@ -625,12 +635,17 @@ def archive_runner(runner: Runner, strat: StrategyInstance):
|
|||||||
BT_FILL_CONDITION_BUY_LIMIT=BT_FILL_CONDITION_BUY_LIMIT,
|
BT_FILL_CONDITION_BUY_LIMIT=BT_FILL_CONDITION_BUY_LIMIT,
|
||||||
BT_FILL_CONDITION_SELL_LIMIT=BT_FILL_CONDITION_SELL_LIMIT))
|
BT_FILL_CONDITION_SELL_LIMIT=BT_FILL_CONDITION_SELL_LIMIT))
|
||||||
|
|
||||||
|
|
||||||
|
#add profit of this batch iteration to batch_sum_profit
|
||||||
|
if inter_batch_params is not None:
|
||||||
|
inter_batch_params["batch_profit"] += round(float(strat.state.profit),2)
|
||||||
|
|
||||||
#WIP
|
#WIP
|
||||||
#populate result metrics dictionary (max drawdown etc.)
|
#populate result metrics dictionary (max drawdown etc.)
|
||||||
#list of maximum positions (2000 2x, 1800 x 1, 900 x 1, 100 x 20)
|
#list of maximum positions (2000 2x, 1800 x 1, 900 x 1, 100 x 20)
|
||||||
#list of most profitable trades (pos,avgp + cena)
|
#list of most profitable trades (pos,avgp + cena)
|
||||||
#file pro vyvoj: ouptut_metriky_tradeList.py
|
#file pro vyvoj: ouptut_metriky_tradeList.py
|
||||||
results_metrics = populate_metrics_output_directory(strat)
|
results_metrics = populate_metrics_output_directory(strat, inter_batch_params)
|
||||||
|
|
||||||
runArchive: RunArchive = RunArchive(id = runner.id,
|
runArchive: RunArchive = RunArchive(id = runner.id,
|
||||||
strat_id = runner.strat_id,
|
strat_id = runner.strat_id,
|
||||||
@ -697,7 +712,8 @@ def archive_runner(runner: Runner, strat: StrategyInstance):
|
|||||||
trades=strat.state.tradeList,
|
trades=strat.state.tradeList,
|
||||||
ext_data=strat.state.extData)
|
ext_data=strat.state.extData)
|
||||||
with lock:
|
with lock:
|
||||||
resh = db_arch_h.insert(runArchive.__dict__)
|
#resh = db_arch_h.insert(runArchive.__dict__)
|
||||||
|
resh = insert_archive_header(runArchive)
|
||||||
resd = insert_archive_detail(runArchiveDetail)
|
resd = insert_archive_detail(runArchiveDetail)
|
||||||
#resd = db_arch_d.insert(runArchiveDetail.__dict__)
|
#resd = db_arch_d.insert(runArchiveDetail.__dict__)
|
||||||
print("archive runner finished")
|
print("archive runner finished")
|
||||||
@ -706,37 +722,116 @@ def archive_runner(runner: Runner, strat: StrategyInstance):
|
|||||||
print("Exception in archive_runner: " + str(e) + format_exc())
|
print("Exception in archive_runner: " + str(e) + format_exc())
|
||||||
return -2, str(e) + format_exc()
|
return -2, str(e) + format_exc()
|
||||||
|
|
||||||
|
# region ARCH HEADER
|
||||||
|
def migrate_archived_runners() -> list[RunArchive]:
|
||||||
|
try:
|
||||||
|
res = db_arch_h.all()
|
||||||
|
|
||||||
|
#migration part
|
||||||
|
for item in res:
|
||||||
|
r = insert_archive_header(RunArchive(**item))
|
||||||
|
print("migrated",r)
|
||||||
|
|
||||||
|
return 0, r
|
||||||
|
except Exception as e:
|
||||||
|
print("Exception in migration: " + str(e) + format_exc())
|
||||||
|
return -2, str(e) + format_exc()
|
||||||
|
|
||||||
def get_all_archived_runners():
|
def get_all_archived_runners():
|
||||||
res = db_arch_h.all()
|
conn = pool.get_connection()
|
||||||
return 0, res
|
try:
|
||||||
|
conn.row_factory = lambda c, r: json.loads(r[0])
|
||||||
|
c = conn.cursor()
|
||||||
|
res = c.execute(f"SELECT data FROM runner_header")
|
||||||
|
finally:
|
||||||
|
conn.row_factory = None
|
||||||
|
pool.release_connection(conn)
|
||||||
|
return 0, res.fetchall()
|
||||||
|
|
||||||
|
#vrátí konkrétní
|
||||||
|
def get_archived_runner_header_byID(id: UUID):
|
||||||
|
conn = pool.get_connection()
|
||||||
|
try:
|
||||||
|
conn.row_factory = lambda c, r: json.loads(r[0])
|
||||||
|
c = conn.cursor()
|
||||||
|
result = c.execute(f"SELECT data FROM runner_header WHERE runner_id='{str(id)}'")
|
||||||
|
res= result.fetchone()
|
||||||
|
finally:
|
||||||
|
conn.row_factory = None
|
||||||
|
pool.release_connection(conn)
|
||||||
|
if res==None:
|
||||||
|
return -2, "not found"
|
||||||
|
else:
|
||||||
|
return 0, res
|
||||||
|
|
||||||
|
def insert_archive_header(archeader: RunArchive):
|
||||||
|
conn = pool.get_connection()
|
||||||
|
try:
|
||||||
|
c = conn.cursor()
|
||||||
|
json_string = json.dumps(archeader, default=json_serial)
|
||||||
|
statement = f"INSERT INTO runner_header VALUES ('{str(archeader.id)}','{json_string}')"
|
||||||
|
res = c.execute(statement)
|
||||||
|
conn.commit()
|
||||||
|
finally:
|
||||||
|
pool.release_connection(conn)
|
||||||
|
return res.rowcount
|
||||||
|
|
||||||
|
#edit archived runner note - headers
|
||||||
|
def edit_archived_runners(runner_id: UUID, archChange: RunArchiveChange):
|
||||||
|
try:
|
||||||
|
res, sada = get_archived_runner_header_byID(id=runner_id)
|
||||||
|
if res == 0:
|
||||||
|
archOriginal = RunArchive(**sada)
|
||||||
|
archOriginal.note = archChange.note
|
||||||
|
try:
|
||||||
|
conn = pool.get_connection()
|
||||||
|
c = conn.cursor()
|
||||||
|
json_string = json.dumps(archOriginal, default=json_serial)
|
||||||
|
statement = f"UPDATE runner_header SET data = '{json_string}' WHERE runner_id='{str(runner_id)}'"
|
||||||
|
res = c.execute(statement)
|
||||||
|
#print(res)
|
||||||
|
conn.commit()
|
||||||
|
finally:
|
||||||
|
pool.release_connection(conn)
|
||||||
|
return 0, runner_id
|
||||||
|
else:
|
||||||
|
return -1, f"Could not find arch runner {runner_id} {res} {sada}"
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
return -2, str(e)
|
||||||
|
|
||||||
#delete runner in archive and archive detail and runner logs
|
#delete runner in archive and archive detail and runner logs
|
||||||
def delete_archived_runners_byID(id: UUID):
|
def delete_archived_runners_byID(id: UUID):
|
||||||
try:
|
try:
|
||||||
with lock:
|
with lock:
|
||||||
print("before header del")
|
print("header del")
|
||||||
resh = db_arch_h.remove(where('id') == id)
|
resh = delete_archive_header_byID(id)
|
||||||
print("before detail del")
|
#resh = db_arch_h.remove(where('id') == id)
|
||||||
|
print("detail del")
|
||||||
#resd = db_arch_d.remove(where('id') == id)
|
#resd = db_arch_d.remove(where('id') == id)
|
||||||
resd = delete_archive_detail_byID(id)
|
resd = delete_archive_detail_byID(id)
|
||||||
print("Arch header and detail removed. Log deletition will start.")
|
print("Arch header and detail removed. Log deletition will start.")
|
||||||
reslogs = delete_logs(id)
|
reslogs = delete_logs(id)
|
||||||
if len(resh) == 0 or resd == 0:
|
if resh == 0 or resd == 0:
|
||||||
return -1, "not found "+str(resh) + " " + str(resd) + " " + str(reslogs)
|
return -1, "not found "+str(resh) + " " + str(resd) + " " + str(reslogs)
|
||||||
return 0, str(resh) + " " + str(resd) + " " + str(reslogs)
|
return 0, str(resh) + " " + str(resd) + " " + str(reslogs)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
return -2, str(e)
|
return -2, str(e)
|
||||||
|
|
||||||
#edit archived runner note
|
#returns number of deleted elements
|
||||||
def edit_archived_runners(runner_id: UUID, archChange: RunArchiveChange):
|
def delete_archive_header_byID(id: UUID):
|
||||||
|
conn = pool.get_connection()
|
||||||
try:
|
try:
|
||||||
with lock:
|
c = conn.cursor()
|
||||||
res = db_arch_h.update(set('note', archChange.note), where('id') == str(runner_id))
|
res = c.execute(f"DELETE from runner_header WHERE runner_id='{str(id)}';")
|
||||||
if len(res) == 0:
|
conn.commit()
|
||||||
return -1, "not found "+str(runner_id)
|
print("deleted", res.rowcount)
|
||||||
return 0, runner_id
|
finally:
|
||||||
except Exception as e:
|
pool.release_connection(conn)
|
||||||
return -2, str(e)
|
return res.rowcount
|
||||||
|
# endregion
|
||||||
|
|
||||||
|
# region ARCHIVE DETAIL
|
||||||
|
|
||||||
#returns number of deleted elements
|
#returns number of deleted elements
|
||||||
def delete_archive_detail_byID(id: UUID):
|
def delete_archive_detail_byID(id: UUID):
|
||||||
@ -750,9 +845,6 @@ def delete_archive_detail_byID(id: UUID):
|
|||||||
pool.release_connection(conn)
|
pool.release_connection(conn)
|
||||||
return res.rowcount
|
return res.rowcount
|
||||||
|
|
||||||
# def get_all_archived_runners_detail_old():
|
|
||||||
# res = db_arch_d.all()
|
|
||||||
# return 0, res
|
|
||||||
|
|
||||||
def get_all_archived_runners_detail():
|
def get_all_archived_runners_detail():
|
||||||
conn = pool.get_connection()
|
conn = pool.get_connection()
|
||||||
@ -798,6 +890,7 @@ def insert_archive_detail(archdetail: RunArchiveDetail):
|
|||||||
finally:
|
finally:
|
||||||
pool.release_connection(conn)
|
pool.release_connection(conn)
|
||||||
return res.rowcount
|
return res.rowcount
|
||||||
|
# endregion
|
||||||
|
|
||||||
# region TESTLISTS db services
|
# region TESTLISTS db services
|
||||||
def get_testlists():
|
def get_testlists():
|
||||||
@ -820,7 +913,8 @@ def get_testlists():
|
|||||||
# endregion
|
# endregion
|
||||||
|
|
||||||
# region CONFIG db services
|
# region CONFIG db services
|
||||||
|
#TODO vytvorit modul pro dotahovani z pythonu (get_from_config(var_name, def_value) {)- stejne jako v js
|
||||||
|
#TODO zvazit presunuti do TOML z JSONu
|
||||||
def get_all_config_items():
|
def get_all_config_items():
|
||||||
conn = pool.get_connection()
|
conn = pool.get_connection()
|
||||||
try:
|
try:
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import os,sys
|
import os,sys
|
||||||
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||||
from v2realbot.enums.enums import Mode, Account
|
from v2realbot.enums.enums import Mode, Account
|
||||||
from v2realbot.config import WEB_API_KEY
|
from v2realbot.config import WEB_API_KEY, DATA_DIR
|
||||||
from alpaca.data.timeframe import TimeFrame, TimeFrameUnit
|
from alpaca.data.timeframe import TimeFrame, TimeFrameUnit
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
#from icecream import install, ic
|
#from icecream import install, ic
|
||||||
@ -271,7 +271,41 @@ def get_trade_history(symbol: str, timestamp_from: float, timestamp_to:float) ->
|
|||||||
else:
|
else:
|
||||||
raise HTTPException(status_code=404, detail=f"No trades found {res}")
|
raise HTTPException(status_code=404, detail=f"No trades found {res}")
|
||||||
|
|
||||||
|
@app.put("/migrate", dependencies=[Depends(api_key_auth)], status_code=status.HTTP_200_OK)
|
||||||
|
def migrate():
|
||||||
|
lock_file = DATA_DIR + "/migr.lock"
|
||||||
|
|
||||||
|
#if lock file not present, we can continue and create the file
|
||||||
|
if not os.path.exists(lock_file):
|
||||||
|
|
||||||
|
#migration code
|
||||||
|
print("migration code done")
|
||||||
|
conn = pool.get_connection()
|
||||||
|
try:
|
||||||
|
conn.row_factory = lambda c, r: json.loads(r[0])
|
||||||
|
c = conn.cursor()
|
||||||
|
res = c.execute(f'CREATE TABLE "runner_header" ("runner_id" varchar(32) NOT NULL,"data" json NOT NULL, PRIMARY KEY("runner_id"))')
|
||||||
|
print(res)
|
||||||
|
print("table created")
|
||||||
|
conn.commit()
|
||||||
|
finally:
|
||||||
|
conn.row_factory = None
|
||||||
|
pool.release_connection(conn)
|
||||||
|
|
||||||
|
res, set =cs.migrate_archived_runners()
|
||||||
|
if res == 0:
|
||||||
|
open(lock_file, 'w').close()
|
||||||
|
return set
|
||||||
|
else:
|
||||||
|
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=f"No data found")
|
||||||
|
|
||||||
|
|
||||||
|
else:
|
||||||
|
raise HTTPException(status_code=status.HTTP_406_NOT_ACCEPTABLE, detail=f"Migration lock file present {lock_file}")
|
||||||
|
|
||||||
|
|
||||||
#ARCHIVE RUNNERS SECTION
|
#ARCHIVE RUNNERS SECTION
|
||||||
|
# region Archive runners
|
||||||
|
|
||||||
#get all archived runners header
|
#get all archived runners header
|
||||||
@app.get("/archived_runners/", dependencies=[Depends(api_key_auth)])
|
@app.get("/archived_runners/", dependencies=[Depends(api_key_auth)])
|
||||||
@ -327,6 +361,8 @@ def _get_archived_runner_log_byID(runner_id: UUID, timestamp_from: float, timest
|
|||||||
else:
|
else:
|
||||||
raise HTTPException(status_code=404, detail=f"No logs found with id: {runner_id} and between {timestamp_from} and {timestamp_to}")
|
raise HTTPException(status_code=404, detail=f"No logs found with id: {runner_id} and between {timestamp_from} and {timestamp_to}")
|
||||||
|
|
||||||
|
# endregion
|
||||||
|
|
||||||
#get alpaca history bars
|
#get alpaca history bars
|
||||||
@app.get("/history_bars/", dependencies=[Depends(api_key_auth)])
|
@app.get("/history_bars/", dependencies=[Depends(api_key_auth)])
|
||||||
def _get_alpaca_history_bars(symbol: str, datetime_object_from: datetime, datetime_object_to: datetime, timeframe_amount: int, timeframe_unit: TimeFrameUnit) -> list[Bar]:
|
def _get_alpaca_history_bars(symbol: str, datetime_object_from: datetime, datetime_object_to: datetime, timeframe_amount: int, timeframe_unit: TimeFrameUnit) -> list[Bar]:
|
||||||
|
|||||||
@ -25,6 +25,12 @@
|
|||||||
|
|
||||||
<script src="https://cdn.datatables.net/select/1.6.2/js/dataTables.select.min.js"></script>
|
<script src="https://cdn.datatables.net/select/1.6.2/js/dataTables.select.min.js"></script>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!-- <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.8.0/styles/gradient-dark.min.css">
|
||||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.8.0/highlight.min.js"></script>
|
||||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.8.0/languages/json.min.js"></script> -->
|
||||||
|
|
||||||
<!-- <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css">
|
<!-- <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css">
|
||||||
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
|
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
|
||||||
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>
|
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>
|
||||||
|
|||||||
@ -1,4 +1,6 @@
|
|||||||
//JS code for using config value on the frontend
|
//JS code for using config value on the frontend
|
||||||
|
//TODO zvazit presunuti do TOML z JSONu
|
||||||
|
|
||||||
configData = {}
|
configData = {}
|
||||||
|
|
||||||
function get_from_config(name, def_value) {
|
function get_from_config(name, def_value) {
|
||||||
|
|||||||
@ -5,7 +5,6 @@ $(document).ready(function () {
|
|||||||
let editingItemId = null;
|
let editingItemId = null;
|
||||||
var localArray = []
|
var localArray = []
|
||||||
|
|
||||||
|
|
||||||
// Function to populate the config list and load JSON data initially
|
// Function to populate the config list and load JSON data initially
|
||||||
function populateConfigList(to_select = null) {
|
function populateConfigList(to_select = null) {
|
||||||
$.ajax({
|
$.ajax({
|
||||||
@ -28,6 +27,20 @@ $(document).ready(function () {
|
|||||||
$('#itemName').val(item.item_name);
|
$('#itemName').val(item.item_name);
|
||||||
$('#jsonTextarea').val(item.json_data);
|
$('#jsonTextarea').val(item.json_data);
|
||||||
editingItemId = item.id;
|
editingItemId = item.id;
|
||||||
|
// Get the textarea element.
|
||||||
|
var textarea = $("#jsonTextarea");
|
||||||
|
|
||||||
|
// // Highlight the JSON formatted string in the textarea.
|
||||||
|
// hljs.highlightElement(textarea.get(0));
|
||||||
|
// console.log(textarea.get(0))
|
||||||
|
// console.log(textarea.get(1))
|
||||||
|
|
||||||
|
// // Highlight the JSON formatted string whenever the textarea is edited.
|
||||||
|
// textarea.on("input", function() {
|
||||||
|
// hljs.highlightElement(textarea.get(0));
|
||||||
|
// //hljs.highlightBlock(textarea.get(0),{ language: 'json' });
|
||||||
|
// });
|
||||||
|
|
||||||
}
|
}
|
||||||
configList.append(`<option value="${item.id}" ${selected}>${item.item_name}</option>`);
|
configList.append(`<option value="${item.id}" ${selected}>${item.item_name}</option>`);
|
||||||
});
|
});
|
||||||
|
|||||||
@ -17,11 +17,11 @@ if (statusBarConfig == null) {
|
|||||||
|
|
||||||
const sorter = (a, b) => a.time > b.time ? 1 : -1;
|
const sorter = (a, b) => a.time > b.time ? 1 : -1;
|
||||||
|
|
||||||
indConfig = {}
|
var indConfig = null
|
||||||
settings = {}
|
settings = {}
|
||||||
settings
|
settings
|
||||||
//ostatni indicatory nez vwap, volume a bary
|
//ostatni indicatory nez vwap, volume a bary
|
||||||
indConfig = [ {name: "ema", titlevisible: false, embed: true, display: true, priceScaleId: "right", lastValueVisible: false},
|
var indConfig_default = [ {name: "ema", titlevisible: false, embed: true, display: true, priceScaleId: "right", lastValueVisible: false},
|
||||||
{name: "ema20", titlevisible: false, embed: true, display: true, priceScaleId: "right", lastValueVisible: false},
|
{name: "ema20", titlevisible: false, embed: true, display: true, priceScaleId: "right", lastValueVisible: false},
|
||||||
{name: "tick_volume", histogram: true, titlevisible: true, embed: true, display: true, priceScaleId: '', lastValueVisible: false},
|
{name: "tick_volume", histogram: true, titlevisible: true, embed: true, display: true, priceScaleId: '', lastValueVisible: false},
|
||||||
{name: "tick_price", titlevisible: true, embed: true, display: true, priceScaleId: "right", lastValueVisible: false},
|
{name: "tick_price", titlevisible: true, embed: true, display: true, priceScaleId: "right", lastValueVisible: false},
|
||||||
@ -50,7 +50,7 @@ indConfig = [ {name: "ema", titlevisible: false, embed: true, display: true, pri
|
|||||||
{name: "ppo", titlevisible: true, embed: true, display: true, priceScaleId: "middle", lastValueVisible: false},
|
{name: "ppo", titlevisible: true, embed: true, display: true, priceScaleId: "middle", lastValueVisible: false},
|
||||||
{name: "stoch2", titlevisible: true, embed: true, display: true, priceScaleId: "middle", lastValueVisible: false},
|
{name: "stoch2", titlevisible: true, embed: true, display: true, priceScaleId: "middle", lastValueVisible: false},
|
||||||
{name: "sec_price", titlevisible: true, embed: true, display: true, priceScaleId: "right", lastValueVisible: false},]
|
{name: "sec_price", titlevisible: true, embed: true, display: true, priceScaleId: "right", lastValueVisible: false},]
|
||||||
console.log(JSON.stringify(indConfig, null,null, 2))
|
console.log(JSON.stringify(indConfig_default, null,null, 2))
|
||||||
|
|
||||||
|
|
||||||
function initialize_statusheader() {
|
function initialize_statusheader() {
|
||||||
@ -129,6 +129,11 @@ function initialize_statusheader() {
|
|||||||
|
|
||||||
|
|
||||||
function get_ind_config(indName) {
|
function get_ind_config(indName) {
|
||||||
|
|
||||||
|
if (indConfig == null) {
|
||||||
|
indConfig = get_from_config("indConfig", indConfig_default)
|
||||||
|
}
|
||||||
|
|
||||||
const i = indConfig.findIndex(e => e.name === indName);
|
const i = indConfig.findIndex(e => e.name === indName);
|
||||||
if (i>-1)
|
if (i>-1)
|
||||||
{
|
{
|
||||||
|
|||||||
Binary file not shown.
@ -63,6 +63,7 @@ def get_log_window(runner_id: UUID, timestamp_from: float = 0, timestamp_to: flo
|
|||||||
c = conn.cursor()
|
c = conn.cursor()
|
||||||
res = c.execute(f"SELECT data FROM runner_logs WHERE runner_id='{str(runner_id)}' AND time >={timestamp_from} AND time <={timestamp_to} ORDER BY time")
|
res = c.execute(f"SELECT data FROM runner_logs WHERE runner_id='{str(runner_id)}' AND time >={timestamp_from} AND time <={timestamp_to} ORDER BY time")
|
||||||
finally:
|
finally:
|
||||||
|
conn.row_factory = None
|
||||||
pool.release_connection(conn)
|
pool.release_connection(conn)
|
||||||
return res.fetchall()
|
return res.fetchall()
|
||||||
|
|
||||||
|
|||||||
@ -25,6 +25,27 @@ import pandas as pd
|
|||||||
from collections import deque
|
from collections import deque
|
||||||
|
|
||||||
|
|
||||||
|
def is_still(lst: list, how_many_last_items: int, precision: int):
|
||||||
|
"""
|
||||||
|
Checks if the last N members of a list are equal within a given precision.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
lst (list): The list of floats to check.
|
||||||
|
how_many_last_items (int): The number of last items to compare.
|
||||||
|
precision (int): The number of decimal places to round to for comparison.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bool: True if the last N members are equal within the specified precision, False otherwise.
|
||||||
|
"""
|
||||||
|
if len(lst) < how_many_last_items:
|
||||||
|
raise ValueError("The list does not have enough items to compare.")
|
||||||
|
|
||||||
|
last_items = lst[-how_many_last_items:] # Get the last N items
|
||||||
|
rounded_last_items = [round(item, precision) for item in last_items]
|
||||||
|
|
||||||
|
# Check if all rounded items are equal
|
||||||
|
return all(rounded_last_items[0] == item for item in rounded_last_items)
|
||||||
|
|
||||||
|
|
||||||
#is_pivot function to check if there is A(V) shaped pivot in the list, each leg consists of N points
|
#is_pivot function to check if there is A(V) shaped pivot in the list, each leg consists of N points
|
||||||
#middle point is the shared one [1,2,3,2,1] - one leg is [1,2,3] second leg is [3,2,1]
|
#middle point is the shared one [1,2,3,2,1] - one leg is [1,2,3] second leg is [3,2,1]
|
||||||
@ -53,22 +74,43 @@ def is_pivot(source: list, leg_number: int, type: str = "A"):
|
|||||||
def crossed_up(threshold, list):
|
def crossed_up(threshold, list):
|
||||||
"""check if threshold has crossed up last thresholdue in list"""
|
"""check if threshold has crossed up last thresholdue in list"""
|
||||||
try:
|
try:
|
||||||
#upraveno, ze threshold muze byt vetsi nez predpredposledni
|
if threshold < list[-1] and threshold > list[-2]:
|
||||||
if threshold < list[-1] and threshold >= list[-2] or threshold < list[-1] and threshold >= list[-3]:
|
|
||||||
return True
|
return True
|
||||||
else:
|
|
||||||
return False
|
# #upraveno, ze threshold muze byt vetsi nez predpredposledni
|
||||||
|
# if threshold < list[-1] and threshold >= list[-2] or threshold < list[-1] and threshold >= list[-3]:
|
||||||
|
# return True
|
||||||
|
# else:
|
||||||
|
# return False
|
||||||
except IndexError:
|
except IndexError:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def crossed_down(threshold, list):
|
def crossed_down(threshold, list):
|
||||||
"""check if threshold has crossed down last thresholdue in list"""
|
"""check if threshold has crossed down last thresholdue in list"""
|
||||||
|
"""
|
||||||
|
Checks if a threshold has just crossed down a line represented by a list.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
threshold (float): The threshold value to check.
|
||||||
|
lst (list): The list representing the line.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bool: True if the threshold just crossed down the line, False otherwise.
|
||||||
|
"""
|
||||||
|
|
||||||
try:
|
try:
|
||||||
#upraveno, ze threshold muze byt mensi nez predpredposledni
|
#upraveno na jednoduchou verzi
|
||||||
if threshold > list[-1] and threshold <= list[-2] or threshold > list[-1] and threshold <= list[-3]:
|
if threshold > list[-1] and threshold < list[-2]:
|
||||||
return True
|
return True
|
||||||
else:
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
# #upraveno, ze threshold muze byt mensi nez predpredposledni
|
||||||
|
# if threshold > list[-1] and threshold <= list[-2] or threshold > list[-1] and threshold <= list[-3]:
|
||||||
|
# return True
|
||||||
|
# else:
|
||||||
|
# return False
|
||||||
except IndexError:
|
except IndexError:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user