mintrade delta pro kulomet,slowscope,strvrs enhncm

This commit is contained in:
David Brazda
2023-06-20 15:21:21 +02:00
parent 5fd6da7f59
commit 8004dc4b4c
17 changed files with 1007 additions and 187 deletions

View File

@ -1018,9 +1018,9 @@ for t in tradeList:
trade_dict.timestamp.append(t.timestamp) trade_dict.timestamp.append(t.timestamp)
trade_dict.symbol.append(t.order.symbol) trade_dict.symbol.append(t.order.symbol)
trade_dict.side.append(t.order.side) trade_dict.side.append(t.order.side)
trade_dict.qty.append(t.qty) trade_dict.qty.append(int(t.qty))
trade_dict.price.append(t.price) trade_dict.price.append(t.price)
trade_dict.position_qty.append(t.position_qty) trade_dict.position_qty.append(int(t.position_qty))
trade_dict.value.append(t.value) trade_dict.value.append(t.value)
trade_dict.cash.append(t.cash) trade_dict.cash.append(t.cash)
trade_dict.order_type.append(t.order.order_type) trade_dict.order_type.append(t.order.order_type)

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, is_open_rush, is_close_rush, eval_cond_dict 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, Average
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
@ -33,6 +33,7 @@ potvrzený CBAR
""" """
stratvars = AttributeDict(maxpozic = 400, stratvars = AttributeDict(maxpozic = 400,
def_mode_from = 200, def_mode_from = 200,
chunk = 10, chunk = 10,
@ -108,7 +109,7 @@ def next(data, state: StrategyState):
#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_profit_price():
def_profit = safe_get(state.vars, "def_profit",state.vars.profit) def_profit = safe_get(state.vars, "def_profit",state.vars.profit)
cena = float(state.avgp) cena = float(state.avgp)
#v MYSELL hrajeme i na 3 desetinna cisla - TBD mozna hrat jen na 5ky (0.125, 0.130, 0.135 atp.) #v MYSELL hrajeme i na 3 desetinna cisla - TBD mozna hrat jen na 5ky (0.125, 0.130, 0.135 atp.)
@ -117,6 +118,11 @@ def next(data, state: StrategyState):
else: else:
return price2dec(cena+get_tick(cena,float(state.vars.profit)),3) return price2dec(cena+get_tick(cena,float(state.vars.profit)),3)
def get_max_profit_price():
max_profit = float(safe_get(state.vars, "max_profit",0.03))
cena = float(state.avgp)
return price2dec(cena+get_tick(cena,max_profit),3)
def optimize_qty_multiplier(): def optimize_qty_multiplier():
akt_pozic = int(state.positions)/int(state.vars.chunk) akt_pozic = int(state.positions)/int(state.vars.chunk)
multiplier = 1 multiplier = 1
@ -124,7 +130,7 @@ def next(data, state: StrategyState):
#zatim jednoduse pokud je akt. pozice 1 nebo 3 chunky (<4) tak zdvojnásubuju #zatim jednoduse pokud je akt. pozice 1 nebo 3 chunky (<4) tak zdvojnásubuju
#aneb druhy a treti nakup #aneb druhy a treti nakup
if akt_pozic > 0 and akt_pozic < 4: if akt_pozic > 0 and akt_pozic < 4:
multiplier = safe_get(state.vars, "market_buy_multiplier", 2) multiplier = safe_get(state.vars, "market_buy_multiplier", 1)
state.ilog(e=f"BUY MULTIPLIER: {multiplier}") state.ilog(e=f"BUY MULTIPLIER: {multiplier}")
return multiplier return multiplier
@ -252,8 +258,9 @@ def next(data, state: StrategyState):
curr_price = float(data['close']) curr_price = float(data['close'])
state.ilog(e="Eval SELL", price=curr_price, pos=state.positions, avgp=state.avgp, sell_in_progress=state.vars.sell_in_progress) state.ilog(e="Eval SELL", price=curr_price, pos=state.positions, avgp=state.avgp, sell_in_progress=state.vars.sell_in_progress)
if int(state.positions) > 0 and float(state.avgp)>0 and state.vars.sell_in_progress is False: if int(state.positions) > 0 and float(state.avgp)>0 and state.vars.sell_in_progress is False:
goal_price = get_limitka_price() goal_price = get_profit_price()
state.ilog(e=f"Goal price {goal_price}") max_price = get_max_profit_price()
state.ilog(e=f"Goal price {goal_price} max price {max_price}")
#pokud je cena vyssi #pokud je cena vyssi
if curr_price>=goal_price: if curr_price>=goal_price:
@ -261,12 +268,12 @@ def next(data, state: StrategyState):
#TODO cekat az slope prestane intenzivn erust, necekat az na klesani #TODO cekat az slope prestane intenzivn erust, necekat az na klesani
#TODO mozna cekat na nejaky signal RSI #TODO mozna cekat na nejaky signal RSI
#TODO pripadne pokud dosahne TGTBB prodat ihned #TODO pripadne pokud dosahne TGTBB prodat ihned
max_price_signal = curr_price>=max_price
#OPTIMALIZACE pri stoupajícím angle #OPTIMALIZACE pri stoupajícím angle
if sell_protection_enabled() is False: if max_price_signal or sell_protection_enabled() is False:
state.interface.sell(size=state.positions) state.interface.sell(size=state.positions)
state.vars.sell_in_progress = True 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) state.ilog(e=f"market SELL was sent {curr_price=} {max_price_signal=}", positions=state.positions, avgp=state.avgp, sellinprogress=state.vars.sell_in_progress)
#pokud je cena nizsi, testujeme REVERSE POZITION PROTECTION #pokud je cena nizsi, testujeme REVERSE POZITION PROTECTION
else: else:
pass pass
@ -312,9 +319,39 @@ def next(data, state: StrategyState):
# None - standard, defaults mode - attributes are read from general stratvars section
# other modes - attributtes are read from mode specific stratvars section, defaults to general section
#WIP
def set_mode():
state.vars.mode = None
#dotahne hodnotu z prislusne sekce
#pouziva se namisto safe_get
# stratvars
# buysignal = 1
# stratvars.mode1
# buysignal = 2
# PARAMS:
# - section: napr. stratvars.buysignal
# - var name: MA_length
# - default: defaultní hodnota, kdyz nenalezeno
# Kroky: 1)
# vrati danou hodnotu nastaveni podle aktualniho modu state.vars.mode
# pokud je None, vrati pro standardni mod, pokud neni nalezeno vrati default
# EXAMPLE:
# get_modded_vars("state")
#get_modded_vars(state.vars, 'buysignal', 1) - namista safe_get
#WIP
def get_modded_vars(section, name: str, default = None):
if state.vars.mode is None:
return safe_get(section, name, default)
else:
try:
modded_section = section[state.vars.mode]
except KeyError:
modded_section = section
return safe_get(modded_section, name, safe_get(section, name, default))
def populate_ema_indicator(): def populate_ema_indicator():
#BAR EMA INDICATOR - #BAR EMA INDICATOR -
@ -336,6 +373,63 @@ def next(data, state: StrategyState):
#evaluate buy signal #evaluate buy signal
#consolidation #consolidation
# [stratvars.indicators.slope]
# lookback
# lookback_offset
def populate_slow_slope_indicator():
options = safe_get(state.vars.indicators, 'slow_slope', None)
if options is None:
state.ilog(e="No options for slow slope in stratvars")
return
#SLOW 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:
slow_slope = 99
slope_lookback = safe_get(options, 'slope_lookback', 100)
minimum_slope = safe_get(options, 'minimum_slope', 25)
maximum_slope = safe_get(options, "maximum_slope",0.9)
lookback_offset = safe_get(options, 'lookback_offset', 25)
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)
lookbacktime = state.bars.time[-slope_lookback]
else:
#kdyz neni dostatek hodnot, pouzivame jako levy bod open hodnotu close[0]
lookbackprice = state.bars.close[0]
lookbacktime = state.bars.time[0]
state.ilog(e="Slow Slope - not enough data bereme left bod open", slope_lookback=slope_lookback, slope=state.indicators.slope, slopeMA=state.indicators.slopeMA)
#výpočet úhlu - a jeho normalizace
slope = ((state.bars.close[-1] - lookbackprice)/lookbackprice)*100
slope = round(slope, 4)
state.indicators.slow_slope[-1]=slope
#angle je ze slope
state.statinds.angle_slow = dict(time=state.bars.time[-1], price=state.bars.close[-1], lookbacktime=lookbacktime, lookbackprice=lookbackprice, minimum_slope=minimum_slope, maximum_slope=maximum_slope)
#slope MA vyrovna vykyvy ve slope, dále pracujeme se slopeMA
slope_MA_length = safe_get(options, 'MA_length', 5)
source = state.indicators.slow_slope[-slope_MA_length:]
slopeMAseries = ema(source, slope_MA_length) #state.bars.vwap
slopeMA = slopeMAseries[-1]
state.indicators.slow_slopeMA[-1]=slopeMA
state.ilog(e=f"SLOW {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
except Exception as e:
print("Exception in NEXT Slow Slope Indicator section", str(e))
state.ilog(e="EXCEPTION", msg="Exception in Slow Slope Indicator section" + str(e) + format_exc())
def populate_slope_indicator(): def populate_slope_indicator():
#SLOPE INDICATOR #SLOPE INDICATOR
#úhel stoupání a klesání vyjádřený mezi -1 až 1 #úhel stoupání a klesání vyjádřený mezi -1 až 1
@ -396,32 +490,37 @@ def next(data, state: StrategyState):
state.ilog(e=f"RSI {rsi_length=} necháváme 0", message=str(e)+format_exc()) state.ilog(e=f"RSI {rsi_length=} necháváme 0", message=str(e)+format_exc())
#state.indicators.RSI14[-1]=0 #state.indicators.RSI14[-1]=0
# def populate_cbar_rsi_indicator(): def populate_cbar_rsi_indicator():
# #CBAR RSI indicator #CBAR RSI indicator
# try: options = safe_get(state.vars.indicators, 'crsi', None)
# crsi_length = int(safe_get(state.vars, "crsi_length",14)) if options is None:
# source = state.cbar_indicators.tick_price #[-rsi_length:] #state.bars.vwap state.ilog(e="No options for crsi in stratvars")
# crsi_res = rsi(source, crsi_length) return
# crsi_value = trunc(crsi_res[-1],3)
# state.cbar_indicators.CRSI[-1]=crsi_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"CRSI {crsi_length=} necháváme 0", message=str(e)+format_exc())
# #state.indicators.RSI14[-1]=0
def populate_secondary_rsi_indicator():
#SBAR RSI indicator
try: try:
srsi_length = int(safe_get(state.vars, "srsi_length",14)) crsi_length = int(safe_get(options, 'crsi_length', 14))
source = state.secondary_indicators.sec_price #[-rsi_length:] #state.bars.vwap source = state.cbar_indicators.tick_price #[-rsi_length:] #state.bars.vwap
srsi_res = rsi(source, srsi_length) crsi_res = rsi(source, crsi_length)
srsi_value = trunc(srsi_res[-1],3) crsi_value = crsi_res[-1]
state.secondary_indicators.SRSI[-1]=srsi_value state.cbar_indicators.CRSI[-1]=crsi_value
#state.ilog(e=f"RSI {rsi_length=} {rsi_value=} {rsi_dont_buy=} {rsi_buy_signal=}", rsi_indicator=state.indicators.RSI14[-5:]) #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: except Exception as e:
state.ilog(e=f"SRSI {srsi_length=} necháváme 0", message=str(e)+format_exc()) state.ilog(e=f"CRSI {crsi_length=} necháváme 0", message=str(e)+format_exc())
#state.indicators.RSI14[-1]=0 #state.indicators.RSI14[-1]=0
# def populate_secondary_rsi_indicator():
# #SBAR RSI indicator
# try:
# srsi_length = int(safe_get(state.vars, "srsi_length",14))
# source = state.secondary_indicators.sec_price #[-rsi_length:] #state.bars.vwap
# srsi_res = rsi(source, srsi_length)
# srsi_value = trunc(srsi_res[-1],3)
# state.secondary_indicators.SRSI[-1]=srsi_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"SRSI {srsi_length=} necháváme 0", message=str(e)+format_exc())
# #state.indicators.RSI14[-1]=0
def slope_too_low(): def slope_too_low():
return state.indicators.slopeMA[-1] < float(state.vars.minimum_slope) return state.indicators.slopeMA[-1] < float(state.vars.minimum_slope)
@ -470,6 +569,25 @@ def next(data, state: StrategyState):
return result return result
def sell_protection_enabled(): def sell_protection_enabled():
options = safe_get(state.vars, 'sell_protection', None)
if options is None:
state.ilog(e="No options for sell protection in stratvars")
return False
disable_sell_proteciton_when = dict(AND=dict(), OR=dict())
#preconditions
disable_sell_proteciton_when['disabled_in_config'] = safe_get(options, 'enabled', False) is False
#too good to be true (maximum profit)
#disable_sell_proteciton_when['tgtbt_reached'] = safe_get(options, 'tgtbt', False) is False
#testing preconditions
result, conditions_met = eval_cond_dict(disable_sell_proteciton_when)
if result:
state.ilog(e=f"SELL_PROTECTION DISABLED by precondition {conditions_met}")
return False
dont_sell_when = dict(AND=dict(), OR=dict()) dont_sell_when = dict(AND=dict(), OR=dict())
##add conditions here ##add conditions here
@ -477,9 +595,13 @@ def next(data, state: StrategyState):
#pokud je slope too high, pak prodavame jakmile slopeMA zacne klesat, napr. 4MA (TODO 3) #pokud je slope too high, pak prodavame jakmile slopeMA zacne klesat, napr. 4MA (TODO 3)
#TODO zkusit pro pevny profit, jednoduse pozdrzet prodej - dokud tick_price roste nebo se drzi tak neprodavat, pokud klesne prodat
#mozna mit dva mody - pri vetsi volatilite pouzivat momentum, pri mensi nebo kdyz potrebuju pryc, tak prodat hned
#toto docasne pryc dont_sell_when['slope_too_high'] = slope_too_high() and not isfalling(state.indicators.slopeMA,4) #toto docasne pryc dont_sell_when['slope_too_high'] = slope_too_high() and not isfalling(state.indicators.slopeMA,4)
dont_sell_when['AND']['slopeMA_rising'] = isrising(state.indicators.slopeMA,2) dont_sell_when['AND']['slopeMA_rising'] = isrising(state.indicators.slopeMA,safe_get(options, 'slopeMA_rising', 2))
dont_sell_when['AND']['rsi_not_falling'] = not isfalling(state.indicators.RSI14,3) dont_sell_when['AND']['rsi_not_falling'] = not isfalling(state.indicators.RSI14,safe_get(options, 'rsi_not_falling',3))
#dont_sell_when['rsi_dont_buy'] = state.indicators.RSI14[-1] > safe_get(state.vars, "rsi_dont_buy_above",50) #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) result, conditions_met = eval_cond_dict(dont_sell_when)
@ -492,7 +614,6 @@ def next(data, state: StrategyState):
#preconditions #preconditions
dont_buy_when = dict(AND=dict(), OR=dict()) dont_buy_when = dict(AND=dict(), OR=dict())
if safe_get(state.vars, "buy_only_on_confirmed",True): if safe_get(state.vars, "buy_only_on_confirmed",True):
dont_buy_when['bar_not_confirmed'] = (data['confirmed'] == 0) dont_buy_when['bar_not_confirmed'] = (data['confirmed'] == 0)
#od posledniho vylozeni musi ubehnout N baru #od posledniho vylozeni musi ubehnout N baru
@ -563,7 +684,8 @@ def next(data, state: StrategyState):
# state.indicators.tick_volume[-1] = state.indicators.tick_volume[-2] # state.indicators.tick_volume[-1] = state.indicators.tick_volume[-2]
# else: # else:
tick_price = round2five(data['close']) #tick_price = round2five(data['close'])
tick_price = data['close']
tick_delta_volume = data['volume'] - state.vars.last_tick_volume tick_delta_volume = data['volume'] - state.vars.last_tick_volume
#docasne dame pryc volume deltu a davame absolutni cislo #docasne dame pryc volume deltu a davame absolutni cislo
@ -588,16 +710,24 @@ def next(data, state: StrategyState):
if key != 'time': if key != 'time':
last_ind_vals[key] = state.cbar_indicators[key][-5:] last_ind_vals[key] = state.cbar_indicators[key][-5:]
for key in state.secondary_indicators: # for key in state.secondary_indicators:
if key != 'time': # if key != 'time':
last_ind_vals[key] = state.secondary_indicators[key][-5:] # last_ind_vals[key] = state.secondary_indicators[key][-5:]
return last_ind_vals return last_ind_vals
conf_bar = data['confirmed'] conf_bar = data['confirmed']
#PROCES DELTAS - to function
last_update_delta = round((float(data['updated']) - state.vars.last_update_time),6) if state.vars.last_update_time != 0 else 0 last_update_delta = round((float(data['updated']) - state.vars.last_update_time),6) if state.vars.last_update_time != 0 else 0
state.vars.last_update_time = float(data['updated']) state.vars.last_update_time = float(data['updated'])
state.ilog(e=f"---{data['index']}-{conf_bar}--delta:{last_update_delta}")
if len(state.vars.last_50_deltas) >=50:
state.vars.last_50_deltas.pop(0)
state.vars.last_50_deltas.append(last_update_delta)
avg_delta = Average(state.vars.last_50_deltas)
state.ilog(e=f"---{data['index']}-{conf_bar}--delta:{last_update_delta}---AVGdelta:{avg_delta}")
#kroky pro CONFIRMED BAR only #kroky pro CONFIRMED BAR only
if conf_bar == 1: if conf_bar == 1:
@ -609,13 +739,17 @@ def next(data, state: StrategyState):
state.vars.last_tick_volume = 0 state.vars.last_tick_volume = 0
state.vars.next_new = 1 state.vars.next_new = 1
#zatim takto na confirm
populate_slow_slope_indicator()
#SRSI #SRSI
populate_secondary_rsi_indicator() #populate_secondary_rsi_indicator()
#kroky pro CONTINOUS TICKS only #kroky pro CONTINOUS TICKS only
else: else:
#CBAR INDICATOR pro tick price a deltu VOLUME #CBAR INDICATOR pro tick price a deltu VOLUME
populate_cbar_tick_price_indicator() populate_cbar_tick_price_indicator()
populate_cbar_rsi_indicator()
#SPOLECNA LOGIKA - bar indikatory muzeme populovat kazdy tick (dobre pro RT GUI), ale uklada se stejne az pri confirmu #SPOLECNA LOGIKA - bar indikatory muzeme populovat kazdy tick (dobre pro RT GUI), ale uklada se stejne az pri confirmu
@ -628,7 +762,8 @@ def next(data, state: StrategyState):
consolidation() consolidation()
#HLAVNI ITERACNI LOG JESTE PRED AKCI - obsahuje aktualni hodnoty vetsiny parametru #HLAVNI ITERACNI LOG JESTE PRED AKCI - obsahuje aktualni hodnoty vetsiny parametru
lp = state.interface.get_last_price(symbol=state.symbol) #lp = state.interface.get_last_price(symbol=state.symbol)
lp = data['close']
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="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())) state.ilog(e="Indikatory", msg=str(get_last_ind_vals()))
@ -640,7 +775,9 @@ def init(state: StrategyState):
print("INIT v main",state.name) print("INIT v main",state.name)
state.vars['sell_in_progress'] = False state.vars['sell_in_progress'] = False
state.vars.mode = None
state.vars.last_tick_price = 0 state.vars.last_tick_price = 0
state.vars.last_50_deltas = []
state.vars.last_tick_volume = 0 state.vars.last_tick_volume = 0
state.vars.next_new = 0 state.vars.next_new = 0
state.vars.last_buysignal_index = 0 state.vars.last_buysignal_index = 0
@ -649,13 +786,20 @@ def init(state: StrategyState):
#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.secondary_indicators['SRSI'] = [] state.cbar_indicators['CRSI'] = []
#state.secondary_indicators['SRSI'] = []
state.indicators['ema'] = [] state.indicators['ema'] = []
state.indicators['slope'] = [] state.indicators['slope'] = []
state.indicators['slopeMA'] = [] state.indicators['slopeMA'] = []
state.indicators['slow_slope'] = []
state.indicators['slow_slopeMA'] = []
state.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"], maximum_slope=safe_get(state.vars, "bigwave_slope_above",0.20)) state.statinds['angle'] = dict(minimum_slope=state.vars["minimum_slope"], maximum_slope=safe_get(state.vars, "bigwave_slope_above",0.20))
#state.statinds['angle_slow'] = dict(minimum_slope=safe_get(state.vars.indicators.slow_slope, "minimum_slope",-2), maximum_slope=safe_get(state.vars.indicators.slow_slope, "maximum_slope",2))
state.statinds['angle_slow'] = dict(minimum_slope=state.vars['indicators']['slow_slope']["minimum_slope"], maximum_slope=state.vars['indicators']['slow_slope']["maximum_slope"])
state.vars["ticks2reset_backup"] = state.vars.ticks2reset state.vars["ticks2reset_backup"] = state.vars.ticks2reset
def main(): def main():

View File

@ -0,0 +1,599 @@
import os,sys
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from v2realbot.strategy.base import StrategyState
from v2realbot.strategy.StrategyOrderLimitVykladaciNormalizedMYSELL import StrategyOrderLimitVykladaciNormalizedMYSELL
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, is_open_rush, is_close_rush, eval_cond_dict
from datetime import datetime
#from icecream import install, ic
#from rich import print
from threading import Event
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__))))
""""
Využívá: StrategyOrderLimitVykladaciNormalizedMYSELL
Kopie RSI Normalizovane Vykladaci navíc s řízením prodeje.
Nepoužíváme LIMITKU.
Required CBAR. (pouze se změnou ceny)
nepotvrzený CBAR bez minticku (pouze se změnou ceny)
- se používá pro žízení prodeje
potvrzený CBAR
- se používá pro BUY
"""
stratvars = AttributeDict(maxpozic = 400,
def_mode_from = 200,
chunk = 10,
MA = 2,
Trend = 2,
profit = 0.02,
def_profit = 0.01,
lastbuyindex=-6,
pendingbuys={},
limitka = None,
limitka_price = None,
jevylozeno=0,
vykladka=5,
curve = [0.01, 0.01, 0.01, 0, 0.02, 0.02, 0.01,0.01, 0.01,0.03, 0.01, 0.01, 0.01,0.04, 0.01,0.01, 0.01,0.05, 0.01,0.01, 0.01,0.01, 0.06,0.01, 0.01,0.01, 0.01],
curve_def = [0.02, 0.02, 0.02, 0, 0, 0.02, 0, 0, 0, 0.02],
blockbuy = 0,
ticks2reset = 0.04,
consolidation_bar_count = 10,
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 = """
[[strategies]]
name = "V1 na BAC"
symbol = "BAC"
script = "ENTRY_backtest_strategyVykladaci"
class = "StrategyOrderLimitVykladaci"
open_rush = 0
close_rush = 0
[strategies.stratvars]
maxpozic = 200
chunk = 10
MA = 6
Trend = 5
profit = 0.02
lastbuyindex=-6
pendingbuys={}
limitka = "None"
jevylozeno=0
vykladka=5
curve = [0.01, 0.01, 0.01,0.01, 0.02, 0.01,0.01, 0.01,0.03, 0.01, 0.01, 0.01,0.04, 0.01,0.01, 0.01,0.05, 0.01,0.01, 0.01,0.01, 0.06,0.01, 0.01,0.01, 0.01]
blockbuy = 0
ticks2reset = 0.04
[[strategies.add_data]]
symbol="BAC"
rectype="bar"
timeframe=5
update_ltp=true
align="round"
mintick=0
minsize=100
exthours=false
"""
def next(data, state: StrategyState):
print(10*"*","NEXT START",10*"*")
#ic(state.avgp, state.positions)
#ic(state.vars)
#ic(data)
#
def is_defensive_mode():
akt_pozic = int(state.positions)
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)
return True
else:
#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)
#v MYSELL hrajeme i na 3 desetinna cisla - TBD mozna hrat jen na 5ky (0.125, 0.130, 0.135 atp.)
if is_defensive_mode():
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)
if state.vars.jevylozeno == 1 or 1==1:
##CONSOLIDATION PART kazdy Nty bar dle nastaveni
if int(data["index"])%int(state.vars.consolidation_bar_count) == 0:
print("***CONSOLIDATION ENTRY***")
state.ilog(e="CONSOLIDATION ENTRY ***")
orderlist = state.interface.get_open_orders(symbol=state.symbol, side=None)
#pro jistotu jeste dotahneme aktualni pozice
state.avgp, state.positions = state.interface.pos()
#print(orderlist)
pendingbuys_new = {}
#zaciname s cistym stitem
state.vars.limitka = None
state.vars.limitka_price = None
for o in orderlist:
if o.side == OrderSide.BUY and o.order_type == OrderType.LIMIT:
pendingbuys_new[str(o.id)]=float(o.limit_price)
if pendingbuys_new != state.vars.pendingbuys:
state.ilog(e="Rozdilna PB prepsana", pb_new=pendingbuys_new, pb_old = state.vars.pendingbuys)
print("ROZDILNA PENDINGBUYS přepsána")
print("OLD",state.vars.pendingbuys)
state.vars.pendingbuys = unpackb(packb(pendingbuys_new))
print("NEW", state.vars.pendingbuys)
else:
print("PENDINGBUYS sedí - necháváme", state.vars.pendingbuys)
state.ilog(e="PB sedi nechavame", pb_new=pendingbuys_new, pb_old = state.vars.pendingbuys)
print("OLD jevylozeno", state.vars.jevylozeno)
if len(state.vars.pendingbuys) > 0:
state.vars.jevylozeno = 1
else:
state.vars.jevylozeno = 0
print("NEW jevylozeno", state.vars.jevylozeno)
state.ilog(e="Nove jevylozeno", msg=state.vars.jevylozeno)
print("***CONSOLIDATION EXIT***")
state.ilog(e="CONSOLIDATION EXIT ***")
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
#curve = [0.01, 0.01, 0, 0, 0.01, 0, 0, 0, 0.02, 0, 0, 0, 0.03, 0,0,0,0,0, 0.02, 0,0,0,0,0,0, 0.02]
curve = state.vars.curve
##defenzivni krivka pro
curve_def = state.vars.curve_def
#vykladani po 5ti kusech, když zbývají 2 a méně, tak děláme nový výklad
vykladka = state.vars.vykladka
#kolik muzu max vylozit
kolikmuzu = int((int(state.vars.maxpozic) - int(state.positions))/int(state.vars.chunk))
akt_pozic = int(state.positions)
max_pozic = int(state.vars.maxpozic)
if akt_pozic >= max_pozic:
state.ilog(e="MAX pozic reached, cannot vyklad")
return
#mame polovinu a vic vylozeno, pouzivame defenzicni krivku
if is_defensive_mode():
state.ilog(e="DEF: Pouzivame defenzivni krivku", akt_pozic=akt_pozic, max_pozic=max_pozic, curve_def=curve_def)
curve = curve_def
#zaroven docasne menime ticks2reset na defenzivni 0.06
state.vars.ticks2reset = 0.06
state.ilog(e="DEF: Menime tick2reset na 0.06", ticks2reset=state.vars.ticks2reset, ticks2reset_backup=state.vars.ticks2reset_backup)
else:
#vracime zpet, pokud bylo zmeneno
if state.vars.ticks2reset != state.vars.ticks2reset_backup:
state.vars.ticks2reset = state.vars.ticks2reset_backup
state.ilog(e="DEF: Menime tick2reset zpet na"+str(state.vars.ticks2reset), ticks2reset=state.vars.ticks2reset, ticks2reset_backup=state.vars.ticks2reset_backup)
if kolikmuzu < vykladka: vykladka = kolikmuzu
if len(curve) < vykladka:
vykladka = len(curve)
qty = int(state.vars.chunk)
last_price = price2dec(state.interface.get_last_price(state.symbol))
#profit = float(state.vars.profit)
price = last_price
state.ilog(e="BUY Vykladame", msg=f"first price {price=} {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
##VAR - na zaklade conf. muzeme jako prvni posilat MARKET order
if safe_get(state.vars, "first_buy_market") == True:
#pri defenzivnim rezimu pouzivame vzdy LIMIT order
if is_defensive_mode():
state.ilog(e="DEF mode on, odesilame jako prvni limitku")
state.buy_l(price=price, size=qty)
else:
state.ilog(e="Posilame jako prvni MARKET order")
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 - get_tick(price, curve[i])))
if price == last_price:
qty = qty + int(state.vars.chunk)
else:
state.buy_l(price=price, size=qty)
#print(i,"BUY limitka - delta",curve[i]," cena:", price, "mnozstvi:", qty)
qty = int(state.vars.chunk)
last_price = price
state.vars.blockbuy = 1
state.vars.jevylozeno = 1
state.vars.last_buysignal_index = data['index']
def eval_sell():
""""
TBD
Když je RSI nahoře tak neprodávat, dokud 1) RSI neprestane stoupat 2)nedosahne to nad im not greedy limit
"""
##mame pozice
##aktualni cena je vetsi nebo rovna cene limitky
#muzeme zde jet i na pulcenty
curr_price = float(data['close'])
state.ilog(e="Eval SELL", price=curr_price, pos=state.positions, avgp=state.avgp, sell_in_progress=state.vars.sell_in_progress)
if int(state.positions) > 0 and float(state.avgp)>0 and state.vars.sell_in_progress is False:
goal_price = get_limitka_price()
state.ilog(e=f"Goal price {goal_price}")
if curr_price>=goal_price:
#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
#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)
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:
ma = int(state.vars.MA)
#poslednich ma hodnot
source = state.bars.close[-ma:] #state.bars.vwap
ema_value = ema(source, ma)
##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
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
#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, maximum_slope=safe_get(state.vars, "bigwave_slope_above",0.20))
#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())
def populate_rsi_indicator():
#RSI14 INDICATOR
try:
rsi_length = int(safe_get(state.vars, "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 populate_cbar_rsi_indicator():
#CBAR RSI indicator
try:
crsi_length = int(safe_get(state.vars, "crsi_length",14))
source = state.cbar_indicators.tick_price #[-rsi_length:] #state.bars.vwap
crsi_res = rsi(source, crsi_length)
crsi_value = trunc(crsi_res[-1],3)
state.cbar_indicators.CRSI[-1]=crsi_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"CRSI {crsi_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))
#resetujeme, kdyz 1) je aktivni buy protection 2) kdyz to ujede
#TODO mozna tick2reset spoustet jednou za X opakovani
def pendingbuys_optimalization():
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())
if state.interface.get_last_price(state.symbol) > float(maxprice) + get_tick(maxprice, float(state.vars.ticks2reset)):
res = asyncio.run(state.cancel_pending_buys())
state.ilog(e=f"UJELO to. Rusime PB", msg=f"{state.vars.ticks2reset=}", pb=state.vars.pendingbuys)
#PENDING BUYS SPENT - PART
#pokud mame vylozeno a pendingbuys se vyklepou a
# 1 vykladame idned znovu
# vyloz()
# 2 nebo - počkat zase na signál a pokračovat dál
# state.vars.blockbuy = 0
# state.vars.jevylozeno = 0
# 3 nebo - počkat na signál s enablovaným lastbuy indexem (tzn. počká nutně ještě pár barů)
#podle BT vyhodnejsi vylozit ihned
if len(state.vars.pendingbuys) == 0:
state.vars.blockbuy = 0
state.vars.jevylozeno = 0
state.ilog(e="PB prazdne nastavujeme: neni vylozeno", jevylozeno=state.vars.jevylozeno)
##kdy nesmí být žádné nákupní objednávky - zruší se
def buy_protection_enabled():
dont_buy_when = dict(AND=dict(), OR=dict())
##add conditions here
dont_buy_when['rsi_too_high'] = 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
#IDENTIFIKOVAce rustoveho MOMENTA - pokud je momentum, tak prodávat později
#pokud je slope too high, pak prodavame jakmile slopeMA zacne klesat, napr. 4MA (TODO 3)
#toto docasne pryc dont_sell_when['slope_too_high'] = slope_too_high() and not isfalling(state.indicators.slopeMA,4)
dont_sell_when['AND']['slopeMA_rising'] = isrising(state.indicators.slopeMA,2)
dont_sell_when['AND']['rsi_not_falling'] = not isfalling(state.indicators.RSI14,3)
#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())
if safe_get(state.vars, "buy_only_on_confirmed",True):
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['rsi_too_high'] = state.indicators.RSI14[-1] > safe_get(state.vars, "rsi_dont_buy_above",50)
dont_buy_when['slope_too_low'] = slope_too_low()
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)
#slopeMA jde dolu, rsi jde nahoru
#buy mame kazdy potvrzeny, tzn. rsi falling muze byt jen 2
#buy_cond['AND']['slopeMA_falling'] = isfalling(state.indicators.slopeMA,3)
#buy_cond['AND']['rsi_is_rising'] = isrising(state.indicators.RSI14,2)
#buy_cond["AND"]["rsi_buy_signal_below"] = state.indicators.RSI14[-1] < safe_get(state.vars, "rsi_buy_signal_below",40)
#puvodni buy conditiony RSI pod + EMA klesajici
#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)
#pouze RSI nizke a RSI klesa
buy_cond["AND"]["rsi_buy_signal_below"] = state.indicators.RSI14[-1] < safe_get(state.vars, "rsi_buy_signal_below",40)
buy_cond["AND"]["rsi_is_falling"] = isfalling(state.indicators.RSI14,state.vars.Trend)
#buy_cond['crsi_below_crsi_buy_limit'] = state.cbar_indicators.CRSI[-1] < safe_get(state.vars, "crsi_buy_signal_below",30)
#slopME klesa a RSI začalo stoupat
# buy_cond["AND"]["rsi_is_rising2"] = isrising(state.indicators.RSI14,2)
# buy_cond['AND']['slopeMA_falling_Trend'] = isfalling(state.indicators.slopeMA,state.vars.Trend)
# buy_cond["AND"]["rsi_buy_signal_below"] = state.indicators.RSI14[-1] < safe_get(state.vars, "rsi_buy_signal_below",40)
#zkusit jako doplnkovy BUY SIGNAL 3 klesavy cbar RSI pripadne TICK PRICE
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']
last_update_delta = round((float(data['updated']) - state.vars.last_update_time),6) if state.vars.last_update_time != 0 else 0
state.vars.last_update_time = float(data['updated'])
state.ilog(e=f"---{data['index']}-{conf_bar}--delta:{last_update_delta}")
#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()
populate_cbar_rsi_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
print("INIT v main",state.name)
state.vars['sell_in_progress'] = False
state.vars.last_tick_price = 0
state.vars.last_tick_volume = 0
state.vars.next_new = 0
state.vars.last_buysignal_index = 0
state.vars.last_update_time = 0
#state.cbar_indicators['ivwap'] = []
state.cbar_indicators['tick_price'] = []
state.cbar_indicators['tick_volume'] = []
state.cbar_indicators['CRSI'] = []
state.indicators['ema'] = []
state.indicators['slope'] = []
state.indicators['slopeMA'] = []
state.indicators['RSI14'] = []
#static indicators - those not series based
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():
name = os.path.basename(__file__)
se = Event()
pe = Event()
s = StrategyOrderLimitVykladaciNormalizedMYSELL(name = name, symbol = "BAC", account=Account.ACCOUNT1, next=next, init=init, stratvars=stratvars, open_rush=10, close_rush=0, pe=pe, se=se, ilog_save=True)
s.set_mode(mode = Mode.BT,
debug = False,
start = datetime(2023, 4, 14, 10, 42, 0, 0, tzinfo=zoneNY),
end = datetime(2023, 4, 14, 14, 35, 0, 0, tzinfo=zoneNY),
cash=100000)
#na sekundovem baru nezaokrouhlovat MAcko
s.add_data(symbol="BAC",rectype=RecordType.BAR,timeframe=2,minsize=100,update_ltp=True,align=StartBarAlign.ROUND,mintick=0, exthours=False)
#s.add_data(symbol="C",rectype=RecordType.BAR,timeframe=1,filters=None,update_ltp=True,align=StartBarAlign.ROUND,mintick=0)
s.start()
print("zastavujeme")
if __name__ == "__main__":
main()

