From 8eb4a3f04555e2582252a606300857d799463f13 Mon Sep 17 00:00:00 2001 From: David Brazda Date: Sat, 22 Apr 2023 21:02:07 +0200 Subject: [PATCH] BT FILL CONDITIONS a FILL LOG SURROUNDING TRADES --- testy/testExecList-standard.py | 153 +++++++++--------- v2realbot/__pycache__/config.cpython-310.pyc | Bin 2590 -> 2762 bytes .../__pycache__/backtester.cpython-310.pyc | Bin 18073 -> 18999 bytes v2realbot/backtesting/backtester.py | 57 +++++-- v2realbot/config.py | 15 +- v2realbot/controller/services.py | 9 +- .../enums/__pycache__/enums.cpython-310.pyc | Bin 1924 -> 2289 bytes v2realbot/enums/enums.py | 10 ++ ...trategyOrderLimitVykladaci.cpython-310.pyc | Bin 7083 -> 7239 bytes .../strategy/__pycache__/base.cpython-310.pyc | Bin 12743 -> 12773 bytes v2realbot/strategy/base.py | 7 +- 11 files changed, 164 insertions(+), 87 deletions(-) diff --git a/testy/testExecList-standard.py b/testy/testExecList-standard.py index 008e644..89e61a1 100644 --- a/testy/testExecList-standard.py +++ b/testy/testExecList-standard.py @@ -11,34 +11,34 @@ btdata = [(1679081913.290388, 27.8634), (1679081913.68588, 27.865), (1679081913. from bisect import bisect_left -def get_last_price(time: float, symbol: str = None): - """"" - returns equity price in timestamp. Used for validations later. - TODO: optimalize - """"" - for i in range(len(btdata)): - #print(btdata[i][0]) - #print(i) - if btdata[i][0] >= time: - break - return btdata[i-1] +# def get_last_price(time: float, symbol: str = None): +# """"" +# returns equity price in timestamp. Used for validations later. +# TODO: optimalize +# """"" +# for i in range(len(btdata)): +# #print(btdata[i][0]) +# #print(i) +# if btdata[i][0] >= time: +# break +# return btdata[i-1] -def take_closest(myList, myNumber): - """ - Assumes myList is sorted. Returns first lower value to the number. - """ - pos = bisect_left(myList, (myNumber,)) - if pos == 0: - return myList[0] - # if pos == len(myList): - # return myList[-1] - after, afterPrice = myList[pos-1] - return after,afterPrice +# def take_closest(myList, myNumber): +# """ +# Assumes myList is sorted. Returns first lower value to the number. +# """ +# pos = bisect_left(myList, (myNumber,)) +# if pos == 0: +# return myList[0] +# # if pos == len(myList): +# # return myList[-1] +# after, afterPrice = myList[pos-1] +# return after,afterPrice -print("bisect price") -print(take_closest(btdata, 1679081913.986395)) -print("stamdard price") -print(get_last_price(1679081913.986395)) +# print("bisect price") +# print(take_closest(btdata, 1679081913.986395)) +# print("stamdard price") +# print(get_last_price(1679081913.986395)) #(1679081919.018929, 27.87), (1679081919.018932, 27.87), (1679081919.018938, 27.87), @@ -122,61 +122,66 @@ print(get_last_price(1679081913.986395)) -# def get_index_bisect(myList, time): -# """ -# Assumes myList is sorted. Returns first biggeer value to the number. -# """ -# pos = bisect_left(myList, (time,)) -# if pos == 0: -# return myList[0] -# if pos == len(myList): -# return myList[-1] -# return pos -# #after, afterPrice = myList[pos] -# #return after,afterPrice +def get_index_bisect(myList, time): + """ + Assumes myList is sorted. Returns first biggeer value to the number. + """ + pos = bisect_left(myList, (time,)) + if pos == 0: + return myList[0] + if pos == len(myList): + return myList[-1] + return pos + #after, afterPrice = myList[pos] + #return after,afterPrice -# def get_index(btdata, time: float): -# index_end = None # -# range_end = time -# print("range_end",range_end) +def get_index(btdata, time: float): + index_end = None # + range_end = time + print("range_end",range_end) -# for i in range(len(btdata)): -# #print(btdata[i][0]) -# #print(i) -# if btdata[i][0] >= range_end: -# index_end = i -# break + for i in range(len(btdata)): + #print(btdata[i][0]) + #print(i) + if btdata[i][0] >= range_end: + index_end = i + break -# print("index_end", index_end) -# print("oriznuto",btdata[0:index_end+1]) -# return index_end + print("index_end", index_end) + print("oriznuto",btdata[0:index_end+1]) + return index_end -# index_end = get_index(btdata, 1679081919.018939) -# print("get_index", index_end) -# index_end = get_index_bisect(btdata, 1679081919.018939) -# print("get_index_bisect", index_end) -# new_range = btdata[0:index_end+1] +index_end = get_index(btdata, 1679081919.018939) +print("get_index", index_end) +index_end = get_index_bisect(btdata, 1679081919.018939) +print("get_index_bisect", index_end) +new_range = btdata[0:index_end+1] -# print("novy rozsah?", len(new_range)) -# print("puvodni pole", len(btdata)) +print("novy rozsah?", len(new_range)) +print("puvodni pole", len(btdata)) -# #LIMIT FILL - BUY -# submitted_at: float = 1679081914.739644 -# limit_price: float = 27.865 -# fill_time = None -# for i in new_range: -# #print(i) -# ##najde prvni nejvetsi čas vetsi nez minfill a majici -# ## pro LIMITku uděláme nějaký spešl BT_DELAY.LIMIT_OFFSET, aby se nevyplnilo hned jako prvni s touto cenou -# ## tzn. o kolik se prumerne vyplni limitka pozdeji -# if float(i[0]) > float(float(submitted_at) + float(0.020)) and i[1] <= limit_price: -# #(1679081919.381649, 27.88) -# print(i) -# fill_time = i[0] -# print("FILL LIMIT BUY at", fill_time, "at",i[1]) -# break -# if not fill_time: print("NO FILL for ", limit_price) +#LIMIT FILL - BUY +submitted_at: float = 1679081914.739644 +limit_price: float = 27.865 +fill_time = None +for index, i in enumerate(new_range): +#for i in new_range: + #print(i) + ##najde prvni nejvetsi čas vetsi nez minfill a majici + ## pro LIMITku uděláme nějaký spešl BT_DELAY.LIMIT_OFFSET, aby se nevyplnilo hned jako prvni s touto cenou + ## tzn. o kolik se prumerne vyplni limitka pozdeji + if float(i[0]) > float(float(submitted_at) + float(0.020)) and i[1] <= limit_price: + #(1679081919.381649, 27.88) + print("pět předtím",new_range[index-5:index]) + print(i) + print("pět potom",new_range[index+1:index+6]) + # print(index) + fill_time = i[0] + ##zalogovat fill time + print("FILL LIMIT BUY at", fill_time, "at",i[1]) + break +if not fill_time: print("NO FILL for ", limit_price) # #LIMIT FILL - SELL # for i in new_range: diff --git a/v2realbot/__pycache__/config.cpython-310.pyc b/v2realbot/__pycache__/config.cpython-310.pyc index aa6c4a1a3daa70ae436ba4653e5e88f73d213552..64679556b0ef17b671662c8794c9ba777e60af7e 100644 GIT binary patch delta 809 zcmYL`zfaph6vutZ#b+mR62J-h0WIN2tB6MG(n?5GRf-d2H6$WVhTd|Dcm|n<7+uW3 z!~j#(1$pnUttrT36OI{bGovv zfCl=70{VH3&WJ1tDUqc_HVbJt4u*^OF=QZnf$1FNs0lMP53{rYb95fgOj?9IExG8h zOe;{J3ouU?!KC-ZcK0Xh5)^3_N_1JME5f@f)HV75%8pX2+{h!~G?u|M<&L6l`| zFdF&6Kz5B8<0(<(X$eCjBk)Dxri{(-L(Hk@B3u<~EKNxzjc(sujO(Eh|6aPaN`GD; z(irnbUcgvA{1ac^nipEThIv*RauPEVRf%cmB$DmCAn-`6F&5C24B~}rhOZDRhqG#Z zN0uY)m3!LY+~+mImxaJrq>91Y3wTlHC5f^`MPj67rCx`yiEmHHDs z4BwKCGoBE3N(RTr;PEk6Wman1trpwrv>n##Zdwh8bsM{VyW6m6Wm0N&wwcrKc02vH zWw*EQToG<=Iz3wa*KOH7yVGVb`>$Ec-m!br@7`6MMvJs=YvDIyrR3Nr)8O^%CG8`6 nIz7ezX+_$zBOgwN?sFvE;}-&H#S|BW367~)MK~7z(jWf?fs3~) delta 635 zcmYL_zi-n(6vyw9i+yoyCrzAR{XtVCP^}2WNF-DVXkkEM>2}M>%DYxBX-}imK=l7%iF7Ol2a|k})-#&rVx%M~d z*X!Zd1tmbBJguBs!orvd8xKDwQ29VbRaszNQsGp|a{@N-D+2toBx;yd!NJVI%!QgN zgR9sP0}uQwCOoJM9~z<#YoY;7u?8*Cgg~?uJqbh`+M)v;(M47C@Vfp|UWcyOfS%Yy zc?-?AP~8>-=pT}B{jV84qy^uPvgnyo5S9uyPCym*ng1*uZrB)h@ua5Y5SQM( zjgq$WQTbQ@#%la6M8TzuXK^OwAiv9QKW(G-GGy8_2H&7=ux+sFTt=o{2MAM48G;j^ z>R|DjeWJ9N?^*Z8rd;qB>ij_KM2EH>prCh*${?O(x?^%PuI?H14OaIoC$x`MCSR%Z z-TaGnhYs^U)^EC#f3`=yu%ojxTwAIu*q6`we$D*-awt7qeB1%x>-D*7JJ%+TliG3OIIdgAM+kMD)=pYF&@SVhakA?ArM8Ph(jPv0SO@?5D0`25<=qmzBjhxxTUN# z-@Nx7?|a|-t~dMaHS&#*k%SeGM+Er2&_Ag@^Td;h4l?%Sp$BV5gWO;w<)qOlHyTZH z6A@IR2K8nmC8vxQxy4A!X`@wcHQMAhqg`(2^pM_RbjqE49M-#xjGW=)h@LgFa@OdU zyZPL&_sG4lo?qW%?3MR%TvXq09FPxe(rY>SATY%ALq?z6$B}XUu+cB~Z!#Q_j{-fR z-)0QR1IC~{$nkahF=I#`GLFl~jT7<-V^|(0LRipZrIYf=89}XA8$KYY4Qrx&O7+hR zxn%WEK0%0N;dfdoEZJJc)@Zh185<>XTp|Is?r*NS>FKjGGx>>gvy*4fpFKC5KYihW z{LIxmnmF6#P(WvWHHXqg-T^q0lxUho^;hhRUeh7Ly$ z;4p{aAp2_QVD}C>B6pBs`bB{rWB&;0WQJ+s2grvuUI|x8%x+B!9~5sF9Fcx&V>CJ| zk`wGB@quI;Z3Y?Fr)wr1z{S$+NAXNu5|LuDK-&?wpZzP|P4==(!bs3Mz~sVo5D6#P z#}k>(lgRA1sH#zyC@v||V@Tv+i2XRxO)U1e#I)EHVyEi*v%^3vNC38e2^hrSnSiJA zl#e}HH(dKDp=}N+h3!Zwx+K!)?U>_RBa^~|_PfN@;A+STsbZ@D9PuTx8s0GzRwH)8 zt}E4p)VLE~jhc0Q-T?EnP6XybJE_82M1ate<^{VEr2VbJ8i7&37E4Vn!di_iN%T1< zN}sbOCxpx%(<;nR@v0vd2{@A7d_Cnz>*RWionD7T@~CTmBG|2}f5}Im1-_8ubAspq zC-^~-T@!(tRKti>#TLNYtt|qMwx~p?ndI_*^W|-;ue`x(|1DNaV0GK3)h};ajdQg6 zJKI)A{*TpQG@N_diGH*OueY!~`u{D5g;HQ8xb01BkH3}eVETH^90T75>|m*VNra{5 z93S}pF!ww73O%*v?e^STY%_roq}IJ*v-O*93StbHu>R#g>r+HW7Qb88reph?A`0?~u8%%N5R<8w<>|`6 zD3hDT=nwyaA0_OCWP6R*$}E<=tXJzsvJ2XxMYWX{EQq&Kltn1FD=BYLbJwaXNiM*v zX%-7>Rx0JPhBdQlXjFldIfE1|c(et{()9TJc~_dBId?xV z#`G@4CiS9GwDV9^M>U$a78fg;P17hehTskaSfwdePZ|f{2JRl8yKCya8%8&3YF@GF zH0x_Rb25c2Ap`;Blkk*WU&W>rx}-pFL%@5=K^z@La29}@VXvezjk$zZ?6Gds69`VS zUpF18x&ET5Y7f(U0VOvsDiu4Aiu2p?BR5ub>&k9q;#MYl4{Gw;RDt%fqi>*|82~?m zr}6~=QcxoGBt&8)A;w@-OT-c+LIV5=i2>3jhQtssWZ_APT|^?%BlTj!cPm%VHdkbu zD*dR0q~$y3W1Igsul4KbWtK9_UY!qz`Jmpee4&_#zW{e9vNp8=pkSTpaeQ5@K_BN^bHYu+ z=Jx8n?OlG^3DDm;fo%Z+1%O{DC2>1;BWw~H5>)o^8o_P=TNHVNNrO=h$mbceC7~wY zAajvyS!6fa&Dek7Dv@#`cFXlNHX7dVM8|Kpmf9Sjr%)B00Cce-phFuri5h|a23IXm z6TRN%cj`QY(g2XY8gk|M9dR<>Iy<$oiE^s zp9OZlU4_JrRjLb{Jw>BW6R4{t_EPq6R~E`!jP!^DP}*WXiA2N{X(L!R#Ya*i`%g9% z5~1J*{t=6?_U7xZl8 zg1l^S^SEWaDEXl%LBrlvM&eW}>qD~C+vg)A?5F#V&h6R~-wj_L-LqBj zxGIk2C%0?)SV1uhn(i$wiR{Au^%*R9l;9E~e|clVBLPtSgNR4LuC*Gl;$d{>x2_xQ zB0GKH-}kPn_s=*7ZP#RVHG%Ce@ym2`Zg?)V%b<80xCJjf#t74yLUqUehKM_p3b9p;fyy;!l~ zkBjoyU)f(ye3CrMK0N#otnr88Zyf#-ihp@)4f>Vs5f8v2oPG^Joeu^tvLBvYCyz60 zq$l=uK;}SWagn~no*!x3^G#&sw(Sbt@TKC#OFBIEA@=&n(&)F4@!JT#i{SeRZWW=g z0`3%Q`~eKyP~lQhS1J6t@Ok$BQ$IO$1CY50jiMlr%>$eZuA+-}5w6EMB=Ceyv)X8C zxC8k``gwTCfdxCS7AfppDqGa{GGg0QH;U(+hx=1iw`bT7N1vJgF|O@bwT0?MIaaM8 zQMd4#3C_5TiclDq^C{&rMP|8Vs*F9zzI^+Y+v}0a3mnf8%t>#X+>e+? zJ5q*c8P7M~1un7tSl6DT$iu5LPp~&lCbmA-6X4aLjlDY7evBF*1lfsy7x{Fnz&|H$ zHX=DXp_r-;e{Mmjxzh3#rA%L8ZFh`L_n=%TpEngl%jao^Pw!Ufl4@NsX%?n(;B?it zEmM}}%ZlmxCX35FVZ1++UIPxAW1qUCtNSnx`w<*La2o>r;F0}js8YT}yV>h^^aQ#P z-N}4+4wFGPdgpx|Pa)!S$QLxO+C^K}z<*pLy}@3%^Z9O!6Z#Vb+zUSXGaPd-@Jc$w z^zjZdu<__P5$pB;+F3`J!HbegFG`VwW@1l1ZEYCGfAx9o5n9a`1tZ? M;cG6&oaxU00!|H0ng9R* delta 4968 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 float(order_min_fill_time+BT_DELAYS.limit_order_offset) and i[1] <= o.limit_price: + + #TODO pridat pokud je EXECUTION_DEBUG zalogování okolnich tradu (5 z kazde strany) od toho, který triggeroval plnění + #TODO pridat jako dalsi nastavovaci atribut pocet tradu po ktere musi byt cena zde (aby to nevyplnil knot high) + + #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: + fill_condition = fast_fill_condition + elif FILL_CONDITION_BUY_LIMIT == FillCondition.SLOW: + fill_condition = slow_fill_condition + else: + print("unknow fill condition") + return -1 + + if float(i[0]) > float(order_min_fill_time+BT_DELAYS.limit_order_offset) and fill_condition: #(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: + #TODO loguru + print("FILL SURR TRADES: before",work_range[index-FILL_LOG_SURROUNDING_TRADES:index]) + print("FILL SURR TRADES: after",work_range[index+1:index+FILL_LOG_SURROUNDING_TRADES+1]) break else: - for i in work_range: + for index, i in enumerate(work_range): #print(i) - if float(i[0]) > float(order_min_fill_time+BT_DELAYS.limit_order_offset) and i[1] >= o.limit_price: + #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: + fill_condition = fast_fill_condition + elif FILL_CONDITION_SELL_LIMIT == FillCondition.SLOW: + fill_condition = slow_fill_condition + else: + print("unknown fill condition") + return -1 + + if float(i[0]) > float(order_min_fill_time+BT_DELAYS.limit_order_offset) and fill_condition: #(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: + #TODO loguru + print("FILL SELL SURR TRADES: before",work_range[index-FILL_LOG_SURROUNDING_TRADES:index]) + print("FILL SELL SURR TRADES: after",work_range[index+1:index+FILL_LOG_SURROUNDING_TRADES+1]) break elif o.order_type == OrderType.MARKET: @@ -410,9 +446,9 @@ class Backtester: reserved = 0 #with lock: for o in self.open_orders: - if o.qty == OrderSide.SELL and o.symbol == symbol: + if o.side == OrderSide.SELL and o.symbol == symbol and o.canceled_at is None: reserved += o.qty - #print("blokovano v open orders pro sell: ", reserved) + print("blokovano v open orders pro sell: ", reserved) if int(self.account[symbol][0]) - reserved - int(size) < 0: print("not enough shares having",self.account[symbol][0],"reserved",reserved,"available",int(self.account[symbol][0]) - reserved,"selling",size) @@ -423,10 +459,10 @@ class Backtester: reserved = 0 #with lock: for o in self.open_orders: - if o.qty == OrderSide.BUY: + if o.side == OrderSide.BUY and o.canceled_at is None: cena = o.limit_price if o.limit_price else self.get_last_price(time, o.symbol) reserved += o.qty * cena - #print("blokovano v open orders: ", reserved) + print("blokovano v open orders: ", reserved) cena = price if price else self.get_last_price(time, self.symbol) if (self.cash - reserved - float(int(size)*float(cena))) < 0: @@ -441,6 +477,7 @@ class Backtester: status = OrderStatus.ACCEPTED, side=side, qty=int(size), + filled_qty=0, limit_price=(float(price) if price else None)) self.open_orders.append(order) diff --git a/v2realbot/config.py b/v2realbot/config.py index 6f07067..c84fbb7 100644 --- a/v2realbot/config.py +++ b/v2realbot/config.py @@ -1,7 +1,20 @@ from alpaca.data.enums import DataFeed -from v2realbot.enums.enums import Mode, Account +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() +#0 - optimistic, every knot high will fill the order +#N - N consecutive trades required +#not impl.yet +FILL_CONS_TRADES_REQUIRED = 0 +#during trade execution logs X-surrounding trades of the one that triggers the fill +FILL_LOG_SURROUNDING_TRADES = 10 +#fill condition for limit order +# 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 #no print in console QUIET_MODE = False #backend counter of api requests diff --git a/v2realbot/controller/services.py b/v2realbot/controller/services.py index 1ebc057..0b26b50 100644 --- a/v2realbot/controller/services.py +++ b/v2realbot/controller/services.py @@ -218,9 +218,16 @@ def is_stratin_running(id: UUID): return False def save_history(id: UUID, st: object, runner: Runner, reason: str = None): + + #zkousime precist profit z objektu + try: + profit = st.state.profit + 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:XX" + 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(profit)+ "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 05334ee8c3165b35560493f83f638f0cdee02299..4d9c1dbacfe6bf8f743bd101031e9d1a2686a294 100644 GIT binary patch delta 606 zcmYLGO=}ZD7~bj5q-o4p>3| zya-a};>rKuuMp|QtAhRq5j=SEokf~~=VjiH=Xu_pJ#7414$~m0d2qfQ5BN`V6t>Z; zqf5!TyB-gCcAt#bqv2_40F#!Wq60)57J{h&-3- znYmHcUGM3{A)7dT4&;52 z!_a1?CC{$VL@3Cdpb>H0I~m^HxV#>c$eYv_QS{aJvrNK!8=6&Q-x6VFv688(k;78I`%7Bv>*I&UALj9 z&%3Z@ulXy@4qR6ObCM6F4v^Y*gx^MPp7~q-M+^^Kv_EibbsdUpfZy)lluj5UpshPE zMD0~_|8z+tJN=y@P`B^x4VisMRvKMkYy$KJ7rOtK`$NicdtB-EHlT4GFyDxPw5vYo zonlz1BGC(wG22|c7`gqm+ebTPy#XK9?0&D_Oj2IN;x>Y!agS2>A{3%1h?b&Cv~;HS E55UQdkN^Mx delta 295 zcmew;*uu}3&&$ij00fn@^-|8TOyrYc%$um4%a+0$%%I7)aosPb$xN)lljpK zY|kMosQ{D`1>(;jE5X`WSQvpC6@VILn2O{lPi6BK1?y)Ga13w-n&9IZ=6Z|CDFmdQ zUlpheBwM5cB2+<|CY!Q79OHRw7;?y2d4+Z(w3r8e`kT|lOIdJ7K;C;sqMS!LK?A!O=y!V|qBR^dG zVLcaQvl&LeKOS$1!pe8KhbI3fdThqYb#ltH(bwti63jU3H(HIbY1cZk;ka@m`ZN6# zUyr`e?DKQug_$fL{>&Nsf)BXILhflz?I1g~^`<5T*$H}#1$L-~$pQ0Ho;l)Vk$=R= zs}FR+Df6_7rG+MRkvP&g8)y{M2Ko{^OdytEUS^P3V;ZYvrnyEq6Aovo7?l#qkv8IG zCQ@ZaZg|lw^CS|^K-h?*=&>y2%X&G=GLKT!bg~UdzdLP`7MXu!%^c~Rg?TYM;*`z2 z!tnmw1NMQ2{A(f%VlQRFU66TcvRnwbCzCgp2 zSE?=kZI#7vl2)oM2|f*1@V>wNfbGzdD@-*=d1+A)b0j6}oxp^YMeQeRyr;zcQ35UY z)Ke{9lXR}Ezj4iN*)7*<+fCmVJ$hTaH?CjW**|T){?6rH%iE?{*SA-#_w9b0GTU}L zuspjNSTFRSovzyKhO$o)%OR{<`&$>Spd;3&0g% zhY;(ZhCO)(pKk%1z*XQi;5u-g5F0Y+wuO8ZjtjsgU>Dc}-UPOQG_Vb*3xAHRc-FV0 zU-B=OFVaWVkf#uR9{3RWD5?}*DMN&IXUUl5i<-#`Ji$$^z~75LE__=?vskZpdrDwz zkX7@gh*suKa({ev?jFDSHYzFkN(uzTX3PG(6Z9L7+D&XYx4Z3TY}Wn2X;O(eQMcuR ztYhVq?R-L?)x<>O%Lp~13&mvv?(Vo&{FQSrI$P=_n~3?*qf&LKrt%Wj6(`&OA2G6p zd^OcJtQ3Ix#kpHro>cXDLe-Y zHNG4lE*jcUjY!E*XN1DB?z`?tDAvPP zC)S&8Pf8^JtFs{AJ$eqFA!v8Zh*$33P&dkSY~Q!*zAJNBX8>w$C0HkcJa7|mf!hQ+ fvmo##PGfRo)p$hoTV<24j4R6@8VL(uU=fMn1H^y<5)*@|rBkK1x3mnGD5i*{ zYc`Gx<3`XWiH|gH+_-Sz#)Op%Z~O<`8MnG{zM)kY+N8gp`Q|+5^uyrpK)4(V1&RFZ zJs)M!-q+z>i>Aa|%kvFLkq?R|fw4GDFXR+T1-F>ZRCpnm=cmQ@z(+bD-Ua7qy58Or zq8raBA)B;HZQ@c}D{3pDhOHMhJ|%5Ke$95Wu2qTcv;9!yNv~>Ey_2jPPz_>RRbzl? zBx5PB0HbcuZK)bet7$cwAWTmXr67mZRNY{8Ll&-4Bx{zEBDGuXP>nKU%TI|sp*6I_ z8_7-P`^(F}rBmXDnN_3Go7ipJksUIx+RgY8k%=-g+suOz?>BNDC~6yg&yBGFgqo(( z1plAL4XXxJQacKNhJrr3JrnBitoo)RQ}vtS5o&U|F(RI}O>7+G7qRaMa0wWf@bqPOji12r3~&XQ z0)~OJ5}wJ+t4oXzK^Orp0Moz>a2YrU1b|UM{k784@>-qjio3A7CY(rLVoWM2llQ{q zC@>G)5HBOAqW#j;9(0!x# z4%NNt1ob_ul)YOi-z((!u-J}uAI`$(Pv3cYOd0!qoW#|l_!8?fAurc|#6DA65TD`| zpN+esnCwWU)%eE{7u%onA7!}%fAw-DSbktyyy!@#Rc$;czXjkS_!3YC&|dRh)H3#) z!qt$ViI|C?&3ZCnY7sT5s-a$bO!Oy{$5s0C@W);}UoN|p%R6d+d_gLWVLja~RXn|z zU*pRvZ%*Dl5)YGNMy=Y)WgREG;N*E2xlBOK8Hd#av;o%v2HckLjD>R9;dz`V0X1Sy U-02#oN9u37(v+@<0dLl%3y*ydgGZH$bplN}Wu zn0S~cH!DUn_HDkexQ~%>;^ukEI*g19H=kAks#v`_NNqMFqy6T0>c*^$hbJrP&SCVM zykFN^0%#6P4ND5M4MPcQ4NEg4BSQ*9FoPz`WDY$e*&-#N?V4;w^MF*5A&6KCBK$yv p(qvyfYoTw93=G9QKt2bf5Tg(i4kxUMx{2}=!2 zGb1BI3PUi1Ci7$|JtJXF)}nbp%Zdy^#8MF9H#t+!THrGy14A*$9UP28j6zI2leg&= OGH&0jp}&WTQ3(L(@-EN- diff --git a/v2realbot/strategy/base.py b/v2realbot/strategy/base.py index 499483e..534e8ae 100644 --- a/v2realbot/strategy/base.py +++ b/v2realbot/strategy/base.py @@ -334,6 +334,7 @@ class Strategy: ##kroky po iteraci def after_iteration(self, item): + #DAT DO VNORENE FUNKCE ##check if real time chart is requested ##posilame dict s objekty: bars, trades podle cbaru, a dale indicators naplnene time a pripadnymi identifikatory (EMA) if self.rtqueue is not None: @@ -389,7 +390,9 @@ class Strategy: #cleaning iterlog lsit #TODO pridat cistku i mimo RT blok self.state.iter_log_list = [] - + else: + #mazeme logy pokud neni na ws pozadovano + self.state.iter_log_list = [] # inicializace poplatna typu strategie (např. u LIMITu dotažení existující limitky) def strat_init(self): @@ -502,4 +505,6 @@ class StrategyState: else: row = dict(time=self.time, event=e, message=msg, details=kwargs) self.iter_log_list.append(row) + row["name"] = self.name print(row) + #TBD mozna odsud to posilat do nejakeho struct logger jako napr. structlog