cbar and buysignal refactor

This commit is contained in:
David Brazda
2023-06-01 13:18:35 +02:00
parent fb9f6c5550
commit 6d90b41cd3
14 changed files with 412 additions and 260 deletions

54
testy/buyconditiontest.py Normal file
View File

@ -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()

View File

@ -5,7 +5,7 @@ from v2realbot.strategy.StrategyOrderLimitVykladaciNormalizedMYSELL import Strat
from v2realbot.enums.enums import RecordType, StartBarAlign, Mode, Account, OrderSide, OrderType from v2realbot.enums.enums import RecordType, StartBarAlign, Mode, Account, OrderSide, OrderType
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.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 datetime import datetime
#from icecream import install, ic #from icecream import install, ic
#from rich import print #from rich import print
@ -14,6 +14,7 @@ from msgpack import packb, unpackb
import asyncio import asyncio
import os import os
from traceback import format_exc from traceback import format_exc
import inspect
print(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) print(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
"""" """"
@ -101,10 +102,10 @@ def next(data, state: StrategyState):
max_pozic = int(state.vars.maxpozic) max_pozic = int(state.vars.maxpozic)
def_mode_from = safe_get(state.vars, "def_mode_from",max_pozic/2) def_mode_from = safe_get(state.vars, "def_mode_from",max_pozic/2)
if akt_pozic >= int(def_mode_from): 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 return True
else: 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 return False
def get_limitka_price(): def get_limitka_price():
@ -160,7 +161,6 @@ def next(data, state: StrategyState):
else: else:
state.ilog(e="No time for consolidation", msg=data["index"]) state.ilog(e="No time for consolidation", msg=data["index"])
print("no time for consolidation", data["index"]) print("no time for consolidation", data["index"])
#mozna presunout o level vys #mozna presunout o level vys
def vyloz(): def vyloz():
##prvni se vyklada na aktualni cenu, další jdou podle krivky, nula v krivce zvyšuje množství pro následující iteraci ##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 last_price = price
state.vars.blockbuy = 1 state.vars.blockbuy = 1
state.vars.jevylozeno = 1 state.vars.jevylozeno = 1
state.vars.last_buysignal_index = data['index']
def eval_sell(): def eval_sell():
"""" """"
@ -241,243 +242,117 @@ def next(data, state: StrategyState):
goal_price = get_limitka_price() goal_price = get_limitka_price()
state.ilog(e=f"Goal price {goal_price}") state.ilog(e=f"Goal price {goal_price}")
if curr_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 #TODO cekat az slope prestane intenzivn erust, necekat az na klesani
#v kazde iteraci testujeme sell #TODO mozna cekat na nejaky signal RSI
#pri potvrzenem baru muzeme provest kroky per hlavni BAR #TODO pripadne pokud dosahne TGTBB prodat ihned
#potvrzeni neprinasi nikdy zadna nova data, ale pouze potvrzeni.
state.ilog(e="-----")
eval_sell()
conf_bar = data['confirmed'] #OPTIMALIZACE pri stoupajícím angle
if conf_bar == 1: if sell_protection_enabled() is False:
#delej veci per standardni bar state.interface.sell(size=state.positions)
state.ilog(e="BAR potvrzeny") state.vars.sell_in_progress = True
else: state.ilog(e=f"market SELL was sent {curr_price=}", positions=state.positions, avgp=state.avgp, sellinprogress=state.vars.sell_in_progress)
pass
#delej veci tick-based
#CBAR INDICATOR pro tick price a deltu VOLUME def populate_ema_indicator():
tick_price = round2five(data['close']) #BAR EMA INDICATOR -
tick_delta_volume = data['volume'] - state.vars.last_tick_volume #plnime MAcko - nyni posilame jen N poslednich hodnot
#zaroven osetrujeme pripady, kdy je malo dat a ukladame nulu
if conf_bar == 0:
try: try:
#pokud v potvrzovacím baru nebyly zmeny, nechavam puvodni hodnoty ma = int(state.vars.MA)
# if tick_delta_volume == 0: #poslednich ma hodnot
# state.indicators.tick_price[-1] = state.indicators.tick_price[-2] source = state.bars.close[-ma:] #state.bars.vwap
# state.indicators.tick_volume[-1] = state.indicators.tick_volume[-2] ema_value = ema(source, ma)
# else:
#docasne dame pryc volume deltu a davame absolutni cislo ##pokus MACKO zakrouhlit na tri desetina a petku
state.cbar_indicators.tick_price[-1] = tick_price state.indicators.ema[-1]=round2five(ema_value[-1])
state.cbar_indicators.tick_volume[-1] = tick_delta_volume ##state.indicators.ema[-1]=trunc(ema_value[-1],3)
except: #state.ilog(e=f"EMA {state.indicators.ema[-1]}", ema_last=state.indicators.ema[-6:])
pass 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)
state.vars.last_tick_price = tick_price if len(state.bars.close) > (slope_lookback + lookback_offset):
state.vars.last_tick_volume = data['volume'] array_od = slope_lookback + lookback_offset
#pri potvrzem CBARu nulujeme counter volume array_do = slope_lookback
if conf_bar == 1: lookbackprice_array = state.bars.vwap[-array_od:-array_do]
state.vars.last_tick_volume = 0 #obycejný prumer hodnot
state.vars.next_new = 1 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)
#TEST BUY SIGNALu z cbartick_price - 3klesave za sebou #slope MA vyrovna vykyvy ve slope, dále pracujeme se slopeMA
buy_tp = isfalling(state.cbar_indicators.tick_price,state.vars.Trend) slope_MA_length = 5
state.ilog(e=f"TICK SIGNAL ISFALLING {buy_tp}", last_tp=state.cbar_indicators.tick_price[-6:], trend=state.vars.Trend) source = state.indicators.slope[-slope_MA_length:]
slopeMAseries = ema(source, slope_MA_length) #state.bars.vwap
slopeMA = slopeMAseries[-1]
state.indicators.slopeMA[-1]=slopeMA
#IVWAP - PRUBEZNY persistovany VWAP 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:])
# try:
# #naplneni cbar tick indikatoru s prubeznou vwap
# state.cbar_indicators.ivwap[-1]=data['vwap']
# except:
# pass
#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())
# if data['confirmed'] == 0: def populate_rsi_indicator():
# state.ilog(e="CBAR unconfirmed - returned", msg=str(data)) #RSI14 INDICATOR
# #TBD zde muzeme i nakupovat try:
# #indikatory pocitat, ale neukladat do historie rsi_buy_signal = False
# return 0 rsi_dont_buy = False
# #confirmed rsi_length = 14
# else: source = state.bars.close #[-rsi_length:] #state.bars.vwap
# state.ilog(e="CBAR confirmed - continue", msg=str(data)) 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
#BAR EMA INDICATOR - def slope_too_low():
#plnime MAcko - nyni posilame jen N poslednich hodnot return state.indicators.slopeMA[-1] < float(state.vars.minimum_slope)
#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 def slope_too_high():
try: return state.indicators.slopeMA[-1] > float(safe_get(state.vars, "bigwave_slope_above",0.20))
##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 #resetujeme, kdyz 1) je aktivni buy protection 2) kdyz to ujede
#jako zdroj je prubezna CBAR tickprice #TODO mozna tick2reset spoustet jednou za X opakovani
source = state.cbar_indicators.tick_price def pendingbuys_optimalization():
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
process triggers
buy_signal
buy protection (dont buy when)
sell signal
sell protection (dont buy when)
#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 slopeMA<maxSlopeMA:
print("OCHRANA SLOPE or RSI TOO HIGH")
# if slopeMA<maxSlopeMA:
# state.ilog(e="Slope MA too high "+str(slopeMA)+" max:"+str(maxSlopeMA))
state.ilog(e=f"Slope or RSI too high {slope=} {rsi_value=}")
if len(state.vars.pendingbuys)>0: if len(state.vars.pendingbuys)>0:
print("CANCEL PENDINGBUYS") if buy_protection_enabled():
#ic(state.vars.pendingbuys) #state.ilog(e="PENDINGBUYS reset", message=inspect.currentframe().f_code.co_name)
res = asyncio.run(state.cancel_pending_buys()) res = asyncio.run(state.cancel_pending_buys())
#ic(state.vars.pendingbuys) state.ilog(e="CANCEL pendingbuyes", pb=state.vars.pendingbuys, res=res)
state.ilog(e="Rusime pendingbuyes", pb=state.vars.pendingbuys, res=res) else:
print("slope", slope) #pokud mame vylozeno a cena je vetsi nez tick2reset
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:
maxprice = max(state.vars.pendingbuys.values()) 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)): 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()) res = asyncio.run(state.cancel_pending_buys())
state.ilog(e=f"UJELO to. Rusime PB", msg=f"{state.vars.ticks2reset=}", pb=state.vars.pendingbuys) 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: if len(state.vars.pendingbuys) == 0:
state.vars.blockbuy = 0 state.vars.blockbuy = 0
state.vars.jevylozeno = 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): def init(state: StrategyState):
#place to declare new vars #place to declare new vars
@ -505,25 +514,19 @@ def init(state: StrategyState):
state.vars.last_tick_price = 0 state.vars.last_tick_price = 0
state.vars.last_tick_volume = 0 state.vars.last_tick_volume = 0
state.vars.next_new = 0 state.vars.next_new = 0
state.vars.last_buysignal_index = 0
#state.cbar_indicators['ivwap'] = [] #state.cbar_indicators['ivwap'] = []
state.cbar_indicators['tick_price'] = [] state.cbar_indicators['tick_price'] = []
state.cbar_indicators['tick_volume'] = [] state.cbar_indicators['tick_volume'] = []
state.indicators['ema'] = [] state.indicators['ema'] = []
state.indicators['slope'] = [] state.indicators['slope'] = []
state.indicators['slopeMA'] = [] state.indicators['slopeMA'] = []
state.cbar_indicators['RSI14'] = [] state.indicators['RSI14'] = []
#static indicators - those not series based #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 state.vars["ticks2reset_backup"] = state.vars.ticks2reset
def main(): 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__) name = os.path.basename(__file__)
se = Event() se = Event()
pe = Event() pe = Event()