View File

@ -181,7 +181,7 @@ class Backtester:
todel.append(order) todel.append(order)
changes = 1 changes = 1
else: else:
print("NOT EXECUTED {a}") print(f"NOT EXECUTED {a}")
#ic("NOT EXECUTED",a) #ic("NOT EXECUTED",a)
##ic("istodel",todel) ##ic("istodel",todel)
#vymazu z pending orderu vschny zprocesovane nebo ty na výmaz #vymazu z pending orderu vschny zprocesovane nebo ty na výmaz
@ -317,7 +317,7 @@ class Backtester:
return -1 return -1
if not fill_time: if not fill_time:
#ic("not FILLED") print("not FILLED")
return 0 return 0
else: else:

View File

@ -2,6 +2,8 @@ from alpaca.data.enums import DataFeed
from v2realbot.enums.enums import Mode, Account, FillCondition from v2realbot.enums.enums import Mode, Account, FillCondition
from appdirs import user_data_dir from appdirs import user_data_dir
#minimalni vzdalenost mezi trady, kterou agregator pousti pro CBAR(0.001 - blokuje mensi nez 1ms)
AGG_MIN_TRADE_DELTA = 0.003
#normalized price for tick 0.01 #normalized price for tick 0.01
NORMALIZED_TICK_BASE_PRICE = 30.00 NORMALIZED_TICK_BASE_PRICE = 30.00
LOG_RUNNER_EVENTS = False LOG_RUNNER_EVENTS = False
@ -20,6 +22,8 @@ BT_FILL_LOG_SURROUNDING_TRADES = 10
# slow - price has to be bigger < # slow - price has to be bigger <
BT_FILL_CONDITION_BUY_LIMIT = FillCondition.SLOW BT_FILL_CONDITION_BUY_LIMIT = FillCondition.SLOW
BT_FILL_CONDITION_SELL_LIMIT = FillCondition.SLOW BT_FILL_CONDITION_SELL_LIMIT = FillCondition.SLOW
#TBD TODO not implemented yet
BT_FILL_PRICE_MARKET_ORDER_PREMIUM = 0.005
#backend counter of api requests #backend counter of api requests
COUNT_API_REQUESTS = False COUNT_API_REQUESTS = False
#stratvars that cannot be changed in gui #stratvars that cannot be changed in gui

