From 83a7bb77dafd3f91c9561068e6940fa02f2cde8f Mon Sep 17 00:00:00 2001 From: David Brazda Date: Sun, 23 Apr 2023 17:43:27 +0200 Subject: [PATCH] strategy trade counter, gui shortcuts, better log --- v2realbot/ENTRY_backtest_strategyVykladaci.py | 10 ++++-- v2realbot/__pycache__/config.cpython-310.pyc | Bin 2767 -> 2779 bytes .../__pycache__/backtester.cpython-310.pyc | Bin 19094 -> 19106 bytes v2realbot/backtesting/backtester.py | 30 +++++++++--------- v2realbot/config.py | 16 +++++----- v2realbot/controller/services.py | 3 +- .../enums/__pycache__/enums.cpython-310.pyc | Bin 2289 -> 2289 bytes v2realbot/static/index.html | 1 + v2realbot/static/js/mytables.js | 29 +++++++++++++++++ v2realbot/static/js/mywebsocket.js | 5 ++- .../strategy/StrategyOrderLimitVykladaci.py | 18 +++++++---- ...trategyOrderLimitVykladaci.cpython-310.pyc | Bin 7239 -> 7494 bytes .../strategy/__pycache__/base.cpython-310.pyc | Bin 12773 -> 12980 bytes v2realbot/strategy/base.py | 15 +++++++-- .../utils/__pycache__/utils.cpython-310.pyc | Bin 7511 -> 7965 bytes v2realbot/utils/utils.py | 24 ++++++++++++++ 16 files changed, 112 insertions(+), 39 deletions(-) diff --git a/v2realbot/ENTRY_backtest_strategyVykladaci.py b/v2realbot/ENTRY_backtest_strategyVykladaci.py index b7f4097..c120908 100644 --- a/v2realbot/ENTRY_backtest_strategyVykladaci.py +++ b/v2realbot/ENTRY_backtest_strategyVykladaci.py @@ -4,7 +4,7 @@ from v2realbot.strategy.base import StrategyState from v2realbot.strategy.StrategyOrderLimitVykladaci import StrategyOrderLimitVykladaci from v2realbot.enums.enums import RecordType, StartBarAlign, Mode, Account, OrderSide from v2realbot.indicators.indicators import ema -from v2realbot.utils.utils import ltp, isrising, isfalling,trunc,AttributeDict, zoneNY, price2dec, dict_replace_value, print +from v2realbot.utils.utils import ltp, isrising, isfalling,trunc,AttributeDict, zoneNY, price2dec, dict_replace_value, print, safe_get from datetime import datetime from icecream import install, ic #from rich import print @@ -51,6 +51,7 @@ stratvars = AttributeDict(maxpozic = 400, slope_lookback = 300, lookback_offset = 20, minimum_slope = -0.05, + first_buy_market = False ) ##toto rozparsovat a strategii spustit stejne jako v main toml_string = """ @@ -129,7 +130,12 @@ def next(data, state: StrategyState): price = last_price state.ilog(e="BUY Vykladame", msg="first price"+str(price) + "pozic:"+str(vykladka), curve=curve, ema=state.indicators.ema[-1], trend=state.vars.Trend, price=price, vykladka=vykladka) ##prvni se vyklada na aktualni cenu, další jdou podle krivky, nula v krivce zvyšuje množství pro následující iteraci - state.buy_l(price=price, size=qty) + + ##VAR - na zaklade conf. muzeme jako prvni posilat MARKET + if safe_get(state.vars, "first_buy_market") == True: + state.buy(size=qty) + else: + state.buy_l(price=price, size=qty) print("prvni limitka na aktuální cenu. Další podle křivky", price, qty) for i in range(0,vykladka-1): price = price2dec(float(price - curve[i])) diff --git a/v2realbot/__pycache__/config.cpython-310.pyc b/v2realbot/__pycache__/config.cpython-310.pyc index 8a758b4a2c0a4bc60d6f38b9bfa881533cdc7d3a..330c5082f0e2a631a0296d7b5fdc26d8a5561d41 100644 GIT binary patch delta 248 zcmYj}O-{l<0EIhP+X4>%4|sW|9iA3=7|8V)BZK3q67hxB%e>UV($i-Zgh{ z>FCP0`@Z+`KEtn2zDZefYz`{nej}IfJ}S=+gAajf?z6ZOs1=<%hb5NR4$G?o>XuF@ zElEoaR`MfOb9d>o#`@YtlMS@kM93D}4AEg5U3%!{;-!xPI~cNyQ)@@`arS4=*~6H9 zM4r_b^fuoRdY6gA@%GB!N5hFWw<=A|&1^b1I=haOxyh1;h02l`Bin8-gJ?YXH;a{4 Vv#FUZ9!;w5mB#PK?kRXJ`~b8RKyv^9 delta 195 zcmW;AJ8r^27)9aviDM7O!`sGV2;tGurb!(k(IP>0>uZpZfF-1W4IuA;4WwWp&{MOA zl#Dptckb~uHhW`2<@))W^6z9;zdovK#o#QcQVwvGlF+7yeaH=qJikzA> z`5UXbxAItH{pg{^2HI>QW(x`1=rBgg1U8pVhAunkF~x_wefs!(-2p9z%rNrZ9y2-p gm2uHjM&5j0UM>b8SnKJU@_r-lF;+!sr;vCzPamInXMaBz&k#?4zj&w6$ao)5 eU(b+RGC;}6?^vZ+$YwRR0v7<%+ZV3@ delta 113 zcmZ29m2uisM&5j0UM>b8D6n)%*}akX7;CVEo2QRYytBWbi)V|$o tElD()U{|0*h?F!~%E#Y5J~%We$UhXQ+0Q*bB*@XlHTag~W+S!&7XWyTBD??q diff --git a/v2realbot/backtesting/backtester.py b/v2realbot/backtesting/backtester.py index 0339a75..2fcbbb2 100644 --- a/v2realbot/backtesting/backtester.py +++ b/v2realbot/backtesting/backtester.py @@ -43,8 +43,8 @@ from v2realbot.common.model import TradeUpdate, Order #from rich import print import threading import asyncio -from v2realbot.config import BT_DELAYS, DATA_DIR, FILL_CONDITION_BUY_LIMIT, FILL_CONDITION_SELL_LIMIT, FILL_LOG_SURROUNDING_TRADES, FILL_CONS_TRADES_REQUIRED -from v2realbot.utils.utils import AttributeDict, ltp, zoneNY, trunc, count_decimals,print +from v2realbot.config import BT_DELAYS, DATA_DIR, BT_FILL_CONDITION_BUY_LIMIT, BT_FILL_CONDITION_SELL_LIMIT, BT_FILL_LOG_SURROUNDING_TRADES, BT_FILL_CONS_TRADES_REQUIRED +from v2realbot.utils.utils import AttributeDict, ltp, zoneNY, trunc, count_decimals, print from v2realbot.utils.tlog import tlog from v2realbot.enums.enums import FillCondition from datetime import datetime, timedelta @@ -194,7 +194,7 @@ class Backtester: #TEST zkusime to nemazat, jak ovlivni performance #Mazeme, jinak je to hruza #nechavame na konci trady, které muzeme potrebovat pro consekutivni pravidlo - del self.btdata[0:index_end-2-FILL_CONS_TRADES_REQUIRED] + del self.btdata[0:index_end-2-BT_FILL_CONS_TRADES_REQUIRED] #ic("after delete",len(self.btdata[0:index_end])) if changes: return 1 @@ -235,9 +235,9 @@ class Backtester: #NASTVENI PODMINEK PLNENI fast_fill_condition = i[1] <= o.limit_price slow_fill_condition = i[1] < o.limit_price - if FILL_CONDITION_BUY_LIMIT == FillCondition.FAST: + if BT_FILL_CONDITION_BUY_LIMIT == FillCondition.FAST: fill_condition = fast_fill_condition - elif FILL_CONDITION_BUY_LIMIT == FillCondition.SLOW: + elif BT_FILL_CONDITION_BUY_LIMIT == FillCondition.SLOW: fill_condition = slow_fill_condition else: print("unknow fill condition") @@ -245,17 +245,17 @@ class Backtester: if float(i[0]) > float(order_min_fill_time+BT_DELAYS.limit_order_offset) and fill_condition: consec_cnt += 1 - if consec_cnt == FILL_CONS_TRADES_REQUIRED: + if consec_cnt == BT_FILL_CONS_TRADES_REQUIRED: #(1679081919.381649, 27.88) ic(i) fill_time = i[0] fill_price = i[1] print("FILL LIMIT BUY at", fill_time, datetime.fromtimestamp(fill_time).astimezone(zoneNY), "at",i[1]) - if FILL_LOG_SURROUNDING_TRADES != 0: + if BT_FILL_LOG_SURROUNDING_TRADES != 0: #TODO loguru - print("FILL SURR TRADES: before",work_range[index-FILL_LOG_SURROUNDING_TRADES:index]) - print("FILL SURR TRADES: fill and after",work_range[index:index+FILL_LOG_SURROUNDING_TRADES]) + print("FILL SURR TRADES: before",work_range[index-BT_FILL_LOG_SURROUNDING_TRADES:index]) + print("FILL SURR TRADES: fill and after",work_range[index:index+BT_FILL_LOG_SURROUNDING_TRADES]) break else: consec_cnt = 0 @@ -266,9 +266,9 @@ class Backtester: #NASTVENI PODMINEK PLNENI fast_fill_condition = i[1] >= o.limit_price slow_fill_condition = i[1] > o.limit_price - if FILL_CONDITION_SELL_LIMIT == FillCondition.FAST: + if BT_FILL_CONDITION_SELL_LIMIT == FillCondition.FAST: fill_condition = fast_fill_condition - elif FILL_CONDITION_SELL_LIMIT == FillCondition.SLOW: + elif BT_FILL_CONDITION_SELL_LIMIT == FillCondition.SLOW: fill_condition = slow_fill_condition else: print("unknown fill condition") @@ -276,16 +276,16 @@ class Backtester: if float(i[0]) > float(order_min_fill_time+BT_DELAYS.limit_order_offset) and fill_condition: consec_cnt += 1 - if consec_cnt == FILL_CONS_TRADES_REQUIRED: + if consec_cnt == BT_FILL_CONS_TRADES_REQUIRED: #(1679081919.381649, 27.88) ic(i) fill_time = i[0] fill_price = i[1] print("FILL LIMIT SELL at", fill_time, datetime.fromtimestamp(fill_time).astimezone(zoneNY), "at",i[1]) - if FILL_LOG_SURROUNDING_TRADES != 0: + if BT_FILL_LOG_SURROUNDING_TRADES != 0: #TODO loguru - print("FILL SELL SURR TRADES: before",work_range[index-FILL_LOG_SURROUNDING_TRADES:index]) - print("FILL SELL SURR TRADES: fill and after",work_range[index:index+FILL_LOG_SURROUNDING_TRADES]) + print("FILL SELL SURR TRADES: before",work_range[index-BT_FILL_LOG_SURROUNDING_TRADES:index]) + print("FILL SELL SURR TRADES: fill and after",work_range[index:index+BT_FILL_LOG_SURROUNDING_TRADES]) break else: consec_cnt = 0 diff --git a/v2realbot/config.py b/v2realbot/config.py index 514b929..6c44083 100644 --- a/v2realbot/config.py +++ b/v2realbot/config.py @@ -3,21 +3,21 @@ from v2realbot.enums.enums import Mode, Account, FillCondition from appdirs import user_data_dir -#how many consecutive trades with the fill price are necessary for LIMIT fill to happen() +#how many consecutive trades with the fill price are necessary for LIMIT fill to happen in backtesting #0 - optimistic, every knot high will fill the order #N - N consecutive trades required #not impl.yet #minimum is 1 -FILL_CONS_TRADES_REQUIRED = 2 -#during trade execution logs X-surrounding trades of the one that triggers the fill -FILL_LOG_SURROUNDING_TRADES = 10 -#fill condition for limit order +BT_FILL_CONS_TRADES_REQUIRED = 2 +#during bt trade execution logs X-surrounding trades of the one that triggers the fill +BT_FILL_LOG_SURROUNDING_TRADES = 10 +#fill condition for limit order in bt # fast - price has to be equal or bigger <= # slow - price has to be bigger < -FILL_CONDITION_BUY_LIMIT = FillCondition.FAST -FILL_CONDITION_SELL_LIMIT = FillCondition.FAST +BT_FILL_CONDITION_BUY_LIMIT = FillCondition.FAST +BT_FILL_CONDITION_SELL_LIMIT = FillCondition.FAST #no print in console -QUIET_MODE = False +QUIET_MODE = True #backend counter of api requests COUNT_API_REQUESTS = False #stratvars that cannot be changed in gui diff --git a/v2realbot/controller/services.py b/v2realbot/controller/services.py index 0b26b50..8e48204 100644 --- a/v2realbot/controller/services.py +++ b/v2realbot/controller/services.py @@ -222,12 +222,13 @@ def save_history(id: UUID, st: object, runner: Runner, reason: str = None): #zkousime precist profit z objektu try: profit = st.state.profit + trade_count = len(st.tradeList) except Exception as e: profit = str(e) for i in db.stratins: if str(i.id) == str(id): - i.history += "START:"+str(runner.run_started)+"STOP:"+str(runner.run_stopped)+"ACC:"+runner.run_account.value+"M:"+runner.run_mode.value+"PROFIT:"+str(profit)+ "REASON:" + str(reason) + i.history += "START:"+str(runner.run_started)+"STOP:"+str(runner.run_stopped)+"ACC:"+runner.run_account.value+"M:"+runner.run_mode.value+"PROFIT:"+str(round(profit,2))+ "TradeCNT:"+str(trade_count) + "REASON:" + str(reason) #i.history += str(runner.__dict__)+"
" db.save() diff --git a/v2realbot/enums/__pycache__/enums.cpython-310.pyc b/v2realbot/enums/__pycache__/enums.cpython-310.pyc index 4d9c1dbacfe6bf8f743bd101031e9d1a2686a294..017f62b5abb55cd5541bae2f635670eb3bdef7ce 100644 GIT binary patch delta 20 acmew;_)(BMpO=@50SMkmxo+fs#sL64Xa$%6 delta 20 acmew;_)(BMpO=@50SHc>cHYSSi~|5aj|L +
diff --git a/v2realbot/static/js/mytables.js b/v2realbot/static/js/mytables.js index 0f4818b..e594718 100644 --- a/v2realbot/static/js/mytables.js +++ b/v2realbot/static/js/mytables.js @@ -1,6 +1,35 @@ API_KEY = localStorage.getItem("api-key") +//KEY shortcuts +Mousetrap.bind('e', function() { + $( "#button_edit" ).trigger( "click" ); +}); +Mousetrap.bind('a', function() { + $( "#button_add" ).trigger( "click" ); +}); +Mousetrap.bind('d', function() { + $( "#button_dup" ).trigger( "click" ); +}); +Mousetrap.bind('c', function() { + $( "#button_copy" ).trigger( "click" ); +}); +Mousetrap.bind('r', function() { + $( "#button_run" ).trigger( "click" ); +}); +Mousetrap.bind('p', function() { + $( "#button_pause" ).trigger( "click" ); +}); +Mousetrap.bind('s', function() { + $( "#button_stop" ).trigger( "click" ); +}); +Mousetrap.bind('j', function() { + $( "#button_add_json" ).trigger( "click" ); +}); +Mousetrap.bind('x', function() { + $( "#button_delete" ).trigger( "click" ); +}); + //on button function store_api_key(event) { key = document.getElementById("api-key").value; diff --git a/v2realbot/static/js/mywebsocket.js b/v2realbot/static/js/mywebsocket.js index 555f349..3759572 100644 --- a/v2realbot/static/js/mywebsocket.js +++ b/v2realbot/static/js/mywebsocket.js @@ -62,7 +62,7 @@ function connect(event) { var lines = document.getElementById('lines') var line = document.createElement('div') line.classList.add("line") - const newLine = document.createTextNode("-----------------NEXT ITER------------------") + const newLine = document.createTextNode("---------------") line.appendChild(newLine) lines.appendChild(line) @@ -84,8 +84,7 @@ function connect(event) { logcnt++; row = '
'+logLine.time + " " + logLine.event + ' - '+ logLine.message+'
' str_row = JSON.stringify(logLine.details, null, 2) - - row_detail = '
' + str_row + '
' + row_detail = '
' + str_row + '
' var lines = document.getElementById('lines') var line = document.createElement('div') diff --git a/v2realbot/strategy/StrategyOrderLimitVykladaci.py b/v2realbot/strategy/StrategyOrderLimitVykladaci.py index 4d0d3aa..ccb8571 100644 --- a/v2realbot/strategy/StrategyOrderLimitVykladaci.py +++ b/v2realbot/strategy/StrategyOrderLimitVykladaci.py @@ -1,10 +1,11 @@ from v2realbot.strategy.base import Strategy -from v2realbot.utils.utils import parse_alpaca_timestamp, ltp, AttributeDict,trunc,price2dec, zoneNY, print +from v2realbot.utils.utils import parse_alpaca_timestamp, ltp, AttributeDict,trunc,price2dec, zoneNY, print, json_serial from v2realbot.utils.tlog import tlog, tlog_exception from v2realbot.enums.enums import Mode, Order, Account from alpaca.trading.models import TradeUpdate from alpaca.trading.enums import TradeEvent, OrderStatus from v2realbot.indicators.indicators import ema +import json #from rich import print from random import randrange from alpaca.common.exceptions import APIError @@ -12,13 +13,15 @@ import copy from threading import Event + class StrategyOrderLimitVykladaci(Strategy): def __init__(self, name: str, symbol: str, next: callable, init: callable, account: Account, mode: Mode = Mode.PAPER, stratvars: AttributeDict = None, open_rush: int = 30, close_rush: int = 30, pe: Event = None, se: Event = None) -> None: super().__init__(name, symbol, next, init, account, mode, stratvars, open_rush, close_rush, pe, se) async def orderUpdateBuy(self, data: TradeUpdate): o: Order = data.order - self.state.ilog(e="Příchozí BUY notifikace", msg="order status:"+o.status, status=o.status, orderid=str(o.id)) + ##nejak to vymyslet, aby se dal poslat cely Trade a serializoval se + self.state.ilog(e="Příchozí BUY notifikace", msg="order status:"+o.status, trade=json.loads(json.dumps(data, default=json_serial))) if o.status == OrderStatus.FILLED or o.status == OrderStatus.CANCELED: #pokud existuje objednavka v pendingbuys - vyhodime ji @@ -68,6 +71,7 @@ class StrategyOrderLimitVykladaci(Strategy): async def orderUpdateSell(self, data: TradeUpdate): + self.state.ilog(e="Příchozí SELL notifikace", msg="order status:"+data.order.status, trade=json.loads(json.dumps(data, default=json_serial))) #PROFIT #profit pocitame z TradeUpdate.price a TradeUpdate.qty - aktualne provedene mnozstvi a cena #naklady vypocteme z prumerne ceny, kterou mame v pozicich @@ -117,19 +121,19 @@ class StrategyOrderLimitVykladaci(Strategy): def buy(self, size = None, repeat: bool = False): print("overriden method to size&check maximum ") if int(self.state.positions) >= self.state.vars.maxpozic: - self.state.ilog(e="buy Maxim mnozstvi naplneno", curr_positions=self.state.positions) + self.state.ilog(e="buy Maxim mnozstvi naplneno", positions=self.state.positions) print("max mnostvi naplneno") return 0 if size is None: sizer = self.state.vars.chunk else: sizer = size + self.state.blockbuy = 1 self.state.vars.lastbuyindex = self.state.bars['index'][-1] - ic(self.state.blockbuy) - ic(self.state.vars.lastbuyindex) + self.state.ilog(e="send MARKET buy to if", msg="S:"+str(size), ltp=self.state.interface.get_last_price(self.state.symbol)) return self.state.interface.buy(size=sizer) - + def buy_l(self, price: float = None, size = None, repeat: bool = False): print("entering overriden BUY") if int(self.state.positions) >= self.state.vars.maxpozic: @@ -139,7 +143,7 @@ class StrategyOrderLimitVykladaci(Strategy): if price is None: price=price2dec((self.state.interface.get_last_price(self.symbol))) ic(price) print("odesilame LIMIT s cenou/qty", price, size) - self.state.ilog(e="send buy to if", msg="S:"+str(size)+" P:"+str(price), price=price, size=size) + self.state.ilog(e="send LIMIT buy to if", msg="S:"+str(size)+" P:"+str(price), price=price, size=size) order = self.state.interface.buy_l(price=price, size=size) print("ukladame pendingbuys") self.state.vars.pendingbuys[str(order)]=price diff --git a/v2realbot/strategy/__pycache__/StrategyOrderLimitVykladaci.cpython-310.pyc b/v2realbot/strategy/__pycache__/StrategyOrderLimitVykladaci.cpython-310.pyc index 778a6e769ac5fd736fcef139ba4741206f79f850..02f26d6f9cd7b505749a47fc2a896ec43668d352 100644 GIT binary patch delta 3507 zcmaJ@U5p!76~1@Ig$IQC0_WWE{tz`-^5;9} zocrB#&OPUNK0Woj#dJHBiWB(!`OH~%ef~jun*RR5;iG*wUW-%02-BT}o2(_>R4t{R zLr&Vw)G}_imUVNroRS&Nn47QV)jI4H-0|ADJ5ifZ&k?8SmTD!njyjXIN#Kk*Q*OCd zREa(%?^K)*cR-xpZge6((eZo=}9q6@vEV@Ff>Ce&OD)pl)g4cz0 zYrPtM@SiIwKVf_Amg!l%S$E`RTBl3$=XCP%r}URpzNa76_yPF~{l4)m>>iURLd*T6 zPRP5oM{TmH^@vSvjZvocG+Qqc5!y0D$PV|Yh%kMqJ)|r&)G0x&h}y9=%{w?+$JaEz zr1mH5Fmv8IL^-r@ERMpg*0DZROW zv?KjQ4*GO2#fWS_%M1;q0s`DVw{_qlxvs9qEThCMswhxb9#Du!9b(T8s0t;taeX8y zZ5ptevk&${+Y<4NS{1?J>`?DNJxWM%MVV?Wx7W!a&K?p&_Hg@Kf>+@$>JziW0rk25N3~9A9sO@i+=YjW)CV*x7pxt0S82RyD$( z13CW+DruWz>|kWI>VBltz0+o`CRb4&LMsJ_})S|l4!)tj*Md>C&qv*1Qi({XxN!70V6e#B4Kt{ z0}~G%gNX#3+ioeDX6L~wIgF?|s9f)ZM?W1Ml49vSW*MB#qQHO{%!xg|H8C0+#LVCh zv#3VOZayC2v5=1vaDE{sS>Of)2rOeyVd(>nC@2RMsa?cAQe%(UQ)YQ*HO=zMYRa5p zI4n>*i@#fQ4@od~l$)5^0t}1oYeXkh+`%5Z0v!$i4(K|5jq1cww=9olW;6ToJBZ? zpjzZxxXK|cBYYdc*Kdn;RmuDfl)Z^?4dF6s4c_jy7{7u7EMWc?!rKTdgcJ!sk4tPd zegQ%C`>XQ1*<;r(!gJNw?HF#M!74y4sYVYpeS5Vjf<_6t1(be9HUFC(2ED&xIS!uS zeGNdne@H8Zcy^_$&w6}oT0%5=B`(kcy3RD8RnahM8qVK!S$(UG6$t|r1@ zi+S=sA<`_&No(xdBHWZ_hgpopMFRhei&%adz6hw_G`u(@)Qf|X+8Jo9|#va7G#CUbNTsq7Gbe5?pZBXxpL;}rL%8Tz{!eeSDLF|Xe*0VJs1@@b$JK?9Dfmi zvOzX)pj_Q6GOFbIQMZ1t)81${_-k@2U#{7x!D~{t;-_y}!gT7M7){eD)U*Jqp&%#7 z&u;_N46nIi@h38`Y}Y~Ul|CvIV%h|qr&+o&Cv%}`%rHOo_;le1bXLWw<~|bE(v2?X zCd|(!&PY%GY5c&+f{Od{g)0~Kgv|w*Z|IffMQ})wsNi>)_(^$qVk*JGihBr)a(QB| zuPjgFGZsNL|J3~OE*hyexPz+*f~r>ximP;}8dfQ5qwFHWU4(lGn9%K#-FB-Iq%7zx zRZt2Jqdju`=<#IHqeqmN=pcu=PR?!Qm*M7{ty}Ar4c>)pRG`?m@BD=PRmsZkHm&NM zi*jLd@{;oJ64IdKez;L@H7qB%1${rr$r%bZ} zMdyK=j%n`kWFEAKxXM!zmO1!(NF60hG_9wPMd!1zLN=S{sIBgoznOaLyc$z};m!-( zsyjE^VxcRVj<+D-1%M~Oj3)v7@m;;u>bl;7LXNTWG(tw+D3|x)VSb_Rbn1=z0!|#b zj*%%k11}68m!HY!af!py5A%A9wOwA2pOt4#{Lkh+l*h#Pz#ZJpRg%!(J#p@ogCBj# eZL_Xpy@Dm+VZ9{@worj40h2UJlbS+W2>lm-x*-4n delta 3274 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 SXJbW-nXDpc%;IlV>;C|ze;=j* diff --git a/v2realbot/strategy/base.py b/v2realbot/strategy/base.py index 534e8ae..8c7c2bc 100644 --- a/v2realbot/strategy/base.py +++ b/v2realbot/strategy/base.py @@ -17,6 +17,8 @@ from v2realbot.interfaces.backtest_interface import BacktestInterface from v2realbot.interfaces.live_interface import LiveInterface from alpaca.trading.enums import OrderSide from v2realbot.backtesting.backtester import Backtester +from alpaca.trading.models import TradeUpdate +from alpaca.trading.enums import TradeEvent, OrderStatus from threading import Event, current_thread import json @@ -48,6 +50,7 @@ class Strategy: self.account = account self.key = get_key(mode=self.mode, account=self.account) self.rtqueue = None + self.tradeList = [] #TODO predelat na dynamické queues @@ -308,7 +311,7 @@ class Strategy: #for order updates from LIVE or BACKTEST #updates are sent only for SYMBOL of strategy - async def order_updates(self, data): + async def order_updates(self, data: TradeUpdate): if self.mode == Mode.LIVE or self.mode == Mode.PAPER: now = datetime.now().timestamp() else: @@ -316,10 +319,16 @@ class Strategy: print("NOTIFICATION ARRIVED AT:", now) + #pokud jde o FILL zapisujeme do self.trades a notifikujeme + if data.event == TradeEvent.FILL: + self.tradeList.append(data) + ##TradeUpdate objekt better? order: Order = data.order - if order.side == OrderSide.BUY: await self.orderUpdateBuy(data) - if order.side == OrderSide.SELL: await self.orderUpdateSell(data) + if order.side == OrderSide.BUY: + await self.orderUpdateBuy(data) + if order.side == OrderSide.SELL: + await self.orderUpdateSell(data) async def orderUpdateBuy(self, data): print(data) diff --git a/v2realbot/utils/__pycache__/utils.cpython-310.pyc b/v2realbot/utils/__pycache__/utils.cpython-310.pyc index 8781759cf3ed921414c7afe0fa362485ed590829..b066da0aea0352d3de5088651ac1c3b19bc4fb7e 100644 GIT binary patch delta 2274 zcmZ{lYitx%6vyYz&d%;mx7%&IrQ2>7wk@=sw)9P3K%u3j@=%0Q!40~sdv9^+zPLNv z2Wc$WY9eT`ToWNi9wrb}(3r-=XyONr`bGUjG?{3k#+Z=sjW32s@ti3jkl1E^J@e@vyDX+O9R&;fYi zvf2yk7CH#(7AlWO`mpGhznRsEsSKrZNnJMWyEtXs%-hSOl#OO+)L=0ievErRXuIIq z0#9};;HYCpx**Mv8Tq2TPa2UF$sp5SBH{0|Qi@DUN9{8(Unbp~l?~Y0bk+S8GxEr+ zG%4xiX!|fTLKD$Mj%7n*Je>?hL$P!s!D2={oeE9HjTh57BgCWeY&>-+#5hm$tZp-H zhnQiy_D*Nm5K5-DEk)UsW$U)E_Fo9oHqNF^2W4Z?T*7!?;wvHj+k2Wv#kjJ2tuq@P zV-bi|iaT2YkZm5~CJK@7$~KL7iA)q(zQaQ>wRlIaBBWA;l+9IEm}RVjDbt%}DH<`- z5rZYzAs$WEh#!?8(Zx;RgwX7bUDAwXsBD%t^dvMmp?zplF~p z-&68Lm;F!T78Pp4YK{q-iUGUkn6T-LL})x_L?YY|LtYLL`_<~oHZZK+c$rt zRM?qH{DilNH`O0Vqj=s?uC}6Qop{NyCSZMDFN|g4fvtPs*Lh4{^4fTpxLe|1{K?Tr zNRKFS)sbDI&-HpoKl*M&3;;}p=8_rSgX2L29`!?Kq-3KLY*Z|{f@Hm@&>A4r6WS_o zFRm&?3?sISUn@$>c{kWQ;mKlC&?GP9qY<~tyTujlRq~u@&I>@49eH1q5mDd{=2KiN z1Iq1upXhO4t7wFQ>5OJ0MlO?Jrjt!&(kYfQbi((G!a#B1C@dJi@8(zds5n;Q6TSJd zf+MIZ06!@r{Ghm+{|AYRQ=WPH~FZ78Pua|%9g82zNS=_QyQsBPuvrr5BYa_Vm zv3J@Ho=e3(#q~0vobYptcT4^u^|%vVG40tLTu*);U9Ey{LfyuPP}q&wBkKJDJI;M2 zw)<<#9!<)0z@<*d;7$*V6aL_;i|B$q#tQiv7!UIFx%heUt^cOG9#pt}&xiyG#`9usKBry?VA~7-QIhTaE4>oyzJv=10n`7w#zJa$3JAXvb=!#k1F=tP&Tq4GKCu)N{!Mia05KoF>-mTnw zcrON9^&h2=_oK3!4+w^7ujGUHwg%H4;=`EsFs41iSMk*tXB5>nd<4}IF?Q0H9N-AwYKmL;SP~oIY3tVuZ)?jL3&B_R2?%Ki z27MJ#Hh-i3V4UdH<2%i2!18t&G<8eKy^Lxd3ur19!> zS@zTW7@T*7*;<%)#n?*t#+B?>as!R|$hR(&$rg(xBWvVK#Y!e42WY6CkRq&yzeC|j zADR?jWnXLYVHs+f+add4kNXtc45mAZ;s0>oWZU6$Pt3EEe65HkyW9nLJReV}9qQRi z#;BGH!qmk~xl|NIBf;cu^phL%B&^Au@V)o>x+h7|5MkE9O> zqrNV77=&+!gT`eVKJ$&TgYcU#$fm(re`fG0k`EB}6Als%5f~v$$PqYUl5i9j>)Tv; zGK+-L!o7MY8{L8ST^oUt_}`ETo2fr9#8I9-R*{FvGY12He=|*&6~Y4%t%O}pk#GbK z`6CbVFTkun$*S;?zn#s%E&r!%3(N+3*=z7gAlXtz?|GYPD~O_L%N7cz?RdUCZuP=gEA9a0Z;AXV_Vgp)SuQ6x4AAm^=sbp$Xpxa@k1OMA#00hGIdQ z{3bpX2SUf2r89XRPd5PT8aKuFlH<}|Fztq{7IT+rjup|wINnU{~(Kb8H zzX6NUcGd$wN6#KmTXRZULB2=0MtGM%t}3AE$d=3a#ljw%C+!O1eZmKX7-4BCRg^`z z)g0?k@zg3z-HODzv}?LDRnF#)_KF!pQl;e^&=A|^*h=Q(kd2KvM#vn7tFb}+82u1y zoeiU4YSn6<%OH)l65<54w%q^# diff --git a/v2realbot/utils/utils.py b/v2realbot/utils/utils.py index bae320d..718163c 100644 --- a/v2realbot/utils/utils.py +++ b/v2realbot/utils/utils.py @@ -16,6 +16,24 @@ import tomli from v2realbot.config import DATA_DIR, QUIET_MODE import requests from uuid import UUID +from enum import Enum +#from v2realbot.enums.enums import Order +from v2realbot.common.model import Order, TradeUpdate + +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): apiToken = '5836666362:AAGPuzwp03tczMQTwTBiHW6VsZZ-1RCMAEE' @@ -38,6 +56,12 @@ def json_serial(obj): return obj.timestamp() if isinstance(obj, UUID): return str(obj) + if isinstance(obj, Enum): + return str(obj) + if type(obj) is Order: + return obj.__dict__ + if type(obj) is TradeUpdate: + return obj.__dict__ raise TypeError (str(obj)+"Type %s not serializable" % type(obj)) def parse_toml_string(tomlst: str):