View File

@ -363,6 +363,9 @@ class TradeAggregator2Queue(TradeAggregator):
copy = obj.copy() copy = obj.copy()
else: else:
copy = obj copy = obj
##populate secondary resolution if required
self.queue.put(copy) self.queue.put(copy)
res = [] res = []
#print("po insertu",res) #print("po insertu",res)

View File

@ -157,14 +157,15 @@ class Trade_Offline_Streamer(Thread):
wait_for_q = False wait_for_q = False
else: else:
wait_for_q = True wait_for_q = True
#ic(wait_for_q) print(f"{wait_for_q=}")
# v tradesResponse je dict = Trades identifikovane symbolem # v tradesResponse je dict = Trades identifikovane symbolem
for symbol in tradesResponse: for symbol in tradesResponse:
#print(tradesResponse[symbol]) #print(tradesResponse[symbol])
celkem = len(tradesResponse[symbol]) celkem = len(tradesResponse[symbol])
#ic(symbol, celkem) #ic(symbol, celkem)
#print("POCET: ", celkem) print("POCET: ", celkem)
cnt = 1 cnt = 1
@ -177,7 +178,8 @@ class Trade_Offline_Streamer(Thread):
if self.time_from < to_datetime(t['t']) < self.time_to: if self.time_from < to_datetime(t['t']) < self.time_to:
#poustime dal, jinak ne #poustime dal, jinak ne
if wait_for_q: 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: else:
#ic("Q found poustime dal") #ic("Q found poustime dal")
wait_for_q = False wait_for_q = False
@ -185,7 +187,7 @@ class Trade_Offline_Streamer(Thread):
#homogenizace timestampu s online streamem #homogenizace timestampu s online streamem
t['t'] = Timestamp.from_unix(to_datetime(t['t']).timestamp()) t['t'] = Timestamp.from_unix(to_datetime(t['t']).timestamp())
#print("PROGRESS ",cnt,"/",celkem) print("PROGRESS ",cnt,"/",celkem)
#print(t) #print(t)
#na rozdil od wwebsocketu zde nemame v zaznamu symbol ['S'] #na rozdil od wwebsocketu zde nemame v zaznamu symbol ['S']
#vsem streamum na tomto symbolu posilame data - tbd mozna udelat i per stream vlakno #vsem streamum na tomto symbolu posilame data - tbd mozna udelat i per stream vlakno