View File

@ -11,7 +11,7 @@ from v2realbot.utils.utils import AttributeDict, zoneNY, dict_replace_value, Sto
from v2realbot.utils.ilog import delete_logs from v2realbot.utils.ilog import delete_logs
from datetime import datetime from datetime import datetime
from threading import Thread, current_thread, Event, enumerate from threading import Thread, current_thread, Event, enumerate
from v2realbot.config import STRATVARS_UNCHANGEABLES, ACCOUNT1_LIVE_API_KEY, ACCOUNT1_LIVE_SECRET_KEY, DATA_DIR,BT_FILL_CONS_TRADES_REQUIRED,BT_FILL_LOG_SURROUNDING_TRADES,BT_FILL_CONDITION_BUY_LIMIT,BT_FILL_CONDITION_SELL_LIMIT from v2realbot.config import STRATVARS_UNCHANGEABLES, ACCOUNT1_LIVE_API_KEY, ACCOUNT1_LIVE_SECRET_KEY, DATA_DIR,BT_FILL_CONS_TRADES_REQUIRED,BT_FILL_LOG_SURROUNDING_TRADES,BT_FILL_CONDITION_BUY_LIMIT,BT_FILL_CONDITION_SELL_LIMIT, AGG_MIN_TRADE_DELTA
import importlib import importlib
from queue import Queue from queue import Queue
from tinydb import TinyDB, Query, where from tinydb import TinyDB, Query, where
@ -436,10 +436,14 @@ def populate_metrics_output_directory(strat: StrategyInstance):
trade_dict.qty.append(t.qty) trade_dict.qty.append(t.qty)
trade_dict.price.append(t.price) trade_dict.price.append(t.price)
trade_dict.position_qty.append(t.position_qty) trade_dict.position_qty.append(t.position_qty)
trade_dict.value.append(t.value)
trade_dict.cash.append(t.cash)
trade_dict.order_type.append(t.order.order_type) trade_dict.order_type.append(t.order.order_type)
trade_dict.pos_avg_price.append(t.pos_avg_price) #backtest related additional attributtes, not present on LIVE
try:
trade_dict.value.append(t.value)
trade_dict.cash.append(t.cash)
trade_dict.pos_avg_price.append(t.pos_avg_price)
except Exception:
pass
trade_df = pd.DataFrame(trade_dict) trade_df = pd.DataFrame(trade_dict)
trade_df = trade_df.set_index('timestamp',drop=False) trade_df = trade_df.set_index('timestamp',drop=False)
@ -470,6 +474,7 @@ def archive_runner(runner: Runner, strat: StrategyInstance):
settings = dict(resolution=strat.state.timeframe, settings = dict(resolution=strat.state.timeframe,
rectype=strat.state.rectype, rectype=strat.state.rectype,
configs=dict( configs=dict(
AGG_MIN_TRADE_DELTA=AGG_MIN_TRADE_DELTA,
BT_FILL_CONS_TRADES_REQUIRED=BT_FILL_CONS_TRADES_REQUIRED, BT_FILL_CONS_TRADES_REQUIRED=BT_FILL_CONS_TRADES_REQUIRED,
BT_FILL_LOG_SURROUNDING_TRADES=BT_FILL_LOG_SURROUNDING_TRADES, BT_FILL_LOG_SURROUNDING_TRADES=BT_FILL_LOG_SURROUNDING_TRADES,
BT_FILL_CONDITION_BUY_LIMIT=BT_FILL_CONDITION_BUY_LIMIT, BT_FILL_CONDITION_BUY_LIMIT=BT_FILL_CONDITION_BUY_LIMIT,
@ -527,16 +532,16 @@ def archive_runner(runner: Runner, strat: StrategyInstance):
#print("is not numpy", key, value) #print("is not numpy", key, value)
flattened_indicators[key]= value flattened_indicators[key]= value
flattened_indicators_list.append(flattened_indicators) flattened_indicators_list.append(flattened_indicators)
flattened_indicators = {} # flattened_indicators = {}
for key, value in strat.state.secondary_indicators.items(): # for key, value in strat.state.secondary_indicators.items():
if isinstance(value, ndarray): # if isinstance(value, ndarray):
#print("is numpy", key,value) # #print("is numpy", key,value)
flattened_indicators[key]= value.tolist() # flattened_indicators[key]= value.tolist()
#print("changed numpy:",value.tolist()) # #print("changed numpy:",value.tolist())
else: # else:
#print("is not numpy", key, value) # #print("is not numpy", key, value)
flattened_indicators[key]= value # flattened_indicators[key]= value
flattened_indicators_list.append(flattened_indicators) # flattened_indicators_list.append(flattened_indicators)
runArchiveDetail: RunArchiveDetail = RunArchiveDetail(id = runner.id, runArchiveDetail: RunArchiveDetail = RunArchiveDetail(id = runner.id,
name=runner.run_name, name=runner.run_name,

View File

@ -11,7 +11,7 @@ import threading
from copy import deepcopy from copy import deepcopy
from msgpack import unpackb from msgpack import unpackb
import os import os
from config import DATA_DIR from config import DATA_DIR, AGG_MIN_TRADE_DELTA
class TradeAggregator: class TradeAggregator:
def __init__(self, def __init__(self,
@ -66,6 +66,7 @@ class TradeAggregator:
self.barindex = 1 self.barindex = 1
self.diff_price = True self.diff_price = True
self.preconfBar = {} self.preconfBar = {}
self.trades_too_close = False
async def ingest_trade(self, indata, symbol): async def ingest_trade(self, indata, symbol):
""" """
@ -244,6 +245,11 @@ class TradeAggregator:
self.diff_price = True self.diff_price = True
self.last_price = data['p'] self.last_price = data['p']
if float(data['t']) - float(self.lasttimestamp) < AGG_MIN_TRADE_DELTA:
self.trades_too_close = True
else:
self.trades_too_close = False
#spočteme vwap - potřebujeme předchozí hodnoty #spočteme vwap - potřebujeme předchozí hodnoty
self.vwaphelper += (data['p'] * data['s']) self.vwaphelper += (data['p'] * data['s'])
self.newBar['updated'] = data['t'] self.newBar['updated'] = data['t']
@ -333,7 +339,16 @@ class TradeAggregator:
#print(self.newBar) #print(self.newBar)
#pro (nepotvrzeny) cbar vracime jen pri zmene ceny #pro (nepotvrzeny) cbar vracime jen pri zmene ceny
if self.diff_price is True:
#nevracime pokud predchozi timestamp a novy od sebe nema alespon 1 ms (vyhneme se kulometum)
#127788.123000 127788.124000 (rozdil 0.001)
#zkousime pustit i stejnou cenu(potrebujeme kvuli MYSELLU), ale blokoval kulomet,tzn. trady mensi nez AGG_MIN_TRADE_DELTA (1ms)
#if self.diff_price is True:
#pripadne jeste vratit jako subpodminkiu
if self.trades_too_close is False:
return [self.newBar] return [self.newBar]
else: else:
return [] return []

View File

@ -259,19 +259,24 @@ function chart_archived_run(archRecord, data, oneMinuteBars) {
intitialize_candles() intitialize_candles()
candlestickSeries.setData(AllCandleSeriesesData.get(interval)); candlestickSeries.setData(AllCandleSeriesesData.get(interval));
remove_indicators();
btnElement = document.getElementById("indicatorsButtons")
if (btnElement) {
container1.removeChild(btnElement);
}
if (interval == native_resolution) { if (interval == native_resolution) {
//indicators are in native resolution only //indicators are in native resolution only
display_indicators(data); display_indicators(data, true);
var indbuttonElement = populate_indicator_buttons(); var indbuttonElement = populate_indicator_buttons(true);
container1.append(indbuttonElement);
} }
else { else {
remove_indicators(); //na nepuvodnim grafu zobrazit jako offset a zobrazit jako neviditelne
btnElement = document.getElementById("indicatorsButtons") display_indicators(data,false,30)
if (btnElement) { //buttonky jako vypnute
container1.removeChild(btnElement); var indbuttonElement = populate_indicator_buttons(false);
}
} }
container1.append(indbuttonElement);
display_buy_markers(); display_buy_markers();
@ -284,7 +289,8 @@ function chart_archived_run(archRecord, data, oneMinuteBars) {
//pro kazdy identifikator zobrazime button na vypnuti zapnuti //pro kazdy identifikator zobrazime button na vypnuti zapnuti
//vybereme barvu pro kazdy identifikator //vybereme barvu pro kazdy identifikator
//zjistime typ idenitfikatoru - zatim right vs left //zjistime typ idenitfikatoru - zatim right vs left
function display_indicators(data) { // input: data, offset(zobrazovat pouze hodnoty kazdych N sekund, visible)
function display_indicators(data, visible, offset) {
//console.log("indikatory", JSON.stringify(data.indicators,null,2)) //console.log("indikatory", JSON.stringify(data.indicators,null,2))
//podobne v livewebsokcets.js - dat do jedne funkce //podobne v livewebsokcets.js - dat do jedne funkce
if (data.hasOwnProperty("indicators")) { if (data.hasOwnProperty("indicators")) {
@ -331,6 +337,16 @@ 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]
//pokud je nastaveny offset (zobrazujeme pouze bod vzdaleny N sekund od posledniho)
//vynechavame prvni iteraci, aby se nam naplnil last_time
if (offset && last_time !==0) {
if (last_time + offset > time) {
return;
}
}
if (last_time>=time) { if (last_time>=time) {
console.log(key, "problem v case - zarovnano",time, last_time, element) console.log(key, "problem v case - zarovnano",time, last_time, element)
@ -437,6 +453,7 @@ function chart_archived_run(archRecord, data, oneMinuteBars) {
//add options //add options
obj.series.applyOptions({ obj.series.applyOptions({
visible: visible,
lastValueVisible: false, lastValueVisible: false,
priceLineVisible: false, priceLineVisible: false,
}); });
@ -456,19 +473,21 @@ function chart_archived_run(archRecord, data, oneMinuteBars) {
} }
}) })
} }
//vwap a volume zatim jen v detailnim zobrazeni
if (!offset) {
//display vwap and volume
initialize_vwap()
vwapSeries.setData(transformed_data["vwap"])
//display vwap and volume initialize_volume()
initialize_vwap() volumeSeries.setData(transformed_data["volume"])
vwapSeries.setData(transformed_data["vwap"]) console.log("volume")
}
initialize_volume()
volumeSeries.setData(transformed_data["volume"])
console.log("volume")
} }
function remove_indicators() { function remove_indicators() {
//reset COLORS //reset COLORS
colors = reset_colors colors = reset_colors.slice()
//remove CUSTOMS indicators if exists //remove CUSTOMS indicators if exists
indList.forEach((element, index, array) => { indList.forEach((element, index, array) => {
@ -479,9 +498,11 @@ function chart_archived_run(archRecord, data, oneMinuteBars) {
//remove BASIC indicators //remove BASIC indicators
if (vwapSeries) { if (vwapSeries) {
chart.removeSeries(vwapSeries) chart.removeSeries(vwapSeries)
vwapSeries = null;
} }
if (volumeSeries) { if (volumeSeries) {
chart.removeSeries(volumeSeries) chart.removeSeries(volumeSeries)
volumeSeries = null;
} }
} }

View File

@ -71,16 +71,15 @@ $(document).ready(function () {
// record2.history = ""; // record2.history = "";
//jsonString2 = JSON.stringify(record2, null, 2); //jsonString2 = JSON.stringify(record2, null, 2);
$('#diff_first').text(record1.name);
document.getElementById('first').innerHTML = '<pre>'+JSON.stringify(record1, null, 2)+'</pre>' $('#diff_second').text(record2.name);
$('#diff_first').text(record1.name);
$('#diff_second').text(record2.name);
//mozna parse?
var delta = compareObjects(record1, record2) var delta = compareObjects(record1, record2)
const htmlMarkup1 = `<pre>{\n${generateHTML(record2, delta)}}\n</pre>`; const htmlMarkup2 = `<pre>{\n${generateHTML(record2, delta)}}\n</pre>`;
document.getElementById('second').innerHTML = htmlMarkup1; document.getElementById('second').innerHTML = htmlMarkup2;
const htmlMarkup1 = `<pre>{\n${generateHTML(record1, delta)}}\n</pre>`;
document.getElementById('first').innerHTML = htmlMarkup1;
event.preventDefault(); event.preventDefault();
//$('#button_compare').attr('disabled','disabled'); //$('#button_compare').attr('disabled','disabled');

View File

@ -5,6 +5,7 @@ var logcnt = 0
var positionsPriceLine = null var positionsPriceLine = null
var limitkaPriceLine = null var limitkaPriceLine = null
var angleSeries = 1 var angleSeries = 1
var angleSeries_slow = 1
var cbar = false var cbar = false
//get details of runner to populate chart status //get details of runner to populate chart status
@ -54,7 +55,7 @@ function connect(event) {
ws.onmessage = function(event) { ws.onmessage = function(event) {
var parsed_data = JSON.parse(event.data) var parsed_data = JSON.parse(event.data)
console.log(JSON.stringify(parsed_data)) //console.log(JSON.stringify(parsed_data))
// //check received data and display lines // //check received data and display lines
// if (parsed_data.hasOwnProperty("bars")) { // if (parsed_data.hasOwnProperty("bars")) {
@ -238,6 +239,34 @@ function connect(event) {
angleSeries.setData(dataPoints) angleSeries.setData(dataPoints)
} }
} }
if (klic === "angle_slow") {
//nejsou vsechny hodnoty
if (Object.keys(hodnota).length > 2) {
// console.log("angle nalezen");
// console.log(JSON.stringify(hodnota));
if (angleSeries_slow !== 1) {
// console.log("angle neni jedna" + toString(angleSeries))
chart.removeSeries(angleSeries_slow)
}
angleSeries_slow = chart.addLineSeries({
//title: key,
lineWidth: 2,
lineStyle: 2,
color: "#8c52c7",
lastValueVisible: false,
priceLineVisible: false,
priceLineWidth: 0,
priceLineStyle: 3
})
dataPoints = [{time: hodnota.lookbacktime, value: hodnota.lookbackprice},{ time: hodnota.time, value: hodnota.price}]
// console.log("pridano")
// console.log(toString(dataPoints))
angleSeries_slow.setData(dataPoints)
}
}
} }

View File

@ -312,13 +312,17 @@ $(document).ready(function () {
//jsonString2 = JSON.stringify(rec2, null, 2); //jsonString2 = JSON.stringify(rec2, null, 2);
document.getElementById('first').innerHTML = '<pre>'+JSON.stringify(rec1, null, 2)+'</pre>' //document.getElementById('first').innerHTML = '<pre>'+JSON.stringify(rec1, null, 2)+'</pre>'
$('#diff_first').text(rec1.name); $('#diff_first').text(rec1.name);
$('#diff_second').text(rec2.name); $('#diff_second').text(rec2.name);
var delta = compareObjects(rec1, rec2) var delta = compareObjects(rec1, rec2)
const htmlMarkup = `<pre>{\n${generateHTML(rec2, delta)}}\n</pre>`; const htmlMarkup2 = `<pre>{\n${generateHTML(rec2, delta)}}\n</pre>`;
document.getElementById('second').innerHTML = htmlMarkup; document.getElementById('second').innerHTML = htmlMarkup2;
//var delta1 = compareObjects(rec2, rec1)
const htmlMarkup1 = `<pre>{\n${generateHTML(rec1, delta)}}\n</pre>`;
document.getElementById('first').innerHTML = htmlMarkup1;
event.preventDefault(); event.preventDefault();
//$('#button_compare').attr('disabled','disabled'); //$('#button_compare').attr('disabled','disabled');

View File

@ -1,8 +1,8 @@
API_KEY = localStorage.getItem("api-key") API_KEY = localStorage.getItem("api-key")
var chart = null var chart = null
var colors = ["#8B1874","#B71375","#B46060","#61c740","#BE6DB7","#898121","#4389d9","#00425A","#B5D5C5","#e61957"] var colors = ["#8B1874","#B71375","#B46060","#61c740","#BE6DB7","#898121","#4389d9","#00425A","#B5D5C5","#e61957","#8B1874","#B71375","#B46060","#61c740","#BE6DB7","#898121","#4389d9","#00425A","#B5D5C5","#e61957"]
var reset_colors = colors var reset_colors = ["#8B1874","#B71375","#B46060","#61c740","#BE6DB7","#898121","#4389d9","#00425A","#B5D5C5","#e61957","#8B1874","#B71375","#B46060","#61c740","#BE6DB7","#898121","#4389d9","#00425A","#B5D5C5","#e61957"]
var indList = [] var indList = []
var verticalSeries=null var verticalSeries=null
var candlestickSeries = null var candlestickSeries = null
@ -27,10 +27,12 @@ indConfig = [ {name: "ema", titlevisible: false, embed: true, display: true, pri
{name: "ivwap", titlevisible: true, embed: true, display: false, priceScaleId: "right", lastValueVisible: false}, {name: "ivwap", titlevisible: true, embed: true, display: false, priceScaleId: "right", lastValueVisible: false},
{name: "slope", titlevisible: true, embed: true, display: false, priceScaleId: "middle", lastValueVisible: false}, {name: "slope", titlevisible: true, embed: true, display: false, priceScaleId: "middle", lastValueVisible: false},
{name: "slopeMA", titlevisible: true, embed: true, display: true, priceScaleId: "middle", lastValueVisible: false}, {name: "slopeMA", titlevisible: true, embed: true, display: true, priceScaleId: "middle", lastValueVisible: false},
{name: "slow_slope", titlevisible: true, embed: true, display: false, priceScaleId: "middle", lastValueVisible: false},
{name: "slow_slopeMA", titlevisible: true, embed: true, display: true, priceScaleId: "middle", lastValueVisible: false},
{name: "emaSlow", titlevisible: true, embed: true, display: true, priceScaleId: "right", lastValueVisible: false}, {name: "emaSlow", titlevisible: true, embed: true, display: true, priceScaleId: "right", lastValueVisible: false},
{name: "emaFast", titlevisible: true, embed: true, display: true, priceScaleId: "right", lastValueVisible: false}, {name: "emaFast", titlevisible: true, embed: true, display: true, priceScaleId: "right", lastValueVisible: false},
{name: "RSI14", titlevisible: true, embed: true, display: true, priceScaleId: "left", lastValueVisible: false}, {name: "RSI14", titlevisible: true, embed: true, display: true, priceScaleId: "left", lastValueVisible: false},
{name: "SRSI", titlevisible: true, embed: true, display: true, priceScaleId: "left", lastValueVisible: false}, {name: "CRSI", titlevisible: true, embed: true, display: true, priceScaleId: "left", lastValueVisible: false},
{name: "aroon", titlevisible: true, embed: true, display: true, priceScaleId: "left", lastValueVisible: false}, {name: "aroon", titlevisible: true, embed: true, display: true, priceScaleId: "left", lastValueVisible: false},
{name: "apo", titlevisible: true, embed: true, display: true, priceScaleId: "left", lastValueVisible: false}, {name: "apo", titlevisible: true, embed: true, display: true, priceScaleId: "left", lastValueVisible: false},
{name: "ppo", titlevisible: true, embed: true, display: true, priceScaleId: "left", lastValueVisible: false}, {name: "ppo", titlevisible: true, embed: true, display: true, priceScaleId: "left", lastValueVisible: false},
@ -294,7 +296,7 @@ function initialize_vwap() {
} }
function populate_indicator_buttons() { function populate_indicator_buttons(def) {
var buttonElement = document.createElement('div'); var buttonElement = document.createElement('div');
buttonElement.id = "indicatorsButtons" buttonElement.id = "indicatorsButtons"
buttonElement.classList.add('switcher'); buttonElement.classList.add('switcher');
@ -305,7 +307,9 @@ function populate_indicator_buttons() {
itemEl.id = "IND"+index; itemEl.id = "IND"+index;
itemEl.style.color = item.series.options().color; itemEl.style.color = item.series.options().color;
itemEl.classList.add('switcher-item'); itemEl.classList.add('switcher-item');
if (def) {
itemEl.classList.add('switcher-active-item'); itemEl.classList.add('switcher-active-item');
}
itemEl.addEventListener('click', function() { itemEl.addEventListener('click', function() {
onItemClicked1(index); onItemClicked1(index);
}); });
@ -464,9 +468,15 @@ Mousetrap.bind('x', function() {
// for (let key in obj1) { // for (let key in obj1) {
// if (typeof obj1[key] === 'object' && typeof obj2[key] === 'object') { // if (typeof obj1[key] === 'object' && typeof obj2[key] === 'object') {
// const nestedDiff = compareObjects(obj1[key], obj2[key]); // if (Array.isArray(obj1[key]) && Array.isArray(obj2[key])) {
// if (Object.keys(nestedDiff).length > 0) { // if (!arraysAreEqual(obj1[key], obj2[key])) {
// diff[key] = nestedDiff; // diff[key] = obj2[key];
// }
// } else {
// const nestedDiff = compareObjects(obj1[key], obj2[key]);
// if (Object.keys(nestedDiff).length > 0) {
// diff[key] = nestedDiff;
// }
// } // }
// } else if (obj1[key] !== obj2[key]) { // } else if (obj1[key] !== obj2[key]) {
// diff[key] = obj2[key]; // diff[key] = obj2[key];
@ -476,52 +486,42 @@ Mousetrap.bind('x', function() {
// return diff; // return diff;
// } // }
// function generateHTML(obj, diff, indent = '') {
// let html = '';
// for (let key in obj) {
// const value = obj[key];
// if (typeof value === 'object' && value !== null) {
// const nestedDiff = diff[key] || {};
// const nestedIndent = indent + ' ';
// html += `${indent}"${key}": {\n${generateHTML(value, nestedDiff, nestedIndent)}${indent}},\n`;
// } else {
// if (key in diff) {
// html += `${indent}"${key}": <span class="highlighted">${JSON.stringify(value)}</span>,\n`;
// } else {
// html += `${indent}"${key}": ${JSON.stringify(value)},\n`;
// }
// }
// }
// return html;
// }
function compareObjects(obj1, obj2) { function compareObjects(obj1, obj2) {
const diff = {}; const diff = {};
for (let key in obj1) { for (let key in obj1) {
if (typeof obj1[key] === 'object' && typeof obj2[key] === 'object') { if (!(key in obj2)) {
if (Array.isArray(obj1[key]) && Array.isArray(obj2[key])) { diff[key] = obj1[key];
if (!arraysAreEqual(obj1[key], obj2[key])) { continue;
diff[key] = obj2[key]; }
}
} else { if (typeof obj1[key] === 'object' && typeof obj2[key] === 'object') {
const nestedDiff = compareObjects(obj1[key], obj2[key]); if (Array.isArray(obj1[key]) && Array.isArray(obj2[key])) {
if (Object.keys(nestedDiff).length > 0) { if (!arraysAreEqual(obj1[key], obj2[key])) {
diff[key] = nestedDiff; diff[key] = obj2[key];
} }
} } else {
} else if (obj1[key] !== obj2[key]) { const nestedDiff = compareObjects(obj1[key], obj2[key]);
diff[key] = obj2[key]; if (Object.keys(nestedDiff).length > 0) {
} diff[key] = nestedDiff;
}
}
} else if (obj1[key] !== obj2[key]) {
diff[key] = obj2[key];
} }
return diff;
} }
for (let key in obj2) {
if (!(key in obj1)) {
diff[key] = obj2[key];
}
}
return diff;
}
function arraysAreEqual(arr1, arr2) { function arraysAreEqual(arr1, arr2) {
if (arr1.length !== arr2.length) { if (arr1.length !== arr2.length) {
return false; return false;

View File

@ -192,55 +192,55 @@ class Strategy:
#pokud jsou nastaveny secondary - zatím skrz stratvars - pripadne do do API #pokud jsou nastaveny secondary - zatím skrz stratvars - pripadne do do API
#zatim jedno, predelat pak na list #zatim jedno, predelat pak na list
if safe_get(self.state.vars, "secondary_timeframe",None): # if safe_get(self.state.vars, "secondary_timeframe",None):
self.process_secondary_indicators(item) # self.process_secondary_indicators(item)
#tady jsem skoncil # #tady jsem skoncil
def process_secondary_indicators(self, item): # def process_secondary_indicators(self, item):
#toto je voláno každý potvrzený CBAR # #toto je voláno každý potvrzený CBAR
resolution = int(safe_get(self.state.vars, "secondary_timeframe",10)) # resolution = int(safe_get(self.state.vars, "secondary_timeframe",10))
if int(item['resolution']) >= int(resolution) or int(resolution) % int(item['resolution']) != 0: # if int(item['resolution']) >= int(resolution) or int(resolution) % int(item['resolution']) != 0:
self.state.ilog(e=f"Secondary res {resolution} must be higher than main resolution {item['resolution']} a jejim delitelem") # self.state.ilog(e=f"Secondary res {resolution} must be higher than main resolution {item['resolution']} a jejim delitelem")
#prvni vytvori pocatecni # #prvni vytvori pocatecni
if safe_get(self.secondary_res_start_time, resolution, None) is None: # if safe_get(self.secondary_res_start_time, resolution, None) is None:
self.secondary_res_start_time[resolution] = item['time'] # self.secondary_res_start_time[resolution] = item['time']
self.secondary_res_start_index[resolution] = int(item['index']) # self.secondary_res_start_index[resolution] = int(item['index'])
self.state.ilog(e=f"INIT SECINDS {self.secondary_res_start_time[resolution]=} {self.secondary_res_start_index[resolution]=}") # self.state.ilog(e=f"INIT SECINDS {self.secondary_res_start_time[resolution]=} {self.secondary_res_start_index[resolution]=}")
start_timestamp = datetime.timestamp(self.secondary_res_start_time[resolution]) # start_timestamp = datetime.timestamp(self.secondary_res_start_time[resolution])
self.state.ilog(e=f"SECINDS EVAL", start_time=start_timestamp,start_time_plus=start_timestamp + resolution, aktual=datetime.timestamp(item['time'])) # self.state.ilog(e=f"SECINDS EVAL", start_time=start_timestamp,start_time_plus=start_timestamp + resolution, aktual=datetime.timestamp(item['time']))
#pokud uz jsme prekrocili okno, ukladame hodnotu # #pokud uz jsme prekrocili okno, ukladame hodnotu
if start_timestamp + resolution <= datetime.timestamp(item['time']): # if start_timestamp + resolution <= datetime.timestamp(item['time']):
self.state.ilog(e=f"SECINDS okno prekroceno") # self.state.ilog(e=f"SECINDS okno prekroceno")
index_from = self.secondary_res_start_index[resolution] - int(item['index']) -1 # index_from = self.secondary_res_start_index[resolution] - int(item['index']) -1
#vytvorime cas a vyplnime data # #vytvorime cas a vyplnime data
for key in self.state.secondary_indicators: # for key in self.state.secondary_indicators:
if key == 'time': # if key == 'time':
#nastavujeme aktualni cas # #nastavujeme aktualni cas
self.state.secondary_indicators['time'].append(item['time']) # self.state.secondary_indicators['time'].append(item['time'])
#self.state.secondary_indicators['time'].append(self.secondary_res_start_time[resolution] ) # #self.state.secondary_indicators['time'].append(self.secondary_res_start_time[resolution] )
#pro cenu vyplnime aktualni cenou, pro ostatni 0 # #pro cenu vyplnime aktualni cenou, pro ostatni 0
elif key == 'sec_price': # elif key == 'sec_price':
#do ceny dame ceny v tomto okne # #do ceny dame ceny v tomto okne
source = self.state.bars['vwap'] # source = self.state.bars['vwap']
#source = self.state.bars['close'] # #source = self.state.bars['close']
self.state.ilog(e=f"SECINDS pocitame z hodnot", hodnty=source[index_from:]) # self.state.ilog(e=f"SECINDS pocitame z hodnot", hodnty=source[index_from:])
self.state.secondary_indicators[key].append(Average(self.state.bars['close'][index_from:])) # self.state.secondary_indicators[key].append(Average(self.state.bars['close'][index_from:]))
else: # else:
self.state.secondary_indicators[key].append(0) # self.state.secondary_indicators[key].append(0)
self.state.ilog(e="SECIND populated", sec_price=self.state.secondary_indicators['sec_price'][-5:]) # self.state.ilog(e="SECIND populated", sec_price=self.state.secondary_indicators['sec_price'][-5:])
#priprava start hodnot pro dalsi iteraci # #priprava start hodnot pro dalsi iteraci
self.secondary_res_start_time[resolution] = item['time'] # self.secondary_res_start_time[resolution] = item['time']
self.secondary_res_start_index[resolution] = int(item['index']) # self.secondary_res_start_index[resolution] = int(item['index'])
""""refresh positions and avgp - for CBAR once per confirmed, for BARS each time""" """"refresh positions and avgp - for CBAR once per confirmed, for BARS each time"""
@ -493,12 +493,12 @@ class Strategy:
except IndexError: except IndexError:
pass pass
#secondaries #secondaries
if len(self.state.secondary_indicators) > 0 and item['confirmed'] == 1: # if len(self.state.secondary_indicators) > 0 and item['confirmed'] == 1:
for key, value in self.state.secondary_indicators.items(): # for key, value in self.state.secondary_indicators.items():
try: # try:
rt_out["indicators"][key]= value[-1] # rt_out["indicators"][key]= value[-1]
except IndexError: # except IndexError:
pass # pass
#same for static indicators #same for static indicators
if len(self.state.statinds) > 0: if len(self.state.statinds) > 0:
@ -635,7 +635,7 @@ class StrategyState:
self.indicators = AttributeDict(time=[]) self.indicators = AttributeDict(time=[])
self.cbar_indicators = AttributeDict(time=[]) self.cbar_indicators = AttributeDict(time=[])
#secondary timeframe indicators #secondary timeframe indicators
self.secondary_indicators = AttributeDict(time=[], sec_price=[]) #self.secondary_indicators = AttributeDict(time=[], sec_price=[])
self.statinds = AttributeDict() self.statinds = AttributeDict()
#these methods can be overrided by StrategyType (to add or alter its functionality) #these methods can be overrided by StrategyType (to add or alter its functionality)
self.buy = self.interface.buy self.buy = self.interface.buy