From 6d90b41cd3b76825a94b8161be61894d08af0472 Mon Sep 17 00:00:00 2001 From: David Brazda Date: Thu, 1 Jun 2023 13:18:35 +0200 Subject: [PATCH] cbar and buysignal refactor --- testy/buyconditiontest.py | 54 ++ v2realbot/ENTRY_Vykladaci_RSI_MYSELL.py | 481 +++++++++--------- v2realbot/__pycache__/config.cpython-310.pyc | Bin 2847 -> 2847 bytes .../__pycache__/aggregator.cpython-310.pyc | Bin 6953 -> 6953 bytes .../trade_offline_streamer.cpython-310.pyc | Bin 4913 -> 5007 bytes v2realbot/loader/aggregator.py | 3 + v2realbot/loader/trade_offline_streamer.py | 10 +- v2realbot/static/js/archivechart.js | 48 +- v2realbot/static/js/livewebsocket.js | 16 +- ...tegyOrderLimitVykladaciNormalizedMYSELL.py | 3 + .../strategy/__pycache__/base.cpython-310.pyc | Bin 14184 -> 14184 bytes v2realbot/strategy/base.py | 16 +- .../utils/__pycache__/utils.cpython-310.pyc | Bin 9396 -> 10166 bytes v2realbot/utils/utils.py | 41 ++ 14 files changed, 412 insertions(+), 260 deletions(-) create mode 100644 testy/buyconditiontest.py diff --git a/testy/buyconditiontest.py b/testy/buyconditiontest.py new file mode 100644 index 0000000..0df6344 --- /dev/null +++ b/testy/buyconditiontest.py @@ -0,0 +1,54 @@ +def buy_conditions_met(): + + buy_cond = dict(AND=dict(), OR=dict()) + ##group eval rules. 1. single 2. AND 3. ORS + #cond groups ["AND"] + #cond groups ["OR"] + #no cond group - takes first + #TEST BUY SIGNALu z cbartick_price - 3klesave za sebou + #buy_cond['tick_price_falling_trend'] = isfalling(state.cbar_indicators.tick_price,state.vars.Trend) + buy_cond["AND"]["1and"] = True + buy_cond["AND"]["2and"] = False + buy_cond["OR"]["3or"] = False + buy_cond["OR"]["4or"] = False + buy_cond["5single"] = False + buy_cond["5siddngle"] = False + + return eval_cond_dict(buy_cond) + +def eval_cond_dict(buy_cond: dict): + """ + group eval rules. 1. single 2. AND 3. ORS + """ + msg = "" + #eval single cond + for klic in buy_cond: + if klic in ["AND","OR"]: continue + else: + if buy_cond[klic]: + print(f"BUY SIGNAL {klic}") + return True + + ##check AND group + if 'AND' in buy_cond.keys(): + for key in buy_cond["AND"]: + + if buy_cond["AND"][key]: + ret = True + msg += key + " AND " + else: + ret = False + break + if ret: + print(f"BUY SIGNAL {msg}") + return True + #eval OR groups + if "OR" in buy_cond.keys(): + for key in buy_cond["OR"]: + if buy_cond["OR"][key]: + print(f"BUY SIGNAL OR {key}") + return True + + return False + +buy_conditions_met() \ No newline at end of file diff --git a/v2realbot/ENTRY_Vykladaci_RSI_MYSELL.py b/v2realbot/ENTRY_Vykladaci_RSI_MYSELL.py index cd5d127..10ca9ef 100644 --- a/v2realbot/ENTRY_Vykladaci_RSI_MYSELL.py +++ b/v2realbot/ENTRY_Vykladaci_RSI_MYSELL.py @@ -5,7 +5,7 @@ from v2realbot.strategy.StrategyOrderLimitVykladaciNormalizedMYSELL import Strat from v2realbot.enums.enums import RecordType, StartBarAlign, Mode, Account, OrderSide, OrderType from v2realbot.indicators.indicators import ema from v2realbot.indicators.oscillators import rsi -from v2realbot.utils.utils import ltp, isrising, isfalling,trunc,AttributeDict, zoneNY, price2dec, print, safe_get, get_tick, round2five +from v2realbot.utils.utils import ltp, isrising, isfalling,trunc,AttributeDict, zoneNY, price2dec, print, safe_get, get_tick, round2five, is_open_rush, is_close_rush, eval_cond_dict from datetime import datetime #from icecream import install, ic #from rich import print @@ -14,6 +14,7 @@ from msgpack import packb, unpackb import asyncio import os from traceback import format_exc +import inspect print(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) """" @@ -101,12 +102,12 @@ def next(data, state: StrategyState): max_pozic = int(state.vars.maxpozic) def_mode_from = safe_get(state.vars, "def_mode_from",max_pozic/2) if akt_pozic >= int(def_mode_from): - state.ilog(e=f"DEFENSIVE mode ACTIVE {state.vars.def_mode_from=}", msg=state.positions) + #state.ilog(e=f"DEFENSIVE mode ACTIVE {state.vars.def_mode_from=}", msg=state.positions) return True else: - state.ilog(e=f"STANDARD mode ACTIVE {state.vars.def_mode_from=}", msg=state.positions) + #state.ilog(e=f"STANDARD mode ACTIVE {state.vars.def_mode_from=}", msg=state.positions) return False - + def get_limitka_price(): def_profit = safe_get(state.vars, "def_profit",state.vars.profit) cena = float(state.avgp) @@ -115,7 +116,7 @@ def next(data, state: StrategyState): return price2dec(cena+get_tick(cena,float(def_profit)),3) else: return price2dec(cena+get_tick(cena,float(state.vars.profit)),3) - + def consolidation(): ##CONSOLIDATION PART - moved here, musí být před nákupem, jinak to dělalo nepořádek v pendingbuys #docasne zkusime konzolidovat i kdyz neni vylozeno (aby se srovnala limitka ve vsech situacich) @@ -160,7 +161,6 @@ def next(data, state: StrategyState): else: state.ilog(e="No time for consolidation", msg=data["index"]) print("no time for consolidation", data["index"]) - #mozna presunout o level vys def vyloz(): ##prvni se vyklada na aktualni cenu, další jdou podle krivky, nula v krivce zvyšuje množství pro následující iteraci @@ -226,6 +226,7 @@ def next(data, state: StrategyState): last_price = price state.vars.blockbuy = 1 state.vars.jevylozeno = 1 + state.vars.last_buysignal_index = data['index'] def eval_sell(): """" @@ -241,243 +242,117 @@ def next(data, state: StrategyState): goal_price = get_limitka_price() state.ilog(e=f"Goal price {goal_price}") if curr_price>=goal_price: - state.interface.sell(size=state.positions) - state.vars.sell_in_progress = True - state.ilog(e=f"market SELL was sent {curr_price=}", positions=state.positions, avgp=state.avgp, sellinprogress=state.vars.sell_in_progress) - #na urovni CBARU mame zajisteno, ze update prichazi pri zmene ceny - #v kazde iteraci testujeme sell - #pri potvrzenem baru muzeme provest kroky per hlavni BAR - #potvrzeni neprinasi nikdy zadna nova data, ale pouze potvrzeni. - state.ilog(e="-----") - eval_sell() + #TODO cekat az slope prestane intenzivn erust, necekat az na klesani + #TODO mozna cekat na nejaky signal RSI + #TODO pripadne pokud dosahne TGTBB prodat ihned - conf_bar = data['confirmed'] - if conf_bar == 1: - #delej veci per standardni bar - state.ilog(e="BAR potvrzeny") - else: - pass - #delej veci tick-based + #OPTIMALIZACE pri stoupajícím angle + if sell_protection_enabled() is False: + state.interface.sell(size=state.positions) + state.vars.sell_in_progress = True + state.ilog(e=f"market SELL was sent {curr_price=}", positions=state.positions, avgp=state.avgp, sellinprogress=state.vars.sell_in_progress) - #CBAR INDICATOR pro tick price a deltu VOLUME - tick_price = round2five(data['close']) - tick_delta_volume = data['volume'] - state.vars.last_tick_volume - - if conf_bar == 0: + def populate_ema_indicator(): + #BAR EMA INDICATOR - + #plnime MAcko - nyni posilame jen N poslednich hodnot + #zaroven osetrujeme pripady, kdy je malo dat a ukladame nulu try: - #pokud v potvrzovacím baru nebyly zmeny, nechavam puvodni hodnoty - # if tick_delta_volume == 0: - # state.indicators.tick_price[-1] = state.indicators.tick_price[-2] - # state.indicators.tick_volume[-1] = state.indicators.tick_volume[-2] - # else: + ma = int(state.vars.MA) + #poslednich ma hodnot + source = state.bars.close[-ma:] #state.bars.vwap + ema_value = ema(source, ma) - #docasne dame pryc volume deltu a davame absolutni cislo - state.cbar_indicators.tick_price[-1] = tick_price - state.cbar_indicators.tick_volume[-1] = tick_delta_volume - except: - pass + ##pokus MACKO zakrouhlit na tri desetina a petku + state.indicators.ema[-1]=round2five(ema_value[-1]) + ##state.indicators.ema[-1]=trunc(ema_value[-1],3) + #state.ilog(e=f"EMA {state.indicators.ema[-1]}", ema_last=state.indicators.ema[-6:]) + except Exception as e: + state.ilog(e="EMA nechavame 0", message=str(e)+format_exc()) + #state.indicators.ema[-1]=(0) + #evaluate buy signal + #consolidation - state.ilog(e=f"TICK PRICE {tick_price} VOLUME {tick_delta_volume} {conf_bar=}", last_price=state.vars.last_tick_price, last_volume=state.vars.last_tick_volume) + def populate_slope_indicator(): + #SLOPE INDICATOR + #úhel stoupání a klesání vyjádřený mezi -1 až 1 + #pravý bod přímky je aktuální cena, levý je průměr X(lookback offset) starších hodnot od slope_lookback. + #obsahuje statický indikátor (angle) pro vizualizaci + try: + slope = 99 + slope_lookback = int(state.vars.slope_lookback) + minimum_slope = float(state.vars.minimum_slope) + lookback_offset = int(state.vars.lookback_offset) + + if len(state.bars.close) > (slope_lookback + lookback_offset): + array_od = slope_lookback + lookback_offset + array_do = slope_lookback + lookbackprice_array = state.bars.vwap[-array_od:-array_do] + #obycejný prumer hodnot + lookbackprice = round(sum(lookbackprice_array)/lookback_offset,3) + + #výpočet úhlu - a jeho normalizace + slope = ((state.bars.close[-1] - lookbackprice)/lookbackprice)*100 + slope = round(slope, 4) + state.indicators.slope[-1]=slope - state.vars.last_tick_price = tick_price - state.vars.last_tick_volume = data['volume'] - #pri potvrzem CBARu nulujeme counter volume - if conf_bar == 1: - state.vars.last_tick_volume = 0 - state.vars.next_new = 1 - - - - #TEST BUY SIGNALu z cbartick_price - 3klesave za sebou - buy_tp = isfalling(state.cbar_indicators.tick_price,state.vars.Trend) - state.ilog(e=f"TICK SIGNAL ISFALLING {buy_tp}", last_tp=state.cbar_indicators.tick_price[-6:], trend=state.vars.Trend) - - #IVWAP - PRUBEZNY persistovany VWAP - # try: - # #naplneni cbar tick indikatoru s prubeznou vwap - # state.cbar_indicators.ivwap[-1]=data['vwap'] - # except: - # pass - - - # if data['confirmed'] == 0: - # state.ilog(e="CBAR unconfirmed - returned", msg=str(data)) - # #TBD zde muzeme i nakupovat - # #indikatory pocitat, ale neukladat do historie - # return 0 - # #confirmed - # else: - # state.ilog(e="CBAR confirmed - continue", msg=str(data)) - - #BAR EMA INDICATOR - - #plnime MAcko - nyni posilame jen N poslednich hodnot - #zaroven osetrujeme pripady, kdy je malo dat a ukladame nulu - try: - ma = int(state.vars.MA) - #poslednich ma hodnot - source = state.bars.close[-ma:] #state.bars.vwap - ema_value = ema(source, ma) - state.indicators.ema[-1]=trunc(ema_value[-1],3) - state.ilog(e=f"EMA {state.indicators.ema[-1]}", ema_last=state.indicators.ema[-6:]) - except Exception as e: - state.ilog(e="EMA nechavame 0", message=str(e)+format_exc()) - #state.indicators.ema[-1]=(0) - - #CBAR RSI14 INDICATOR - try: - ##mame v atributech nastaveni? - rsi_dont_buy_above = safe_get(state.vars, "rsi_dont_buy_above",50) - rsi_buy_signal_conf = safe_get(state.vars, "rsi_buy_signal_below",40) - rsi_buy_signal = False - rsi_dont_buy = False - rsi_length = 14 - - #source = state.bars.close #[-rsi_length:] #state.bars.vwap - #jako zdroj je prubezna CBAR tickprice - source = state.cbar_indicators.tick_price - rsi_res = rsi(source, rsi_length) - rsi_value = trunc(rsi_res[-1],3) - state.cbar_indicators.RSI14[-1]=rsi_value - rsi_dont_buy = rsi_value > rsi_dont_buy_above - rsi_buy_signal = rsi_value < rsi_buy_signal_conf - state.ilog(e=f"CBARRSI{rsi_value} {rsi_length=} {rsi_dont_buy=} {rsi_buy_signal=}", rsi_indicator=state.cbar_indicators.RSI14[-5:]) - except Exception as e: - state.ilog(e=f"CBARRSI {rsi_length=} nechavame 0", message=str(e)+format_exc()) - #state.indicators.RSI14.append(0) - - - #SLOPE INDICATOR - #úhel stoupání a klesání vyjádřený mezi -1 až 1 - #pravý bod přímky je aktuální cena, levý je průměr X(lookback offset) starších hodnot od slope_lookback. - #obsahuje statický indikátor (angle) pro vizualizaci - try: - slope = 99 - slope_lookback = int(state.vars.slope_lookback) - minimum_slope = float(state.vars.minimum_slope) - lookback_offset = int(state.vars.lookback_offset) - - if len(state.bars.close) > (slope_lookback + lookback_offset): - array_od = slope_lookback + lookback_offset - array_do = slope_lookback - lookbackprice_array = state.bars.vwap[-array_od:-array_do] - #obycejný prumer hodnot - lookbackprice = round(sum(lookbackprice_array)/lookback_offset,3) - - #výpočet úhlu - a jeho normalizace - slope = ((state.bars.close[-1] - lookbackprice)/lookbackprice)*100 - slope = round(slope, 4) - state.indicators.slope[-1]=slope - - #angle je ze slope - state.statinds.angle = dict(time=state.bars.time[-1], price=state.bars.close[-1], lookbacktime=state.bars.time[-slope_lookback], lookbackprice=lookbackprice, minimum_slope=minimum_slope) - - #slope MA vyrovna vykyvy ve slope, dále pracujeme se slopeMA - slope_MA_length = 5 - source = state.indicators.slope[-slope_MA_length:] - slopeMAseries = ema(source, slope_MA_length) #state.bars.vwap - slopeMA = slopeMAseries[-1] - state.indicators.slopeMA[-1]=slopeMA - - state.ilog(e=f"{slope=} {slopeMA=}", msg=f"{lookbackprice=}", lookbackoffset=lookback_offset, minimum_slope=minimum_slope, last_slopes=state.indicators.slope[-10:], last_slopesMA=state.indicators.slopeMA[-10:]) - - #dale pracujeme s timto MAckovanym slope - slope = slopeMA - else: - #pokud plnime historii musime ji plnit od zacatku, vsehcny idenitifkatory maji spolecny time - #kvuli spravnemu zobrazovani na gui - #state.indicators.slopeMA[-1]=0 - #state.indicators.slopeMA.append(0) - state.ilog(e="Slope - not enough data", slope_lookback=slope_lookback, slope=state.indicators.slope, slopeMA=state.indicators.slopeMA) - except Exception as e: - print("Exception in NEXT Slope Indicator section", str(e)) - state.ilog(e="EXCEPTION", msg="Exception in Slope Indicator section" + str(e) + format_exc()) - - print("is falling",isfalling(state.indicators.ema,state.vars.Trend)) - print("is rising",isrising(state.indicators.ema,state.vars.Trend)) - - consolidation() - - if int(state.positions) >= state.vars.maxpozic: - state.ilog(e="Max pos reached") - return 0 - - #tbd zakladni schema viz nize + - #pokracovat v buy signalu pro cbar - - - #trigger - #stavy - #ochrany - - get indikator vals - - generate triggers - set working states - rovne, prudce nahoru, prudce dolu + #angle je ze slope + state.statinds.angle = dict(time=state.bars.time[-1], price=state.bars.close[-1], lookbacktime=state.bars.time[-slope_lookback], lookbackprice=lookbackprice, minimum_slope=minimum_slope) + #slope MA vyrovna vykyvy ve slope, dále pracujeme se slopeMA + slope_MA_length = 5 + source = state.indicators.slope[-slope_MA_length:] + slopeMAseries = ema(source, slope_MA_length) #state.bars.vwap + slopeMA = slopeMAseries[-1] + state.indicators.slopeMA[-1]=slopeMA - process triggers + state.ilog(e=f"{slope=} {slopeMA=}", msg=f"{lookbackprice=}", lookbackoffset=lookback_offset, minimum_slope=minimum_slope, last_slopes=state.indicators.slope[-10:], last_slopesMA=state.indicators.slopeMA[-10:]) - buy_signal - buy protection (dont buy when) - sell signal - sell protection (dont buy when) + #dale pracujeme s timto MAckovanym slope + slope = slopeMA + else: + #pokud plnime historii musime ji plnit od zacatku, vsehcny idenitifkatory maji spolecny time + #kvuli spravnemu zobrazovani na gui + #state.indicators.slopeMA[-1]=0 + #state.indicators.slopeMA.append(0) + state.ilog(e="Slope - not enough data", slope_lookback=slope_lookback, slope=state.indicators.slope, slopeMA=state.indicators.slopeMA) + except Exception as e: + print("Exception in NEXT Slope Indicator section", str(e)) + state.ilog(e="EXCEPTION", msg="Exception in Slope Indicator section" + str(e) + format_exc()) + + def populate_rsi_indicator(): + #RSI14 INDICATOR + try: + rsi_buy_signal = False + rsi_dont_buy = False + rsi_length = 14 + source = state.bars.close #[-rsi_length:] #state.bars.vwap + rsi_res = rsi(source, rsi_length) + rsi_value = trunc(rsi_res[-1],3) + state.indicators.RSI14[-1]=rsi_value + #state.ilog(e=f"RSI {rsi_length=} {rsi_value=} {rsi_dont_buy=} {rsi_buy_signal=}", rsi_indicator=state.indicators.RSI14[-5:]) + except Exception as e: + state.ilog(e=f"RSI {rsi_length=} necháváme 0", message=str(e)+format_exc()) + #state.indicators.RSI14[-1]=0 + + def slope_too_low(): + return state.indicators.slopeMA[-1] < float(state.vars.minimum_slope) + def slope_too_high(): + return state.indicators.slopeMA[-1] > float(safe_get(state.vars, "bigwave_slope_above",0.20)) - - - - - #HLAVNI ITERACNI LOG JESTE PRED AKCI - obsahuje aktualni hodnoty vetsiny parametru - #TODO sem pridat aktualni hodnoty vsech indikatoru - lp = state.interface.get_last_price(symbol=state.symbol) - state.ilog(e="ENTRY", msg=f"LP:{lp} P:{state.positions}/{round(float(state.avgp),3)} profit:{round(float(state.profit),2)} Trades:{len(state.tradeList)} DEF:{str(is_defensive_mode())}", last_price=lp, data=data, stratvars=state.vars) - - #SLOPE ANGLE PROTECTIONs - #slope zachycuje rychle sestupy, pripadne zrusi nakupni objednavky - if slope < minimum_slope or rsi_dont_buy: # or slopeMA0: - print("CANCEL PENDINGBUYS") - #ic(state.vars.pendingbuys) - res = asyncio.run(state.cancel_pending_buys()) - #ic(state.vars.pendingbuys) - state.ilog(e="Rusime pendingbuyes", pb=state.vars.pendingbuys, res=res) - print("slope", slope) - print("min slope", minimum_slope) - - if state.vars.jevylozeno == 0: - print("Neni vylozeno, muzeme testovat nakup") - - #pokud je defenziva, buy triggeruje defenzivni def_trend - #TBD - - #NOVY BUY SIGNAL z RSI < 35 - #buy_signal = isfalling(state.indicators.ema,state.vars.Trend) - buy_signal = rsi_buy_signal - - if buy_signal and slope > minimum_slope and not rsi_dont_buy: - state.ilog(e="BUY SIGNAL") - vyloz() - - ## testuje aktualni cenu od nejvyssi visici limitky - ##toto spoustet jednou za X iterací - ted to jede pokazdé - #pokud to ujede o vic, rusime limitky - #TODO: zvazit jestli nechat i pri otevrenych pozicich, zatim nechavame - #TODO int(int(state.oa.poz)/int(state.variables.chunk)) > X - - #TODO spoustet 1x za X iteraci nebo cas - if state.vars.jevylozeno == 1 and len(state.vars.pendingbuys)>0: - #pokud mame vylozeno a cena je vetsi nez tick2reset - if len(state.vars.pendingbuys)>0: + if buy_protection_enabled(): + #state.ilog(e="PENDINGBUYS reset", message=inspect.currentframe().f_code.co_name) + res = asyncio.run(state.cancel_pending_buys()) + state.ilog(e="CANCEL pendingbuyes", pb=state.vars.pendingbuys, res=res) + else: + #pokud mame vylozeno a cena je vetsi nez tick2reset maxprice = max(state.vars.pendingbuys.values()) - print("max cena v orderbuys", maxprice) if state.interface.get_last_price(state.symbol) > float(maxprice) + get_tick(maxprice, float(state.vars.ticks2reset)): - ##TODO toto nejak vymyslet - duplikovat? res = asyncio.run(state.cancel_pending_buys()) state.ilog(e=f"UJELO to. Rusime PB", msg=f"{state.vars.ticks2reset=}", pb=state.vars.pendingbuys) @@ -493,9 +368,143 @@ def next(data, state: StrategyState): if len(state.vars.pendingbuys) == 0: state.vars.blockbuy = 0 state.vars.jevylozeno = 0 - state.ilog(e="PB se vyklepaly nastavujeme: neni vylozeno", jevylozeno=state.vars.jevylozeno) + state.ilog(e="PB prazdne nastavujeme: neni vylozeno", jevylozeno=state.vars.jevylozeno) - print(10*"*","NEXT STOP",10*"*") + ##kdy nenakupovat - tzn. neprojdou nakupy a kdyz uz jsou tak se zrusi + def buy_protection_enabled(): + dont_buy_when = dict(AND=dict(), OR=dict()) + ##add conditions here + dont_buy_when['rsi_dont_buy'] = state.indicators.RSI14[-1] > safe_get(state.vars, "rsi_dont_buy_above",50) + dont_buy_when['slope_too_low'] = slope_too_low() + + result, cond_met = eval_cond_dict(dont_buy_when) + if result: + state.ilog(e=f"BUY_PROTECTION {cond_met}") + return result + + def sell_protection_enabled(): + dont_sell_when = dict(AND=dict(), OR=dict()) + ##add conditions here + + #IDENTIFIKOVAT MOMENTUM - pokud je momentum, tak prodávat později + + #pokud je slope too high, pak prodavame jakmile slopeMA zacne klesat, napr. 4MA (TODO 3) + + dont_sell_when['slope_too_high'] = slope_too_high() and not isfalling(state.indicators.slopeMA,4) + dont_sell_when['slopeMA_rising'] = isrising(state.indicators.slopeMA,2) + #dont_sell_when['rsi_dont_buy'] = state.indicators.RSI14[-1] > safe_get(state.vars, "rsi_dont_buy_above",50) + + result, conditions_met = eval_cond_dict(dont_sell_when) + if result: + state.ilog(e=f"SELL_PROTECTION {conditions_met} enabled") + return result + + #preconditions and conditions of BUY SIGNAL + def buy_conditions_met(): + #preconditions + dont_buy_when = dict(AND=dict(), OR=dict()) + dont_buy_when['bar_not_confirmed'] = (data['confirmed'] == 0) + #od posledniho vylozeni musi ubehnout N baru + dont_buy_when['last_buy_offset_too_soon'] = data['index'] < (state.vars.last_buysignal_index + safe_get(state.vars, "lastbuy_offset",3)) + dont_buy_when['blockbuy_active'] = (state.vars.blockbuy == 1) + dont_buy_when['jevylozeno_active'] = (state.vars.jevylozeno == 1) + dont_buy_when['buy_protection_enabled'] = buy_protection_enabled() + dont_buy_when['open_rush'] = is_open_rush(datetime.fromtimestamp(data['updated']).astimezone(zoneNY), safe_get(state.vars, "open_rush",0)) + dont_buy_when['close_rush'] = is_close_rush(datetime.fromtimestamp(data['updated']).astimezone(zoneNY), safe_get(state.vars, "close_rush",0)) + dont_buy_when['rsi_is_zero'] = (state.indicators.RSI14[-1] == 0) + + #testing preconditions + result, cond_met = eval_cond_dict(dont_buy_when) + if result: + state.ilog(e=f"BUY precondition not met {cond_met}") + return False + + #conditions - bud samostatne nebo v groupe - ty musi platit dohromady + buy_cond = dict(AND=dict(), OR=dict()) + ##add buy conditions here + #cond groups ["AND"] + #cond groups ["OR"] + #no cond group - takes first + #TEST BUY SIGNALu z cbartick_price - 3klesave za sebou + #buy_cond['tick_price_falling_trend'] = isfalling(state.cbar_indicators.tick_price,state.vars.Trend) + buy_cond["AND"]["rsi_buy_signal_below"] = state.indicators.RSI14[-1] < safe_get(state.vars, "rsi_buy_signal_below",40) + buy_cond["AND"]["ema_trend_is_falling"] = isfalling(state.indicators.ema,state.vars.Trend) + + result, conditions_met = eval_cond_dict(buy_cond) + if result: + state.ilog(e=f"BUY SIGNAL {conditions_met}") + return result + + def eval_buy(): + if buy_conditions_met(): + vyloz() + + def populate_cbar_tick_price_indicator(): + try: + #pokud v potvrzovacím baru nebyly zmeny, nechavam puvodni hodnoty + # if tick_delta_volume == 0: + # state.indicators.tick_price[-1] = state.indicators.tick_price[-2] + # state.indicators.tick_volume[-1] = state.indicators.tick_volume[-2] + # else: + + tick_price = round2five(data['close']) + tick_delta_volume = data['volume'] - state.vars.last_tick_volume + + #docasne dame pryc volume deltu a davame absolutni cislo + state.cbar_indicators.tick_price[-1] = tick_price + state.cbar_indicators.tick_volume[-1] = tick_delta_volume + except: + pass + + state.ilog(e=f"TICK PRICE {tick_price} VOLUME {tick_delta_volume} {conf_bar=}", prev_price=state.vars.last_tick_price, prev_volume=state.vars.last_tick_volume) + + state.vars.last_tick_price = tick_price + state.vars.last_tick_volume = data['volume'] + + def get_last_ind_vals(): + last_ind_vals = {} + #print(state.indicators.items()) + for key in state.indicators: + if key != 'time': + last_ind_vals[key] = state.indicators[key][-5:] + + for key in state.cbar_indicators: + if key != 'time': + last_ind_vals[key] = state.cbar_indicators[key][-5:] + return last_ind_vals + + conf_bar = data['confirmed'] + state.ilog(e=f"---{data['index']}-{conf_bar}--") + + #kroky pro CONFIRMED BAR only + if conf_bar == 1: + #logika pouze pro potvrzeny bar + state.ilog(e="BAR potvrzeny") + + + #pri potvrzem CBARu nulujeme counter volume pro tick based indicator + state.vars.last_tick_volume = 0 + state.vars.next_new = 1 + + #kroky pro CONTINOUS TICKS only + else: + #CBAR INDICATOR pro tick price a deltu VOLUME + populate_cbar_tick_price_indicator() + + #SPOLECNA LOGIKA - bar indikatory muzeme populovat kazdy tick (dobre pro RT GUI), ale uklada se stejne az pri confirmu + populate_ema_indicator() + populate_slope_indicator() + populate_rsi_indicator() + eval_sell() + consolidation() + + #HLAVNI ITERACNI LOG JESTE PRED AKCI - obsahuje aktualni hodnoty vetsiny parametru + lp = state.interface.get_last_price(symbol=state.symbol) + state.ilog(e="ENTRY", msg=f"LP:{lp} P:{state.positions}/{round(float(state.avgp),3)} profit:{round(float(state.profit),2)} Trades:{len(state.tradeList)} DEF:{str(is_defensive_mode())}", last_price=lp, data=data, stratvars=state.vars) + state.ilog(e="Indikatory", msg=str(get_last_ind_vals())) + + eval_buy() + pendingbuys_optimalization() def init(state: StrategyState): #place to declare new vars @@ -505,25 +514,19 @@ def init(state: StrategyState): state.vars.last_tick_price = 0 state.vars.last_tick_volume = 0 state.vars.next_new = 0 + state.vars.last_buysignal_index = 0 #state.cbar_indicators['ivwap'] = [] state.cbar_indicators['tick_price'] = [] state.cbar_indicators['tick_volume'] = [] state.indicators['ema'] = [] state.indicators['slope'] = [] state.indicators['slopeMA'] = [] - state.cbar_indicators['RSI14'] = [] + state.indicators['RSI14'] = [] #static indicators - those not series based - state.statinds['angle'] = dict(minimum_slope=state.vars["minimum_slope"]) + state.statinds['angle'] = dict(minimum_slope=state.vars["minimum_slope"], maximum_slope=safe_get(state.vars, "bigwave_slope_above",0.20)) state.vars["ticks2reset_backup"] = state.vars.ticks2reset def main(): - # try: - # strat_settings = tomli.loads("]] this is invalid TOML [[") - # except tomli.TOMLDecodeError: - # print("Yep, definitely not valid.") - - #strat_settings = dict_replace_value(strat_settings, "None", None) - name = os.path.basename(__file__) se = Event() pe = Event() diff --git a/v2realbot/__pycache__/config.cpython-310.pyc b/v2realbot/__pycache__/config.cpython-310.pyc index 25a29de25fd011267eb734888e8a389a50d67e7a..8771c3690f366365277fdad0f66e9d718384301f 100644 GIT binary patch delta 195 zcmW-aI}ULj+5@2NDS-5I_UafF)XRN*$Cz4V>6uq?u%^ zyvo%@DPNeC+Y8?hwZA&>*+f7WZS9;DI)8?A5S;{DFNs*Y^llP~C)R>KgS%jGYalh& zrZT3CW$b8+p|+1UBgS_dT_(txqF{y|yXZ5=fCWk|&qIvZ!qX#fBK diff --git a/v2realbot/loader/__pycache__/aggregator.cpython-310.pyc b/v2realbot/loader/__pycache__/aggregator.cpython-310.pyc index 4380db845c0a2aded233ddac8b1eb7c2128b86be..fe66ce9d987b2666fa5b41e07139bcae078dc480 100644 GIT binary patch delta 51 zcmZ2!w$h9@pO=@50SNXlFHNc1$XhJN$g;Un>>MLw<>mkhX-3Az$vKis7)v(`N{KTv G$^rm;=MDA% delta 51 zcmZ2!w$h9@pO=@50SJBs=cm|gcwcX2N#tPYy=ezhF$}qhZP3# z=7TwkF!K{Mq8ITb;=vyv!L#65aF4q+Sy&sosPC(@9-8HNUQeoj>Q-kEV3 z#XIjd`hdCGaqI$r3E(NIpRiNrB7)Q=V0qIqM7PwWkp>qXlN8O;bQuCqJJvs*R0~c* z!n!VOncyvvYj3Y+Opdw;anu}&8QoBGs4M-E2+J^4 qX;DmOs?ACa)m`**aX+O;X;7EN%Ow-hlIB3+Z@_DD|4F`Qk{Sd$8d{YOYp|;^l&PpU^-2% z3!YI|c#AHaqd;ED(;;7Hm1y!mCCbMTBPSwsKK$0oC)eDf`5Ex7)Gy9LC(X}ri4qrF z5HB(O9M45nR->f=V_X3W%kX>eBb$oqG58JxIualPccST7XaXZ0Wf(wPq8JbqJKInl zOS;*0$$UrgFMVWv-0Wj3u}mW2MmT6U@FrZdkLoJXB_iu`O;IEViCmOTr68+FuE?A8 p>5Lapl~h!57%xg;Q!j;Ib|ZTzGCd`2TghDR1C@hx-U}N8J3stxUi|<7 diff --git a/v2realbot/loader/aggregator.py b/v2realbot/loader/aggregator.py index c15dbf9..b1ed749 100644 --- a/v2realbot/loader/aggregator.py +++ b/v2realbot/loader/aggregator.py @@ -363,6 +363,9 @@ class TradeAggregator2Queue(TradeAggregator): copy = obj.copy() else: copy = obj + + ##populate secondary resolution if required + self.queue.put(copy) res = [] #print("po insertu",res) diff --git a/v2realbot/loader/trade_offline_streamer.py b/v2realbot/loader/trade_offline_streamer.py index 4505664..b980a6b 100644 --- a/v2realbot/loader/trade_offline_streamer.py +++ b/v2realbot/loader/trade_offline_streamer.py @@ -157,14 +157,15 @@ class Trade_Offline_Streamer(Thread): wait_for_q = False else: wait_for_q = True - #ic(wait_for_q) + print(f"{wait_for_q=}") # v tradesResponse je dict = Trades identifikovane symbolem for symbol in tradesResponse: #print(tradesResponse[symbol]) celkem = len(tradesResponse[symbol]) + #ic(symbol, celkem) - #print("POCET: ", celkem) + print("POCET: ", celkem) cnt = 1 @@ -177,7 +178,8 @@ class Trade_Offline_Streamer(Thread): if self.time_from < to_datetime(t['t']) < self.time_to: #poustime dal, jinak ne if wait_for_q: - if 'Q' not in t['c']: continue + #cekame na Q nebo na O (nekterym dnum chybelo Q) + if ('Q' not in t['c']) and ('O' not in t['c']): continue else: #ic("Q found poustime dal") wait_for_q = False @@ -185,7 +187,7 @@ class Trade_Offline_Streamer(Thread): #homogenizace timestampu s online streamem t['t'] = Timestamp.from_unix(to_datetime(t['t']).timestamp()) - #print("PROGRESS ",cnt,"/",celkem) + print("PROGRESS ",cnt,"/",celkem) #print(t) #na rozdil od wwebsocketu zde nemame v zaznamu symbol ['S'] #vsem streamum na tomto symbolu posilame data - tbd mozna udelat i per stream vlakno diff --git a/v2realbot/static/js/archivechart.js b/v2realbot/static/js/archivechart.js index 39ee07c..ada4e48 100644 --- a/v2realbot/static/js/archivechart.js +++ b/v2realbot/static/js/archivechart.js @@ -321,6 +321,9 @@ function chart_archived_run(archRecord, data, oneMinuteBars) { //var last = null var last_time = 0 var time = 0 + + //tento algoritmus z duplicit dela posloupnosti a srovna i pripadne nekonzistence + //napr z .911 .911 .912 udela .911 .912 .913 value.forEach((element, index, array) => { item = {} //debug @@ -328,14 +331,15 @@ function chart_archived_run(archRecord, data, oneMinuteBars) { //if (indicators.time[index] !== undefined) { //{console.log("problem",key,last)} time = indicators.time[index] - if (time==last_time) { - //console.log(key, "problem v case - pousunuto o 0.001",time, last_time, element) - time += 0.000001 + if (last_time>=time) { + console.log(key, "problem v case - zarovnano",time, last_time, element) + + indicators.time[index] = indicators.time[index-1] + 0.000001 } - item["time"] = time + item["time"] = indicators.time[index] item["value"] = element - last_time = time + last_time = indicators.time[index] if ((element == null) || (indicators.time[index] == null)) { console.log("probelem u indikatoru",key, "nekonzistence", element, indicators.time[index]) @@ -352,6 +356,19 @@ function chart_archived_run(archRecord, data, oneMinuteBars) { // } }); + //SERADIT PRO JISTOTU + //items.sort(sorter) + + //FIND DUPLICITIES + // last_time = 0 + // items.forEach((element, index, array) => { + // if (last_time >= element.time) { + // console.log("je duplicita/nekonzistence v ", element.time, element.value) + // } + // last_time = element.time + // }) + + if (conf.embed) { if (conf.histogram) { @@ -392,10 +409,24 @@ function chart_archived_run(archRecord, data, oneMinuteBars) { lineWidth: 1, lineStyle: 2, // LineStyle.Dotted axisLabelVisible: true, - title: "max:", + title: "min:", }; const minSlopeLine = obj.series.createPriceLine(minSlopeLineOptopns); + + const maxSlopeLineOptopns = { + price: data.statinds.angle.maximum_slope, + color: '#b67de8', + lineWidth: 1, + lineStyle: 2, // LineStyle.Dotted + axisLabelVisible: true, + title: "max:", + }; + + const maxSlopeLine = obj.series.createPriceLine(maxSlopeLineOptopns); + + + } } @@ -410,7 +441,10 @@ function chart_archived_run(archRecord, data, oneMinuteBars) { priceLineVisible: false, }); - //console.log("problem tu",JSON.stringify(items)) + //DEBUG + // if (key == 'tick_price') { + // console.log("problem tu",JSON.stringify(items)) + // } //add data obj.series.setData(items) diff --git a/v2realbot/static/js/livewebsocket.js b/v2realbot/static/js/livewebsocket.js index 5edb610..91107fe 100644 --- a/v2realbot/static/js/livewebsocket.js +++ b/v2realbot/static/js/livewebsocket.js @@ -204,7 +204,7 @@ function connect(event) { if (klic === "angle") { //nejsou vsechny hodnoty - if (Object.keys(hodnota).length > 1) { + if (Object.keys(hodnota).length > 2) { // console.log("angle nalezen"); // console.log(JSON.stringify(hodnota)); if (angleSeries !== 1) { @@ -308,10 +308,22 @@ function connect(event) { lineWidth: 1, lineStyle: 2, // LineStyle.Dotted axisLabelVisible: true, - title: "max:", + title: "min:", }; const minSlopeLine = obj.series.createPriceLine(minSlopeLineOptopns); + + const maxSlopeLineOptopns = { + price: parsed_data.statinds.angle.maximum_slope, + color: '#b67de8', + lineWidth: 1, + lineStyle: 2, // LineStyle.Dotted + axisLabelVisible: true, + title: "max:", + }; + + const maxSlopeLine = obj.series.createPriceLine(maxSlopeLineOptopns); + } } //INDICATOR on new pane diff --git a/v2realbot/strategy/StrategyOrderLimitVykladaciNormalizedMYSELL.py b/v2realbot/strategy/StrategyOrderLimitVykladaciNormalizedMYSELL.py index 3bd1f35..2dedc2b 100644 --- a/v2realbot/strategy/StrategyOrderLimitVykladaciNormalizedMYSELL.py +++ b/v2realbot/strategy/StrategyOrderLimitVykladaciNormalizedMYSELL.py @@ -30,6 +30,9 @@ class StrategyOrderLimitVykladaciNormalizedMYSELL(Strategy): print("limit buy filled or cancelled. Vyhazujeme z pendingbuys.") #ic(self.state.vars.pendingbuys) + #davame pryc blockbuy + self.state.vars.blockbuy = 0 + if data.event == TradeEvent.FILL or data.event == TradeEvent.PARTIAL_FILL: #ic("vstupujeme do orderupdatebuy") print(data) diff --git a/v2realbot/strategy/__pycache__/base.cpython-310.pyc b/v2realbot/strategy/__pycache__/base.cpython-310.pyc index 8d53d295ae429785ce2f6a7bb972e499eede41ab..d17c41e75f1db29a3e52d2a05c202ff5c06fc6fd 100644 GIT binary patch delta 59 zcmaEn_acuspO=@50SH3EDpDjj@@^4hWny9EW8QpB>>e{C*W{&AuB@C)4>*)Izn9u2 Oz--RpzIl!I9&P~eU=bYv delta 59 zcmaEn_acuspO=@50SH!x=cmlt$h$?1m63&!k9+emv3tynf|Hj@xw0}bJ?D_#{9bC8 O0J9y3!{#;Gd$<7R?gr}wXdPpW?n_-N*oS}?F-=r#Q^h~<{sM$1O(2k%kR~Cuob%jf zA5a{<-#hnr&-uM`?z{KATpIl8xFcn^TP6HmTwa0N;I|yL?9#=??W`~ZPOSwhw3ayq zwm{{&Iot{^tqrQQyR~+0@0?sM;mjT2URT2Rz`fvs>U9?G058<6OW{tag*v=S|6sd3!0EQh-vJGuVESkFbmC^8Cs0lR%pZMLtolHPjW$5VyPtPD%Y|(o{TYidpCb(yeoJez$^1Q0pBK8Dey7Cg3t0}H>O)1)W z1tSVApr9bjE1_*1?Uk>%FDb9<#27LBq-Swn!(@_L&#wWp=}6Fqp!00=mD@` ziKWpn)?@YKPg{;Aa?z}o@l(0+Y&@0B_#qxEkQL>t{%8{X#WlcNCYQ(>OftHt`BQVB z2NlIuqKoN-mgz7?$8)O@61_jrJJugKdVgRKY6Xt^yZzHVr~Pl2=36d>foLN0Rj2Vu zl4(hCL*@1!t^dcPEfY`9C$!rt;5}Somj*(zZbDX<$0w)xUARpiG8Ve~4yMR5 z!x;Rw7r(Q9!1jsrWnT3l#_MAJy+#$en7(~3C<9l-gv9Z$>OvGpO^?JF@8JkkV&_k(6j}J zu4eed3*jU3^uiO4_B#mw4V*C}{`Y!R5cW2oH*k>q9+)O zMj4nX)mz25O8J{&|JJ|Rx=2Bx2F8a(yKiglJ_@4Uz#Rm3gpkVLBKvKz@6F-t*4{jT}n9kV6g5>2flyTjqFbF`mWOa6#;^@2hGf zNoqhYqYGO|=tHBKT&VZD4INWa=QrrYuM+&$*gJo(xA$~Yw2YjM@sIF^t)rGaj5ubT z9i-@7hi1ZM_!&t@V+&2%N|sX)e_eD22GtmuN%3T0hdM*%5%Er-n;jOP1%j+iY~AK7 z>m}Mt&?gRW3l!c*Q&-dYO^#+b<)xR!Qi+5XGyYBBR4l(hu#JG0UN;w;oN_#sN*J$z z@1nV8f=+^df?pULl~v!!HsTd*9dwmudJR!AJNtaEtDSayBPM8(I`^xiusnYiRxt{D#eS delta 2126 zcmZ{keQZ-z6u{qYyV9*|*KHl!+I3sIbz3(W!ZsL;eSa~=7;J*3B3;w-M!I!vxqTgD zq64>}iHO6i1_`2kggBxCP7zED(HK6A#$eRMC;Eqf5HXr){KJ2Yc+Ok0fQeiBd*_~e z&$;K^bMC#=|6Y$ZX0fD6_;*8z!Oz7(2TLJ$M)I$QJjloI8gR(&#vkT$y#R-t+O1G*ZhMO_D4)XAL~;A&Wd<1VO|yJ4+nwGJB4=Z5<<>!A@f zQ$5fmGc;+2794KGoLZp`b85q!dZ8UUFo#X3?SwAWcFCR7dVgQ41l@8UY>?|Qk;_Vw zN5$TZTj;LWR>4MuVmsvAL^c};edO2x$+0-^pm9GrDm5g6<8mCw2_wSFY|L|SGHp zvpnRbCC4s~W}VLukfnPO9+HX>Q(`FlifJcGKE{K>ZTDIZ;vk_zRrSG0MAc7*<8ylcJb5`RE;~Kh z*HHY^gs?FyD`p19kBi@&F8vGGz4siowbFKpNxO9*4NBZkW?DgK7bR_|m6j^-CFx%l z$pW{T_U5k;j^VKtm_H}+HNpvTqhN%+t{rBVE7$TBDz#$T89yyXTrKA9wCoYWqvCy+ zCx?#v8(KxZYmyAi#P}KNvlk0H*eE&5PEmL=8v2eFQ6D)NpPL^o{F_x$&_08jl1Rp7 z&d=d!p{3W5UeC9XVh7=IairL3q;|g}iFb?3^6!fRmFki}0Ais)fDed2id{u-k&Tu( z`Miz4#pvv*{G3?s{YqtdfzrqoL6Yq;78Bk|V;_k<;!STOYZiCBUbal6 zmlc`oN$nu46|2iUQ&&+`jqzXspe2D5|KknI2KKC%AB7fln{IbdgXZoL91XJ zN%Tzmb-R;l$}U+^Ciy-btNL(M(Oy3uqBTQ=2;l%>n$V~f?+}SvL64Jkf^eEZmw?X^ iv?gvPNvkiQp20x$mDlLfGQ>>zs(%3`Vg@w; diff --git a/v2realbot/utils/utils.py b/v2realbot/utils/utils.py index 5955aaf..6045c33 100644 --- a/v2realbot/utils/utils.py +++ b/v2realbot/utils/utils.py @@ -38,6 +38,47 @@ def get_tick(price: float, normalized_ticks: float = 0.01): ratio = price/NORMALIZED_TICK_BASE_PRICE return price2dec(ratio*normalized_ticks) +def eval_cond_dict(cond: dict) -> tuple[bool, str]: + """ + evaluates conditions dictionary and return result and name of condition + examples: + buy_cond["AND"]["1and"] = True + buy_cond["AND"]["2and"] = False + buy_cond["OR"]["3or"] = False + buy_cond["OR"]["4or"] = False + buy_cond["5single"] = False + buy_cond["5siddngle"] = False + group eval rules. 1. single 2. AND 3. ORS + """ + msg = "" + ret = False + #eval single cond + for klic in cond: + if klic in ["AND","OR"]: continue + else: + if cond[klic]: + return True, klic + + ##check AND group + if 'AND' in cond.keys(): + for key in cond["AND"]: + + if cond["AND"][key]: + ret = True + msg += key + " AND " + else: + ret = False + break + if ret: + return True, msg + #eval OR groups + if "OR" in cond.keys(): + for key in cond["OR"]: + if cond["OR"][key]: + return True, key + + return False, None + def safe_get(collection, key, default=None): """Get values from a collection without raising errors"""