View File

@ -321,6 +321,9 @@ function chart_archived_run(archRecord, data, oneMinuteBars) {
//var last = null //var last = null
var last_time = 0 var last_time = 0
var 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) => { value.forEach((element, index, array) => {
item = {} item = {}
//debug //debug
@ -328,14 +331,15 @@ function chart_archived_run(archRecord, data, oneMinuteBars) {
//if (indicators.time[index] !== undefined) { //if (indicators.time[index] !== undefined) {
//{console.log("problem",key,last)} //{console.log("problem",key,last)}
time = indicators.time[index] time = indicators.time[index]
if (time==last_time) { if (last_time>=time) {
//console.log(key, "problem v case - pousunuto o 0.001",time, last_time, element) console.log(key, "problem v case - zarovnano",time, last_time, element)
time += 0.000001
indicators.time[index] = indicators.time[index-1] + 0.000001
} }
item["time"] = time item["time"] = indicators.time[index]
item["value"] = element item["value"] = element
last_time = time last_time = indicators.time[index]
if ((element == null) || (indicators.time[index] == null)) { if ((element == null) || (indicators.time[index] == null)) {
console.log("probelem u indikatoru",key, "nekonzistence", element, indicators.time[index]) 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.embed) {
if (conf.histogram) { if (conf.histogram) {
@ -392,10 +409,24 @@ function chart_archived_run(archRecord, data, oneMinuteBars) {
lineWidth: 1, lineWidth: 1,
lineStyle: 2, // LineStyle.Dotted lineStyle: 2, // LineStyle.Dotted
axisLabelVisible: true, axisLabelVisible: true,
title: "max:", title: "min:",
}; };
const minSlopeLine = obj.series.createPriceLine(minSlopeLineOptopns); 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, priceLineVisible: false,
}); });
//console.log("problem tu",JSON.stringify(items)) //DEBUG
// if (key == 'tick_price') {
// console.log("problem tu",JSON.stringify(items))
// }
//add data //add data
obj.series.setData(items) obj.series.setData(items)

View File

@ -204,7 +204,7 @@ function connect(event) {
if (klic === "angle") { if (klic === "angle") {
//nejsou vsechny hodnoty //nejsou vsechny hodnoty
if (Object.keys(hodnota).length > 1) { if (Object.keys(hodnota).length > 2) {
// console.log("angle nalezen"); // console.log("angle nalezen");
// console.log(JSON.stringify(hodnota)); // console.log(JSON.stringify(hodnota));
if (angleSeries !== 1) { if (angleSeries !== 1) {
@ -308,10 +308,22 @@ function connect(event) {
lineWidth: 1, lineWidth: 1,
lineStyle: 2, // LineStyle.Dotted lineStyle: 2, // LineStyle.Dotted
axisLabelVisible: true, axisLabelVisible: true,
title: "max:", title: "min:",
}; };
const minSlopeLine = obj.series.createPriceLine(minSlopeLineOptopns); 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 //INDICATOR on new pane

View File

@ -30,6 +30,9 @@ class StrategyOrderLimitVykladaciNormalizedMYSELL(Strategy):
print("limit buy filled or cancelled. Vyhazujeme z pendingbuys.") print("limit buy filled or cancelled. Vyhazujeme z pendingbuys.")
#ic(self.state.vars.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: if data.event == TradeEvent.FILL or data.event == TradeEvent.PARTIAL_FILL:
#ic("vstupujeme do orderupdatebuy") #ic("vstupujeme do orderupdatebuy")
print(data) print(data)

View File

@ -254,17 +254,10 @@ class Strategy:
#calling plugin (can be overriden to do some additional steps) #calling plugin (can be overriden to do some additional steps)
self.before_iteration() self.before_iteration()
ted = datetime.fromtimestamp(self.state.time).astimezone(zoneNY) ted = datetime.fromtimestamp(self.state.time).astimezone(zoneNY)
#pro mysell je realizovano v next, kvuli prodavaci logice
if is_open_rush(ted, self.open_rush) or is_close_rush(ted, self.close_rush): if is_open_rush(ted, self.open_rush) or is_close_rush(ted, self.close_rush):
pass pass
#self.state.ilog(e="Rush hour - skipping") #self.state.ilog(e="Rush hour - skipping")
#identifikatory jsou ulozeny vektorove, tzn. kdyz nejdeme dovnitr iterace(tak nepotrebujeme prazdny cas pro tuto iteraci)
#hodnoty time a identifikatoru musi byt stejne
#TBD pripdane predelat a dodelat pro CBARy az je budu pouzivat
# if self.rectype == RecordType.BAR:
# self.state.indicators['time'].pop()
# elif self.rectype == RecordType.CBAR:
# print("RUSH skipping NOT IMPLEMENTED for CBARs yet")
else: else:
self.next(item, self.state) self.next(item, self.state)
self.after_iteration(item) self.after_iteration(item)
@ -315,6 +308,13 @@ class Strategy:
continue continue
#self.state.iter_log(event="INGEST",msg="New data ingested", item=item) #self.state.iter_log(event="INGEST",msg="New data ingested", item=item)
print("New data ingested") print("New data ingested")
#TODO sem pridat ochranu kulometu
#pokud je updatetime aktualniho baru mensi nez LIMIT a nejde o potvrzovaci bar
#tak jej vyhodit
#zabraní se tím akcím na než bych stejně nešlo reagovat
#TODO jeste promyslet
#calling main loop #calling main loop
self.strat_loop(item=item) self.strat_loop(item=item)

View File

@ -38,6 +38,47 @@ def get_tick(price: float, normalized_ticks: float = 0.01):
ratio = price/NORMALIZED_TICK_BASE_PRICE ratio = price/NORMALIZED_TICK_BASE_PRICE
return price2dec(ratio*normalized_ticks) 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): def safe_get(collection, key, default=None):
"""Get values from a collection without raising errors""" """Get values from a collection without raising errors"""