retreat commit

This commit is contained in:
David Brázda
2023-10-09 09:15:52 +02:00
parent a6678f9a4f
commit be93c17848
93 changed files with 16821 additions and 2561 deletions

View File

@ -0,0 +1,594 @@
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__))))
""""
MYSELL, CBAR
Rychloobratka KLARA
- profit 0.005
- buy signal nejspis RSI, cilem co nejvic obchodu - rychle ven
"""
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

@ -0,0 +1,487 @@
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.StrategyOrderLimitVykladaci import StrategyOrderLimitVykladaci
from v2realbot.enums.enums import RecordType, StartBarAlign, Mode, Account, OrderSide, OrderType
from v2realbot.indicators.indicators import ema
from v2realbot.indicators.oscillators import rsi, stochastic_oscillator, stochastic_rsi, absolute_price_oscillator, percentage_price_oscillator
from v2realbot.utils.utils import ltp, isrising, isfalling,trunc,AttributeDict, zoneNY, price2dec, print, safe_get
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
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")
if def_mode_from == None: 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")
if def_profit == None: def_profit = state.vars.profit
if is_defensive_mode():
return price2dec(float(state.avgp)+float(def_profit))
else:
return price2dec(float(state.avgp)+float(state.vars.profit))
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 = {}
limitka_old = state.vars.limitka
#print("Puvodni LIMITKA", limitka_old)
#zaciname s cistym stitem
state.vars.limitka = None
state.vars.limitka_price = None
limitka_found = False
limitka_qty = 0
limitka_filled_qty = 0
for o in orderlist:
if o.side == OrderSide.SELL:
if limitka_found:
state.ilog(e="nalezeno vicero sell objednavek, bereme prvni, ostatni - rusime")
result=state.interface.cancel(o.id)
state.ilog(e="zrusena objednavka"+str(o.id), message=result)
continue
#print("Nalezena LIMITKA")
limitka_found = True
state.vars.limitka = o.id
state.vars.limitka_price = o.limit_price
limitka_qty = int(o.qty)
limitka_filled_qty = int(o.filled_qty)
#aktualni mnozstvi = puvodni minus filled
if limitka_filled_qty is not None:
print("prepocitavam filledmnozstvi od limitka_qty a filled_qty", limitka_qty, limitka_filled_qty)
limitka_qty = int(limitka_qty) - int(limitka_filled_qty)
##TODO sem pridat upravu ceny
if o.side == OrderSide.BUY and o.order_type == OrderType.LIMIT:
pendingbuys_new[str(o.id)]=float(o.limit_price)
state.ilog(e="Konzolidace limitky", msg=f"stejna:{(str(limitka_old)==str(state.vars.limitka))}", limitka_old=str(limitka_old), limitka_new=str(state.vars.limitka), limitka_new_price=state.vars.limitka_price, limitka_qty=limitka_qty, limitka_filled_qty=limitka_filled_qty)
#pokud mame
#neni limitka, ale mela by byt - vytváříme ji
if int(state.positions) > 0 and state.vars.limitka is None:
state.ilog(e="Limitka neni, ale mela by být.", msg=f"{state.positions=}")
price=get_limitka_price()
state.vars.limitka = asyncio.run(state.interface.sell_l(price=price, size=int(state.positions)))
state.vars.limitka_price = price
if state.vars.limitka == -1:
state.ilog(e="Vytvoreni limitky neprobehlo, vracime None", msg=f"{state.vars.limitka=}")
state.vars.limitka = None
state.vars.limitka_price = None
else:
state.ilog(e="Vytvořena nová limitka", limitka=str(state.vars.limitka), limtka_price=state.vars.limitka_price, qty=state.positions)
#existuje a nesedi mnozstvi nebo cena
elif state.vars.limitka is not None and int(state.positions) > 0 and ((int(state.positions) != int(limitka_qty)) or float(state.vars.limitka_price) != float(get_limitka_price())):
#limitka existuje, ale spatne mnostvi - updatujeme
state.ilog(e=f"Limitka existuje, ale spatne mnozstvi nebo CENA - updatujeme", msg=f"{state.positions=} {limitka_qty=} {state.vars.limitka_price=}", nastavenacena=state.vars.limitka_price, spravna_cena=get_limitka_price(), pos=state.positions, limitka_qty=limitka_qty)
#snad to nespadne, kdyztak pridat exception handling
puvodni = state.vars.limitka
#TBD zde odchytit nejak result
state.vars.limitka = asyncio.run(state.interface.repl(price=get_limitka_price(), orderid=state.vars.limitka, size=int(state.positions)))
if state.vars.limitka == -1:
state.ilog(e="Replace limitky neprobehl, vracime puvodni", msg=f"{state.vars.limitka=}", puvodni=puvodni)
state.vars.limitka = puvodni
else:
limitka_qty = int(state.positions)
state.ilog(e="Změněna limitka", limitka=str(state.vars.limitka), limitka_price=state.vars.limitka_price, limitka_qty=limitka_qty)
#tbd pokud se bude vyskytovat pak pridat ještě konzolidaci ceny limitky
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(limitka)
#print(pendingbuys_new)
#print(pendingbuys)
#print(len(pendingbuys))
#print(len(pendingbuys_new))
#print(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)
#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 - 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
#CBAR protection, only 1x order per CBAR - then wait until another confirmed bar
if state.vars.blockbuy == 1 and state.rectype == RecordType.CBAR:
if state.bars.confirmed[-1] == 0:
print("OCHR: multibuy protection. waiting for next bar")
return 0
# pop potvrzeni jeste jednou vratime (aby se nekoupilo znova, je stale ten stejny bar)
# a pak dalsi vejde az po minticku
else:
# pro vykladaci
state.vars.blockbuy = 0
return 0
state.ilog(e="-----")
#EMA INDICATOR -
#plnime MAcko - nyni posilame jen N poslednich hodnot
#zaroven osetrujeme pripady, kdy je malo dat a ukladame nulu
try:
ma = int(state.vars.MA)
#poslednich ma hodnot
source = state.bars.close[-ma:] #state.bars.vwap
ema_value = ema(source, ma)
state.indicators.ema[-1]=trunc(ema_value[-1],3)
except Exception as e:
state.ilog(e="EMA ukladame 0", message=str(e)+format_exc())
#state.indicators.ema[-1]=0
#EMA SLOW
try:
ma = 100
#poslednich ma hodnot
source = state.bars.hlcc4[-ma:] #state.bars.vwap
emaSlow_value = ema(source, ma)
emaSlow = trunc(emaSlow_value[-1],3)
state.indicators.emaSlow[-1]=emaSlow
state.ilog(e=f"emaSlow {emaSlow=}", emaSlow=state.indicators.emaSlow[-5:])
except Exception as e:
state.ilog(e=f"emaSlow {ma=} ukladame 0", message=str(e)+format_exc())
#state.indicators.emaSlow.append(0)
#EMA FAST
try:
ma = 20
#poslednich ma hodnot
source = state.bars.hlcc4[-ma:] #state.bars.vwap
emaFast_value = ema(source, ma)
emaFast = trunc(emaFast_value[-1],3)
state.indicators.emaFast[-1]=emaFast
state.ilog(e=f"emaFast {emaFast=}", emaFast=state.indicators.emaFast[-5:])
except Exception as e:
state.ilog(e=f"emaFast {ma=} ukladame 0", message=str(e)+format_exc())
#state.indicators.emaFast.append(0)
#RSI14
try:
rsi_length = 14
#poslednich ma hodnot
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.append(rsi_value)
state.ilog(e=f"RSI {rsi_length=} {rsi_value=}", rsi_indicator=state.indicators.RSI14[-5:])
except Exception as e:
state.ilog(e=f"RSI {rsi_length=} ukladame 0", message=str(e)+format_exc())
state.indicators.RSI14.append(0)
#stoch
try:
stoch_length = 14
#poslednich ma hodnot
source_high = state.bars.high #[-rsi_length:] #state.bars.vwap
source_low = state.bars.low
source_close=state.bars.close
stoch_res1, stoch_res2 = stochastic_oscillator(source_high, source_low, source_close)
stoch_value1 = trunc(stoch_res1[-1],3)
stoch_value2 = trunc(stoch_res2[-1],3)
state.indicators.stoch1.append(stoch_value1)
state.indicators.stoch2.append(stoch_value2)
state.ilog(e=f"stoch {stoch_value1=} {stoch_value2=}", stoch1=state.indicators.stoch1[-5:], stoch2=state.indicators.stoch2[-5:])
except Exception as e:
state.ilog(e=f"stoch ukladame 0", message=str(e)+format_exc())
state.indicators.stoch1.append(0)
state.indicators.stoch2.append(0)
#absolute price oscillator
#meri mezeru mezi dvemi MACky (ato bud absolut price nebo percentage)
try:
short = 1
long = 20
#poslednich ma hodnot
source = state.bars.close #[-rsi_length:] #state.bars.vwap
apo_res = absolute_price_oscillator(source, short,long)
apo_value = trunc(apo_res[-1],3)
state.indicators.apo.append(apo_value)
state.ilog(e=f"apo {apo_value=}", apo_indicator=state.indicators.apo[-5:])
except Exception as e:
state.ilog(e=f"apo ukladame 0", message=str(e)+format_exc())
state.indicators.apo.append(0)
#percentage price oscillator
try:
short = 1
long = 20
#poslednich ma hodnot
source = state.bars.close #[-rsi_length:] #state.bars.vwap
ppo_res = percentage_price_oscillator(source, short,long)
ppo_value = trunc(ppo_res[-1],3)
state.indicators.ppo.append(ppo_value)
state.ilog(e=f"poo {ppo_value=}", ppo_indicator=state.indicators.ppo[-5:])
except Exception as e:
state.ilog(e=f"ppo ukladame 0", message=str(e)+format_exc())
state.indicators.ppo.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
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:])
#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()
#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)
#SLOPE ANGLE PROTECTIONs
#slope zachycuje rychle sestupy, pripadne zrusi nakupni objednavky
if slope < minimum_slope: # or slopeMA<maxSlopeMA:
print("OCHRANA SLOPE TOO HIGH")
# if slopeMA<maxSlopeMA:
# state.ilog(e="Slope MA too high "+str(slopeMA)+" max:"+str(maxSlopeMA))
state.ilog(e=f"Slope too high {slope}")
if len(state.vars.pendingbuys)>0:
print("CANCEL PENDINGBUYS")
#ic(state.vars.pendingbuys)
res = asyncio.run(state.cancel_pending_buys())
#ic(state.vars.pendingbuys)
state.ilog(e="Rusime pendingbuyes", pb=state.vars.pendingbuys, res=res)
print("slope", slope)
print("min slope", minimum_slope)
if state.vars.jevylozeno == 0:
print("Neni vylozeno, muzeme testovat nakup")
#pokud je defenziva, buy triggeruje defenzivni def_trend
#TBD
if isfalling(state.indicators.ema,state.vars.Trend) and slope > minimum_slope:
vyloz()
if state.vars.jevylozeno == 1:
#pokud mame vylozeno a cena je vetsi nez tick2reset
if len(state.vars.pendingbuys)>0:
maxprice = max(state.vars.pendingbuys.values())
print("max cena v orderbuys", maxprice)
if state.interface.get_last_price(state.symbol) > float(maxprice) + float(state.vars.ticks2reset):
##TODO toto nejak vymyslet - duplikovat?
res = asyncio.run(state.cancel_pending_buys())
state.ilog(e=f"UJELO to. Rusime PB", msg=f"{state.vars.ticks2reset=}", pb=state.vars.pendingbuys)
#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 se vyklepaly nastavujeme: neni vylozeno", jevylozeno=state.vars.jevylozeno)
#TODO toto dodelat konzolidaci a mozna lock na limitku a pendingbuys a jevylozeno ??
#kdykoliv se muze notifikace ztratit
# - pendingbuys - vsechny open orders buy
# - limitka - open order sell
#pokud je vylozeno a mame pozice a neexistuje limitka - pak ji vytvorim
# if int(state.oe.poz)>0 and state.oe.limitka == 0:
# #pro jistotu updatujeme pozice
# state.oe.avgp, state.oe.poz = state.oe.pos()
# if int(state.oe.poz) > 0:
# cena = round(float(state.oe.avgp) + float(state.oe.stratvars["profit"]),2)
# print("BUGF: limitka neni vytvarime, a to za cenu",cena,"mnozstvi",state.oe.poz)
# print("aktuzalni ltp",ltp.price[state.oe.symbol])
# try:
# state.oe.limitka = state.oe.sell_noasync(cena, state.oe.poz)
# print("vytvorena limitka", state.oe.limitka)
# except Exception as e:
# print("Neslo vytvorit profitku. Problem,ale jedeme dal",str(e))
# pass
# ##raise Exception(e)
print(10*"*","NEXT STOP",10*"*")
def init(state: StrategyState):
#place to declare new vars
print("INIT v main",state.name)
state.indicators['ema'] = []
state.indicators['slope'] = []
state.indicators['slopeMA'] = []
state.indicators['emaSlow'] = []
state.indicators['emaFast'] = []
state.indicators['RSI14'] = []
state.indicators['stoch1'] = []
state.indicators['stoch2'] = []
state.indicators['apo'] = []
state.indicators['ppo'] = []
#static indicators - those not series based
state.statinds['angle'] = dict(minimum_slope=state.vars["minimum_slope"])
state.vars["ticks2reset_backup"] = state.vars.ticks2reset

View File

@ -0,0 +1,521 @@
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.StrategyOrderLimitVykladaci import StrategyOrderLimitVykladaci
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
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
print(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
""""
Kope Vykladaci strategie s navic pridanym RSI
- pokud RSI > 50
- rusime pendingbuye
- netriggerujeme 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")
if def_mode_from == None: 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")
if def_profit == None: def_profit = state.vars.profit
if is_defensive_mode():
return price2dec(float(state.avgp)+float(def_profit))
else:
return price2dec(float(state.avgp)+float(state.vars.profit))
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 = {}
limitka_old = state.vars.limitka
#print("Puvodni LIMITKA", limitka_old)
#zaciname s cistym stitem
state.vars.limitka = None
state.vars.limitka_price = None
limitka_found = False
limitka_qty = 0
limitka_filled_qty = 0
for o in orderlist:
if o.side == OrderSide.SELL:
if limitka_found:
state.ilog(e="nalezeno vicero sell objednavek, bereme prvni, ostatni - rusime")
result=state.interface.cancel(o.id)
state.ilog(e="zrusena objednavka"+str(o.id), message=result)
continue
#print("Nalezena LIMITKA")
limitka_found = True
state.vars.limitka = o.id
state.vars.limitka_price = o.limit_price
limitka_qty = int(o.qty)
limitka_filled_qty = int(o.filled_qty)
#aktualni mnozstvi = puvodni minus filled
if limitka_filled_qty is not None:
print("prepocitavam filledmnozstvi od limitka_qty a filled_qty", limitka_qty, limitka_filled_qty)
limitka_qty = int(limitka_qty) - int(limitka_filled_qty)
##TODO sem pridat upravu ceny
if o.side == OrderSide.BUY and o.order_type == OrderType.LIMIT:
pendingbuys_new[str(o.id)]=float(o.limit_price)
state.ilog(e="Konzolidace limitky", msg=f"stejna:{(str(limitka_old)==str(state.vars.limitka))}", limitka_old=str(limitka_old), limitka_new=str(state.vars.limitka), limitka_new_price=state.vars.limitka_price, limitka_qty=limitka_qty, limitka_filled_qty=limitka_filled_qty)
#pokud mame
#neni limitka, ale mela by byt - vytváříme ji
if int(state.positions) > 0 and state.vars.limitka is None:
state.ilog(e="Limitka neni, ale mela by být.", msg=f"{state.positions=}")
price=get_limitka_price()
state.vars.limitka = asyncio.run(state.interface.sell_l(price=price, size=int(state.positions)))
state.vars.limitka_price = price
if state.vars.limitka == -1:
state.ilog(e="Vytvoreni limitky neprobehlo, vracime None", msg=f"{state.vars.limitka=}")
state.vars.limitka = None
state.vars.limitka_price = None
else:
state.ilog(e="Vytvořena nová limitka", limitka=str(state.vars.limitka), limtka_price=state.vars.limitka_price, qty=state.positions)
#existuje a nesedi mnozstvi nebo cena
elif state.vars.limitka is not None and int(state.positions) > 0 and ((int(state.positions) != int(limitka_qty)) or float(state.vars.limitka_price) != float(get_limitka_price())):
#limitka existuje, ale spatne mnostvi - updatujeme
state.ilog(e=f"Limitka existuje, ale spatne mnozstvi nebo CENA - updatujeme", msg=f"{state.positions=} {limitka_qty=} {state.vars.limitka_price=}", nastavenacena=state.vars.limitka_price, spravna_cena=get_limitka_price(), pos=state.positions, limitka_qty=limitka_qty)
#snad to nespadne, kdyztak pridat exception handling
puvodni = state.vars.limitka
#TBD zde odchytit nejak result
state.vars.limitka = asyncio.run(state.interface.repl(price=get_limitka_price(), orderid=state.vars.limitka, size=int(state.positions)))
if state.vars.limitka == -1:
state.ilog(e="Replace limitky neprobehl, vracime puvodni", msg=f"{state.vars.limitka=}", puvodni=puvodni)
state.vars.limitka = puvodni
else:
limitka_qty = int(state.positions)
state.ilog(e="Změněna limitka", limitka=str(state.vars.limitka), limitka_price=state.vars.limitka_price, limitka_qty=limitka_qty)
#tbd pokud se bude vyskytovat pak pridat ještě konzolidaci ceny limitky
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(limitka)
#print(pendingbuys_new)
#print(pendingbuys)
#print(len(pendingbuys))
#print(len(pendingbuys_new))
#print(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)
#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 - 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
#CBAR protection, only 1x order per CBAR - then wait until another confirmed bar
if state.vars.blockbuy == 1 and state.rectype == RecordType.CBAR:
if state.bars.confirmed[-1] == 0:
print("OCHR: multibuy protection. waiting for next bar")
return 0
# pop potvrzeni jeste jednou vratime (aby se nekoupilo znova, je stale ten stejny bar)
# a pak dalsi vejde az po minticku
else:
# pro vykladaci
state.vars.blockbuy = 0
return 0
state.ilog(e="-----")
#EMA INDICATOR -
#plnime MAcko - nyni posilame jen N poslednich hodnot
#zaroven osetrujeme pripady, kdy je malo dat a ukladame nulu
try:
ma = int(state.vars.MA)
#poslednich ma hodnot
source = state.bars.close[-ma:] #state.bars.vwap
ema_value = ema(source, ma)
state.indicators.ema[-1]=trunc(ema_value[-1],3)
except Exception as e:
state.ilog(e="EMA ukladame 0", message=str(e)+format_exc())
state.indicators.ema[-1]=0
#RSI14 INDICATOR
try:
##mame v atributech nastaveni?
rsi_dont_buy_above = safe_get(state.vars, "rsi_dont_buy_above")
if rsi_dont_buy_above == None:
rsi_dont_buy_above = 50
rsi_buy_signal = False
rsi_dont_buy = False
rsi_length = 14
source = state.bars.close #[-rsi_length:] #state.bars.vwap
rsi_res = rsi(source, rsi_length)
rsi_value = trunc(rsi_res[-1],3)
state.indicators.RSI14[-1]=rsi_value
rsi_dont_buy = rsi_value > rsi_dont_buy_above
rsi_buy_signal = rsi_value < 40
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=} ukladame 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
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()
#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:
print("CANCEL PENDINGBUYS")
#ic(state.vars.pendingbuys)
res = asyncio.run(state.cancel_pending_buys())
#ic(state.vars.pendingbuys)
state.ilog(e="Rusime pendingbuyes", pb=state.vars.pendingbuys, res=res)
print("slope", slope)
print("min slope", minimum_slope)
if state.vars.jevylozeno == 0:
print("Neni vylozeno, muzeme testovat nakup")
#pokud je defenziva, buy triggeruje defenzivni def_trend
#TBD
#NOVY BUY SIGNAL z RSI < 35
#buy_signal = isfalling(state.indicators.ema,state.vars.Trend)
buy_signal = rsi_buy_signal
if buy_signal and slope > minimum_slope and not rsi_dont_buy:
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 predelat mechanismus ticků (zrelativizovat), aby byl pouzitelny na tituly s ruznou cenou
#TODO spoustet 1x za X iteraci nebo cas
if state.vars.jevylozeno == 1:
#pokud mame vylozeno a cena je vetsi nez tick2reset
if len(state.vars.pendingbuys)>0:
maxprice = max(state.vars.pendingbuys.values())
print("max cena v orderbuys", maxprice)
if state.interface.get_last_price(state.symbol) > float(maxprice) + float(state.vars.ticks2reset):
##TODO toto nejak vymyslet - duplikovat?
res = asyncio.run(state.cancel_pending_buys())
state.ilog(e=f"UJELO to. Rusime PB", msg=f"{state.vars.ticks2reset=}", pb=state.vars.pendingbuys)
#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 se vyklepaly nastavujeme: neni vylozeno", jevylozeno=state.vars.jevylozeno)
#TODO toto dodelat konzolidaci a mozna lock na limitku a pendingbuys a jevylozeno ??
#kdykoliv se muze notifikace ztratit
# - pendingbuys - vsechny open orders buy
# - limitka - open order sell
#pokud je vylozeno a mame pozice a neexistuje limitka - pak ji vytvorim
# if int(state.oe.poz)>0 and state.oe.limitka == 0:
# #pro jistotu updatujeme pozice
# state.oe.avgp, state.oe.poz = state.oe.pos()
# if int(state.oe.poz) > 0:
# cena = round(float(state.oe.avgp) + float(state.oe.stratvars["profit"]),2)
# print("BUGF: limitka neni vytvarime, a to za cenu",cena,"mnozstvi",state.oe.poz)
# print("aktuzalni ltp",ltp.price[state.oe.symbol])
# try:
# state.oe.limitka = state.oe.sell_noasync(cena, state.oe.poz)
# print("vytvorena limitka", state.oe.limitka)
# except Exception as e:
# print("Neslo vytvorit profitku. Problem,ale jedeme dal",str(e))
# pass
# ##raise Exception(e)
print(10*"*","NEXT STOP",10*"*")
def init(state: StrategyState):
#place to declare new vars
print("INIT v main",state.name)
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"])
state.vars["ticks2reset_backup"] = state.vars.ticks2reset
def main():
# try:
# strat_settings = tomli.loads("]] this is invalid TOML [[")
# except tomli.TOMLDecodeError:
# print("Yep, definitely not valid.")
#strat_settings = dict_replace_value(strat_settings, "None", None)
name = os.path.basename(__file__)
se = Event()
pe = Event()
s = StrategyOrderLimitVykladaci(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

@ -0,0 +1,839 @@
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, Average
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
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_profit_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 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():
akt_pozic = int(state.positions)/int(state.vars.chunk)
multiplier = 1
#zatim jednoduse pokud je akt. pozice 1 nebo 3 chunky (<4) tak zdvojnásubuju
#aneb druhy a treti nakup
if akt_pozic > 0 and akt_pozic < 4:
multiplier = safe_get(state.vars, "market_buy_multiplier", 1)
state.ilog(e=f"BUY MULTIPLIER: {multiplier}")
return multiplier
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 pouzijeme LIMIT nebo MARKET podle nastaveni
if is_defensive_mode() and safe_get(state.vars, "first_buy_market_def_mode", False) is False:
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")
#market size optimalization based on conditions
state.buy(size=optimize_qty_multiplier()*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_profit_price()
max_price = get_max_profit_price()
state.ilog(e=f"Goal price {goal_price} max price {max_price}")
#pokud je cena vyssi
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
max_price_signal = curr_price>=max_price
#OPTIMALIZACE pri stoupajícím angle
if max_price_signal or 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=} {max_price_signal=}", positions=state.positions, avgp=state.avgp, sellinprogress=state.vars.sell_in_progress)
#pokud je cena nizsi, testujeme REVERSE POZITION PROTECTION
else:
pass
#reverse_position()
# def reverse_position():
# """"
# Reverse position - ochrana pred vetsim klesanim
# - proda kdyz je splnena podminka
# - nakoupi opet ve stejnem mnozstvi, kdyz je splnena podminka
# required STRATVARS:
# reverse_position_slope = -0.9
# reverse_position_on_confirmed_only = true
# reverse_position_waiting_amount = 0
# """""
# #reverse position preconditions
# dont_do_reverse_when = {}
# dont_do_reverse_when['reverse_position_waiting_amount_not_0'] = (state.vars.reverse_position_waiting_amount != 0)
# result, conditions_met = eval_cond_dict(dont_do_reverse_when)
# if result:
# state.ilog(e=f"REVERSE_PRECOND PROTECTION {conditions_met}")
# return result
# #reverse position for
# confirmrequried = safe_get(state.vars, "reverse_position_on_confirmed_only", True)
# if (confirmrequried and data['confirmed'] == 1) or confirmrequried is False:
# #check reverse position
# state.ilog(e="REVERSE POSITION check - GO")
# else:
# #not time for reverse position
# state.ilog(e="REVERSE POSITION check - NO TIME")
# #predpokladame, ze uz byly testovany pozice a mame je if int(state.positions) > 0 and float(state.avgp)>0
# if state.indicators.slopeMA[-1] < float(safe_get(state.vars, "reverse_position_slope", -0.10)):
# state.interface.sell(size=state.positions)
# state.vars.sell_in_progress = True
# state.ilog(e=f"REV POS market SELL was sent {curr_price=}", positions=state.positions, avgp=state.avgp, sellinprogress=state.vars.sell_in_progress)
# state.vars.rev_position_waiting_amount =
# 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():
#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
# [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():
#populuje indikator typu SLOPE
#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
#cekame na dostatek dat
if len(source) > rsi_length:
rsi_res = rsi(source, rsi_length)
rsi_value = trunc(rsi_res[-1],3)
state.indicators.RSI14[-1]=rsi_value
else:
state.ilog(e=f"RSI {rsi_length=} necháváme 0", message="not enough source data")
#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
options = safe_get(state.vars.indicators, 'crsi', None)
if options is None:
state.ilog(e="No options for crsi in stratvars")
return
try:
crsi_length = int(safe_get(options, 'crsi_length', 14))
source = state.cbar_indicators.tick_price #[-rsi_length:] #state.bars.vwap
crsi_res = rsi(source, crsi_length)
crsi_value = crsi_res[-1]
if str(crsi_value) == "nan":
crsi_value = 0
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:
# 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():
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():
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())
##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)
#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)
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,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)
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)
dont_buy_when['reverse_position_waiting_amount_not_0'] = (state.vars.reverse_position_waiting_amount != 0)
#testing preconditions
result, cond_met = eval_cond_dict(dont_buy_when)
if result:
state.ilog(e=f"BUY precondition not met {cond_met} {state.vars.jevylozeno=}")
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, pripadne k tomu CRSI
#TATO KOMBINACE se da konfigurovat pouze hodnotama, aby platila libovolna kombinace podminek (např. Trend = 1 - vypne stredni podminku)
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["AND"]['crsi_below_crsi_buy_limit'] = state.cbar_indicators.CRSI[-1] < safe_get(state.vars, "crsi_buy_signal_below",25)
buy_cond["AND"]['slopeMA_is_below_limit'] = state.indicators.slopeMA[-1] < safe_get(state.vars, "slopeMA_buy_signal_below",1)
#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 {result} {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_price = 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:]
# for key in state.secondary_indicators:
# if key != 'time':
# last_ind_vals[key] = state.secondary_indicators[key][-5:]
return last_ind_vals
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
state.vars.last_update_time = float(data['updated'])
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
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
#zatim takto na confirm
populate_slow_slope_indicator()
#SRSI
#populate_secondary_rsi_indicator()
#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)
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="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.mode = None
state.vars.last_tick_price = 0
state.vars.last_50_deltas = []
state.vars.last_tick_volume = 0
state.vars.next_new = 0
state.vars.last_buysignal_index = 0
state.vars.last_update_time = 0
state.vars.reverse_position_waiting_amount = 0
#state.cbar_indicators['ivwap'] = []
state.cbar_indicators['tick_price'] = []
state.cbar_indicators['tick_volume'] = []
state.cbar_indicators['CRSI'] = []
#state.secondary_indicators['SRSI'] = []
state.indicators['ema'] = []
state.indicators['slope'] = []
state.indicators['slopeMA'] = []
state.indicators['slow_slope'] = []
state.indicators['slow_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.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
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

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

@ -0,0 +1,519 @@
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.StrategyOrderLimitVykladaciNormalized import StrategyOrderLimitVykladaciNormalized
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
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
print(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
""""
Kope Vykladaci strategie s navic pridanym RSI a normalizovaným tickem.
- pokud RSI > 50
- rusime pendingbuye
- netriggerujeme 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)
if is_defensive_mode():
return price2dec(cena+get_tick(cena,float(def_profit)))
else:
return price2dec(cena+get_tick(cena,float(state.vars.profit)))
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 = {}
limitka_old = state.vars.limitka
#print("Puvodni LIMITKA", limitka_old)
#zaciname s cistym stitem
state.vars.limitka = None
state.vars.limitka_price = None
limitka_found = False
limitka_qty = 0
limitka_filled_qty = 0
for o in orderlist:
if o.side == OrderSide.SELL:
if limitka_found:
state.ilog(e="nalezeno vicero sell objednavek, bereme prvni, ostatni - rusime")
result=state.interface.cancel(o.id)
state.ilog(e="zrusena objednavka"+str(o.id), message=result)
continue
#print("Nalezena LIMITKA")
limitka_found = True
state.vars.limitka = o.id
state.vars.limitka_price = o.limit_price
limitka_qty = int(o.qty)
limitka_filled_qty = int(o.filled_qty)
#aktualni mnozstvi = puvodni minus filled
if limitka_filled_qty is not None:
print("prepocitavam filledmnozstvi od limitka_qty a filled_qty", limitka_qty, limitka_filled_qty)
limitka_qty = int(limitka_qty) - int(limitka_filled_qty)
##TODO sem pridat upravu ceny
if o.side == OrderSide.BUY and o.order_type == OrderType.LIMIT:
pendingbuys_new[str(o.id)]=float(o.limit_price)
state.ilog(e="Konzolidace limitky", msg=f"stejna:{(str(limitka_old)==str(state.vars.limitka))}", limitka_old=str(limitka_old), limitka_new=str(state.vars.limitka), limitka_new_price=state.vars.limitka_price, limitka_qty=limitka_qty, limitka_filled_qty=limitka_filled_qty)
#pokud mame
#neni limitka, ale mela by byt - vytváříme ji
if int(state.positions) > 0 and state.vars.limitka is None:
state.ilog(e="Limitka neni, ale mela by být.", msg=f"{state.positions=}")
price=get_limitka_price()
state.vars.limitka = asyncio.run(state.interface.sell_l(price=price, size=int(state.positions)))
state.vars.limitka_price = price
if state.vars.limitka == -1:
state.ilog(e="Vytvoreni limitky neprobehlo, vracime None", msg=f"{state.vars.limitka=}")
state.vars.limitka = None
state.vars.limitka_price = None
else:
state.ilog(e="Vytvořena nová limitka", limitka=str(state.vars.limitka), limtka_price=state.vars.limitka_price, qty=state.positions)
#existuje a nesedi mnozstvi nebo cena
elif state.vars.limitka is not None and int(state.positions) > 0 and ((int(state.positions) != int(limitka_qty)) or float(state.vars.limitka_price) != float(get_limitka_price())):
#limitka existuje, ale spatne mnostvi - updatujeme
state.ilog(e=f"Limitka existuje, ale spatne mnozstvi nebo CENA - updatujeme", msg=f"{state.positions=} {limitka_qty=} {state.vars.limitka_price=}", nastavenacena=state.vars.limitka_price, spravna_cena=get_limitka_price(), pos=state.positions, limitka_qty=limitka_qty)
#snad to nespadne, kdyztak pridat exception handling
puvodni = state.vars.limitka
#TBD zde odchytit nejak result
state.vars.limitka = asyncio.run(state.interface.repl(price=get_limitka_price(), orderid=state.vars.limitka, size=int(state.positions)))
if state.vars.limitka == -1:
state.ilog(e="Replace limitky neprobehl, vracime puvodni", msg=f"{state.vars.limitka=}", puvodni=puvodni)
state.vars.limitka = puvodni
else:
limitka_qty = int(state.positions)
state.ilog(e="Změněna limitka", limitka=str(state.vars.limitka), limitka_price=state.vars.limitka_price, limitka_qty=limitka_qty)
#tbd pokud se bude vyskytovat pak pridat ještě konzolidaci ceny limitky
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(limitka)
#print(pendingbuys_new)
#print(pendingbuys)
#print(len(pendingbuys))
#print(len(pendingbuys_new))
#print(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)
#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
#CBAR protection, only 1x order per CBAR - then wait until another confirmed bar
if state.vars.blockbuy == 1 and state.rectype == RecordType.CBAR:
if state.bars.confirmed[-1] == 0:
print("OCHR: multibuy protection. waiting for next bar")
return 0
# pop potvrzeni jeste jednou vratime (aby se nekoupilo znova, je stale ten stejny bar)
# a pak dalsi vejde az po minticku
else:
# pro vykladaci
state.vars.blockbuy = 0
return 0
state.ilog(e="-----")
#EMA INDICATOR -
#plnime MAcko - nyni posilame jen N poslednich hodnot
#zaroven osetrujeme pripady, kdy je malo dat a ukladame nulu
try:
ma = int(state.vars.MA)
#poslednich ma hodnot
source = state.bars.close[-ma:] #state.bars.vwap
ema_value = ema(source, ma)
state.indicators.ema[-1]=trunc(ema_value[-1],3)
except Exception as e:
state.ilog(e="EMA ukladame 0", message=str(e)+format_exc())
#state.indicators.ema[-1]=0
#RSI14 INDICATOR
try:
##mame v atributech nastaveni?
rsi_dont_buy_above = safe_get(state.vars, "rsi_dont_buy_above",50)
rsi_buy_signal_conf = safe_get(state.vars, "rsi_buy_signal_below",40)
rsi_buy_signal = False
rsi_dont_buy = False
rsi_length = 14
source = state.bars.close #[-rsi_length:] #state.bars.vwap
rsi_res = rsi(source, rsi_length)
rsi_value = trunc(rsi_res[-1],3)
state.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"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=} ukladame 0", message=str(e)+format_exc())
#state.indicators.RSI14[-1]=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
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()
#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:
print("CANCEL PENDINGBUYS")
#ic(state.vars.pendingbuys)
res = asyncio.run(state.cancel_pending_buys())
#ic(state.vars.pendingbuys)
state.ilog(e="Rusime pendingbuyes", pb=state.vars.pendingbuys, res=res)
print("slope", slope)
print("min slope", minimum_slope)
if state.vars.jevylozeno == 0:
print("Neni vylozeno, muzeme testovat nakup")
#pokud je defenziva, buy triggeruje defenzivni def_trend
#TBD
#NOVY BUY SIGNAL z RSI < 35
#buy_signal = isfalling(state.indicators.ema,state.vars.Trend)
buy_signal = rsi_buy_signal
if buy_signal and slope > minimum_slope and not rsi_dont_buy:
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 predelat mechanismus ticků (zrelativizovat), aby byl pouzitelny na tituly s ruznou cenou
#TODO spoustet 1x za X iteraci nebo cas
if state.vars.jevylozeno == 1:
#pokud mame vylozeno a cena je vetsi nez tick2reset
if len(state.vars.pendingbuys)>0:
maxprice = max(state.vars.pendingbuys.values())
print("max cena v orderbuys", maxprice)
if state.interface.get_last_price(state.symbol) > float(maxprice) + get_tick(maxprice, float(state.vars.ticks2reset)):
##TODO toto nejak vymyslet - duplikovat?
res = asyncio.run(state.cancel_pending_buys())
state.ilog(e=f"UJELO to. Rusime PB", msg=f"{state.vars.ticks2reset=}", pb=state.vars.pendingbuys)
#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 se vyklepaly nastavujeme: neni vylozeno", jevylozeno=state.vars.jevylozeno)
#TODO toto dodelat konzolidaci a mozna lock na limitku a pendingbuys a jevylozeno ??
#kdykoliv se muze notifikace ztratit
# - pendingbuys - vsechny open orders buy
# - limitka - open order sell
#pokud je vylozeno a mame pozice a neexistuje limitka - pak ji vytvorim
# if int(state.oe.poz)>0 and state.oe.limitka == 0:
# #pro jistotu updatujeme pozice
# state.oe.avgp, state.oe.poz = state.oe.pos()
# if int(state.oe.poz) > 0:
# cena = round(float(state.oe.avgp) + float(state.oe.stratvars["profit"]),2)
# print("BUGF: limitka neni vytvarime, a to za cenu",cena,"mnozstvi",state.oe.poz)
# print("aktuzalni ltp",ltp.price[state.oe.symbol])
# try:
# state.oe.limitka = state.oe.sell_noasync(cena, state.oe.poz)
# print("vytvorena limitka", state.oe.limitka)
# except Exception as e:
# print("Neslo vytvorit profitku. Problem,ale jedeme dal",str(e))
# pass
# ##raise Exception(e)
print(10*"*","NEXT STOP",10*"*")
def init(state: StrategyState):
#place to declare new vars
print("INIT v main",state.name)
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"])
state.vars["ticks2reset_backup"] = state.vars.ticks2reset
def main():
# try:
# strat_settings = tomli.loads("]] this is invalid TOML [[")
# except tomli.TOMLDecodeError:
# print("Yep, definitely not valid.")
#strat_settings = dict_replace_value(strat_settings, "None", None)
name = os.path.basename(__file__)
se = Event()
pe = Event()
s = StrategyOrderLimitVykladaciNormalized(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

@ -0,0 +1,90 @@
from strategy.base import Strategy, StrategyState
from strategy.strategyOrderLimit import StrategyOrderLimit
from enums import RecordType, StartBarAlign, Mode
from config import API_KEY, SECRET_KEY, MAX_BATCH_SIZE, PAPER
from indicators import ema
from rich import print
from utils.utils import ltp, isrising, isfalling,trunc,AttributeDict, zoneNY
from datetime import datetime
from icecream import install, ic
install()
ic.configureOutput(includeContext=True)
#ic.disable()
""""
Simple strategie pro test backtesting
"""
def next(data, state: StrategyState):
print(10*"*","NEXT START",10*"*")
#ic(state.avgp, state.positions)
#ic(state.vars.limitka)
#ic(state.vars.lastbuyindex)
#ic(data)
#print("last trade price")
#print(state.interface.get_last_price("BAC"))
#print(state.vars.novaprom)
#print("trades history", state.trades)
#print("bar history", state.bars)
#print("ltp", ltp.price["BAC"], ltp.time["BAC"])
#TODO indikátory ukládat do vlastní historie - tu pak automaticky zobrazuje backtester graf
#TODO ema = state.indicators.ema a pouzivat nize ema, zjistit jestli bude fungovat
try:
state.indicators.ema = ema(state.bars.hlcc4, state.vars.MA) #state.bars.vwap
#trochu prasarna, EMAcko trunc na 3 mista - kdyz se osvedci, tak udelat efektivne
state.indicators.ema = [trunc(i,3) for i in state.indicators.ema]
#ic(state.vars.MA, state.vars.Trend, state.indicators.ema[-5:])
except Exception as e:
print("No data for MA yet", str(e))
print("is falling",isfalling(state.indicators.ema,state.vars.Trend))
print("is rising",isrising(state.indicators.ema,state.vars.Trend))
#ZDE JSEM SKONCIL
#nejprve zacit s BARy
#TODO vyzkoušet limit buy - vetsina z nakupu by se dala koupit o cent dva mene
#proto dodělat LTP pro BT, neco jako get_last_price(self.state.time)
##TODO vyzkouset hlidat si sell objednavku sam na zaklade tradu
# v pripade ze to jde nahoru(is rising - nebo jiny indikator) tak neprodavat
#vyuzit CBARy k tomuto .....
#triggerovat buy treba po polovine CBARu, kdyz se cena bude rovnat nebo bude nizsi nez low
#a hned na to (po potvrzeni) hlidat sell +0.01 nebo kdyz roste nechat rust.vyzkouset na LIVE
if isfalling(state.indicators.ema,state.vars.Trend) and data['index'] > state.vars.lastbuyindex+state.vars.Trend: #and state.blockbuy == 0
print("BUY MARKET")
#ic(data['updated'])
#ic(state.time)
state.buy_l()
print(10*"*","NEXT STOP",10*"*")
def init(state: StrategyState):
#place to declare new vars
print("INIT v main",state.name)
state.vars['novaprom'] = 4
state.indicators['ema'] = []
def main():
stratvars = AttributeDict(maxpozic = 2400, chunk = 400, MA = 6, Trend = 7, profit = 0.03, lastbuyindex=-6, pendingbuys={},limitka = None)
s = StrategyOrderLimit(name = "BackTEST", symbol = "KO", next=next, init=init, stratvars=stratvars, debug=False)
s.set_mode(mode = Mode.BT,
start = datetime(2023, 2, 23, 9, 30, 0, 0, tzinfo=zoneNY),
end = datetime(2023, 2, 23, 16, 00, 0, 0, tzinfo=zoneNY),
cash=100000)
#na sekundovem baru nezaokrouhlovat MAcko
s.add_data(symbol="KO",rectype=RecordType.BAR,timeframe=30,filters=None,update_ltp=True,align=StartBarAlign.RANDOM,mintick=0)
#s.add_data(symbol="C",rectype=RecordType.BAR,timeframe=1,filters=None,update_ltp=True,align=StartBarAlign.ROUND,mintick=0)
s.start()
if __name__ == "__main__":
main()

View File

@ -0,0 +1,99 @@
# import os,sys
# sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from v2realbot.strategy.base import Strategy, StrategyState
from v2realbot.strategy.StrategyOrderLimitKOKA import StrategyOrderLimitKOKA
from v2realbot.enums.enums import RecordType, StartBarAlign, Mode
from v2realbot.indicators.indicators import ema
from rich import print
from v2realbot.utils.utils import ltp, isrising, isfalling,trunc,AttributeDict, zoneNY
from datetime import datetime
from icecream import install, ic
import os
install()
ic.configureOutput(includeContext=True)
#ic.disable()
""""
Simple strategie LIMIT buy a lIMIT SELL working ok
DOkupovaci strategie, nakupuje dalsi pozice až po dalším signálu.
POZOR nekontroluje se maximální pozice - tzn. nejvic se vycerpalo 290, ale prezila kazdy den.
Dobrá defenzivní pri nastaveni
30s maxpozic = 290,chunk = 10,MA = 6,Trend = 6,profit = 0.02,
"""
stratvars = AttributeDict(maxpozic = 250,
chunk = 10,
MA = 6,
Trend = 6,
profit = 0.02,
lastbuyindex=-6,
pendingbuys={},
limitka = None)
def next(data, state: StrategyState):
print(10*"*","NEXT START",10*"*")
#ic(state.avgp, state.positions)
#ic(state.vars.limitka)
#ic(state.vars.lastbuyindex)
#ic(data)
#print("last trade price")
#print(state.interface.get_last_price("BAC"))
#print(state.vars.novaprom)
#print("trades history", state.trades)
#print("bar history", state.bars)
#print("ltp", ltp.price["BAC"], ltp.time["BAC"])
#TODO indikátory ukládat do vlastní historie - tu pak automaticky zobrazuje backtester graf
#TODO ema = state.indicators.ema a pouzivat nize ema, zjistit jestli bude fungovat
try:
state.indicators.ema = ema(state.bars.hlcc4, state.vars.MA) #state.bars.vwap
#trochu prasarna, EMAcko trunc na 3 mista - kdyz se osvedci, tak udelat efektivne
state.indicators.ema = [trunc(i,3) for i in state.indicators.ema]
#ic(state.vars.MA, state.vars.Trend, state.indicators.ema[-5:])
except Exception as e:
print("No data for MA yet", str(e))
print("is falling",isfalling(state.indicators.ema,state.vars.Trend))
print("is rising",isrising(state.indicators.ema,state.vars.Trend))
#ZDE JSEM SKONCIL
#nejprve zacit s BARy
#TODO vyzkoušet limit buy - vetsina z nakupu by se dala koupit o cent dva mene
#proto dodělat LTP pro BT, neco jako get_last_price(self.state.time)
if isfalling(state.indicators.ema,state.vars.Trend) and data['index'] > state.vars.lastbuyindex+state.vars.Trend: #and state.blockbuy == 0
print("BUY MARKET")
#ic(data['updated'])
#ic(state.time)
state.buy_l()
print(10*"*","NEXT STOP",10*"*")
def init(state: StrategyState):
#place to declare new vars
print("INIT v main",state.name)
state.vars['novaprom'] = 4
state.indicators['ema'] = []
def main():
name = os.path.basename(__file__)
s = StrategyOrderLimitKOKA(name = name, symbol = "BAC", next=next, init=init, stratvars=stratvars, open_rush=30, close_rush=0)
s.set_mode(mode = Mode.PAPER,
debug = False,
start = datetime(2023, 3, 6, 9, 30, 0, 0, tzinfo=zoneNY),
end = datetime(2023, 3, 9, 16, 0, 0, 0, tzinfo=zoneNY),
cash=100000)
#na sekundovem baru nezaokrouhlovat MAcko
s.add_data(symbol="BAC",rectype=RecordType.BAR,timeframe=30,filters=None,update_ltp=True,align=StartBarAlign.ROUND,mintick=0)
#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

@ -0,0 +1,502 @@
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.StrategyOrderLimitVykladaci import StrategyOrderLimitVykladaci
from v2realbot.enums.enums import RecordType, StartBarAlign, Mode, Account, OrderSide, OrderType
from v2realbot.indicators.indicators import ema
from v2realbot.utils.utils import ltp, isrising, isfalling,trunc,AttributeDict, zoneNY, price2dec, print, safe_get
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
# install()
# ic.configureOutput(includeContext=True)
#ic.disable()
print(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
""""
Vykladaci strategie refactored z původního engine
Params:
(maxpozic = 200, chunk = 50, MA = 6, Trend = 6, profit = 0.02, lastbuyindex=-6, pendingbuys={},limitka = None, jevylozeno=0, ticks2reset = 0.04, blockbuy=0)
Pozor na symbolu nesmi byt dalsi cizí otevrene objednavky:
Pravidelny konzolidacni process da SELL order da do limitka, BUY - do pole pendingbuys
consolidation_bar_count - pocet baru po kterych se triggeruje konzolidační proces
Více nakupuje oproti Dokupovaci. Tady vylozime a nakupujeme 5 pozic hned. Pri dokupovaci se dokupuje, az na zaklade dalsich triggeru.
Do budoucna vice ridit nakupy pri klesani - napr. vyložení jen 2-3 pozic a další dokupy až po triggeru.
#
"""
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)
if is_defensive_mode():
return price2dec(float(state.avgp)+float(def_profit))
else:
return price2dec(float(state.avgp)+float(state.vars.profit))
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 = {}
limitka_old = state.vars.limitka
#print("Puvodni LIMITKA", limitka_old)
#zaciname s cistym stitem
state.vars.limitka = None
state.vars.limitka_price = None
limitka_found = False
limitka_qty = 0
limitka_filled_qty = 0
for o in orderlist:
if o.side == OrderSide.SELL:
if limitka_found:
state.ilog(e="nalezeno vicero sell objednavek, bereme prvni, ostatni - rusime")
result=state.interface.cancel(o.id)
state.ilog(e="zrusena objednavka"+str(o.id), message=result)
continue
#print("Nalezena LIMITKA")
limitka_found = True
state.vars.limitka = o.id
state.vars.limitka_price = o.limit_price
limitka_qty = int(o.qty)
limitka_filled_qty = int(o.filled_qty)
#aktualni mnozstvi = puvodni minus filled
if limitka_filled_qty is not None:
print("prepocitavam filledmnozstvi od limitka_qty a filled_qty", limitka_qty, limitka_filled_qty)
limitka_qty = int(limitka_qty) - int(limitka_filled_qty)
##TODO sem pridat upravu ceny
if o.side == OrderSide.BUY and o.order_type == OrderType.LIMIT:
pendingbuys_new[str(o.id)]=float(o.limit_price)
state.ilog(e="Konzolidace limitky", msg=f"stejna:{(str(limitka_old)==str(state.vars.limitka))}", limitka_old=str(limitka_old), limitka_new=str(state.vars.limitka), limitka_new_price=state.vars.limitka_price, limitka_qty=limitka_qty, limitka_filled_qty=limitka_filled_qty)
#pokud mame
#neni limitka, ale mela by byt - vytváříme ji
if int(state.positions) > 0 and state.vars.limitka is None:
state.ilog(e="Limitka neni, ale mela by být.", msg=f"{state.positions=}")
price=get_limitka_price()
state.vars.limitka = asyncio.run(state.interface.sell_l(price=price, size=int(state.positions)))
state.vars.limitka_price = price
if state.vars.limitka == -1:
state.ilog(e="Vytvoreni limitky neprobehlo, vracime None", msg=f"{state.vars.limitka=}")
state.vars.limitka = None
state.vars.limitka_price = None
else:
state.ilog(e="Vytvořena nová limitka", limitka=str(state.vars.limitka), limtka_price=state.vars.limitka_price, qty=state.positions)
#existuje a nesedi mnozstvi nebo cena
elif state.vars.limitka is not None and int(state.positions) > 0 and ((int(state.positions) != int(limitka_qty)) or float(state.vars.limitka_price) != float(get_limitka_price())):
#limitka existuje, ale spatne mnostvi - updatujeme
state.ilog(e=f"Limitka existuje, ale spatne mnozstvi nebo CENA - updatujeme", msg=f"{state.positions=} {limitka_qty=} {state.vars.limitka_price=}", nastavenacena=state.vars.limitka_price, spravna_cena=get_limitka_price(), pos=state.positions, limitka_qty=limitka_qty)
#snad to nespadne, kdyztak pridat exception handling
puvodni = state.vars.limitka
#TBD zde odchytit nejak result
state.vars.limitka = asyncio.run(state.interface.repl(price=get_limitka_price(), orderid=state.vars.limitka, size=int(state.positions)))
if state.vars.limitka == -1:
state.ilog(e="Replace limitky neprobehl, vracime puvodni", msg=f"{state.vars.limitka=}", puvodni=puvodni)
state.vars.limitka = puvodni
else:
limitka_qty = int(state.positions)
state.ilog(e="Změněna limitka", limitka=str(state.vars.limitka), limitka_price=state.vars.limitka_price, limitka_qty=limitka_qty)
#tbd pokud se bude vyskytovat pak pridat ještě konzolidaci ceny limitky
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(limitka)
#print(pendingbuys_new)
#print(pendingbuys)
#print(len(pendingbuys))
#print(len(pendingbuys_new))
#print(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)
#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", False) == 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 - 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
#CBAR protection, only 1x order per CBAR - then wait until another confirmed bar
if state.vars.blockbuy == 1 and state.rectype == RecordType.CBAR:
if state.bars.confirmed[-1] == 0:
print("OCHR: multibuy protection. waiting for next bar")
return 0
# pop potvrzeni jeste jednou vratime (aby se nekoupilo znova, je stale ten stejny bar)
# a pak dalsi vejde az po minticku
else:
# pro vykladaci
state.vars.blockbuy = 0
return 0
state.ilog(e="-----")
#EMA INDICATOR -
#plnime MAcko - nyni posilame jen N poslednich hodnot
#zaroven osetrujeme pripady, kdy je malo dat a ukladame nulu
try:
ma = int(state.vars.MA)
#poslednich ma hodnot
source = state.bars.close[-ma:] #state.bars.vwap
ema_value = ema(source, ma)
state.indicators.ema[-1]=trunc(ema_value[-1],3)
except Exception as e:
state.ilog(e="EMA ukladame 0", message=str(e)+format_exc())
state.indicators.ema[-1]=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
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:])
#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()
#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)
#SLOPE ANGLE PROTECTIONs
#slope zachycuje rychle sestupy, pripadne zrusi nakupni objednavky
if slope < minimum_slope: # or slopeMA<maxSlopeMA:
print("OCHRANA SLOPE TOO HIGH")
# if slopeMA<maxSlopeMA:
# state.ilog(e="Slope MA too high "+str(slopeMA)+" max:"+str(maxSlopeMA))
state.ilog(e=f"Slope too high {slope}")
if len(state.vars.pendingbuys)>0:
print("CANCEL PENDINGBUYS")
#ic(state.vars.pendingbuys)
res = asyncio.run(state.cancel_pending_buys())
#ic(state.vars.pendingbuys)
state.ilog(e="Rusime pendingbuyes", pb=state.vars.pendingbuys, res=res)
print("slope", slope)
print("min slope", minimum_slope)
if state.vars.jevylozeno == 0:
print("Neni vylozeno, muzeme testovat nakup")
#pokud je defenziva, buy triggeruje defenzivni def_trend
#TBD
if isfalling(state.indicators.ema,state.vars.Trend) and slope > minimum_slope:
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 predelat mechanismus ticků (zrelativizovat), aby byl pouzitelny na tituly s ruznou cenou
#TODO spoustet 1x za X iteraci nebo cas
if state.vars.jevylozeno == 1:
#pokud mame vylozeno a cena je vetsi nez tick2reset
if len(state.vars.pendingbuys)>0:
maxprice = max(state.vars.pendingbuys.values())
print("max cena v orderbuys", maxprice)
if state.interface.get_last_price(state.symbol) > float(maxprice) + float(state.vars.ticks2reset):
##TODO toto nejak vymyslet - duplikovat?
res = asyncio.run(state.cancel_pending_buys())
state.ilog(e=f"UJELO to. Rusime PB", msg=f"{state.vars.ticks2reset=}", pb=state.vars.pendingbuys)
#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 se vyklepaly nastavujeme: neni vylozeno", jevylozeno=state.vars.jevylozeno)
#TODO toto dodelat konzolidaci a mozna lock na limitku a pendingbuys a jevylozeno ??
#kdykoliv se muze notifikace ztratit
# - pendingbuys - vsechny open orders buy
# - limitka - open order sell
#pokud je vylozeno a mame pozice a neexistuje limitka - pak ji vytvorim
# if int(state.oe.poz)>0 and state.oe.limitka == 0:
# #pro jistotu updatujeme pozice
# state.oe.avgp, state.oe.poz = state.oe.pos()
# if int(state.oe.poz) > 0:
# cena = round(float(state.oe.avgp) + float(state.oe.stratvars["profit"]),2)
# print("BUGF: limitka neni vytvarime, a to za cenu",cena,"mnozstvi",state.oe.poz)
# print("aktuzalni ltp",ltp.price[state.oe.symbol])
# try:
# state.oe.limitka = state.oe.sell_noasync(cena, state.oe.poz)
# print("vytvorena limitka", state.oe.limitka)
# except Exception as e:
# print("Neslo vytvorit profitku. Problem,ale jedeme dal",str(e))
# pass
# ##raise Exception(e)
print(10*"*","NEXT STOP",10*"*")
def init(state: StrategyState):
#place to declare new vars
print("INIT v main",state.name)
state.indicators['ema'] = []
state.indicators['slope'] = []
state.indicators['slopeMA'] = []
#static indicators - those not series based
state.statinds['angle'] = dict(minimum_slope=state.vars["minimum_slope"])
state.vars["ticks2reset_backup"] = state.vars.ticks2reset
def main():
# try:
# strat_settings = tomli.loads("]] this is invalid TOML [[")
# except tomli.TOMLDecodeError:
# print("Yep, definitely not valid.")
#strat_settings = dict_replace_value(strat_settings, "None", None)
name = os.path.basename(__file__)
se = Event()
pe = Event()
s = StrategyOrderLimitVykladaci(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

@ -0,0 +1,103 @@
from strategy.base import Strategy, StrategyState
from strategy.strategyOrderLimitWatched import StrategyOrderLimitWatched
from v2realbot.enums.enums import RecordType, StartBarAlign, Mode
from indicators import ema
from rich import print
from utils.utils import ltp, isrising, isfalling,trunc,AttributeDict, zoneNY
from datetime import datetime
from icecream import install, ic
install()
ic.configureOutput(includeContext=True)
#ic.disable()
""""
Simple strategie pro test backtesting
"""
def next(data, state: StrategyState):
print(10*"*","NEXT START",10*"*")
#ic(state.avgp, state.positions)
#ic(state.vars.lastbuyindex)
#ic(data)
#ic(state.positions)
#ic(state.vars.watched)
#ic(state.vars.wait)
try:
state.indicators.ema = ema(state.bars.hlcc4, state.vars.MA) #state.bars.vwap
#trochu prasarna, EMAcko trunc na 3 mista - kdyz se osvedci, tak udelat efektivne
state.indicators.ema = [trunc(i,3) for i in state.indicators.ema]
#ic(state.vars.MA, state.vars.Trend, state.indicators.ema[-5:])
except Exception as e:
print("No data for MA yet", str(e))
print("is falling",isfalling(state.indicators.ema,state.vars.Trend))
print("is rising",isrising(state.indicators.ema,state.vars.Trend))
#ZDE JSEM SKONCIL
#nejprve zacit s BARy
#TODO vyzkoušet limit buy - vetsina z nakupu by se dala koupit o cent dva mene
#proto dodělat LTP pro BT, neco jako get_last_price(self.state.time)
##TODO vyzkouset hlidat si sell objednavku sam na zaklade tradu
# v pripade ze to jde nahoru(is rising - nebo jiny indikator) tak neprodavat
#vyuzit CBARy k tomuto .....
#triggerovat buy treba po polovine CBARu, kdyz se cena bude rovnat nebo bude nizsi nez low
#a hned na to (po potvrzeni) hlidat sell +0.01 nebo kdyz roste nechat rust.vyzkouset na LIVE
datetime.fromtimestamp(state.last_trade_time)
casbaru = datetime.fromtimestamp(state.last_trade_time)-data['time']
kupuj = casbaru.seconds > int(int(data['resolution']) * 0.4)
#ic(kupuj)
#ic(casbaru.seconds)
#kupujeme kdyz v druhe polovine baru je aktualni cena=low (nejnizsi)
#isrising(state.indicators.ema,state.vars.Trend)
#kdyz se v jednom baru pohneme o 2
if kupuj and data['confirmed'] != 1 and data['close'] == data['low'] and float(data['close']) + 0.01 < data['open'] and state.vars.wait is False and state.vars.watched is None:
print("BUY MARKET")
#ic(data['updated'])
#ic(state.time)
##updatneme realnou cenou po fillu
state.buy()
state.vars.wait = True
if state.vars.watched and state.vars.wait is False:
currprice = state.interface.get_last_price(symbol = state.symbol)
#ic(currprice)
if float(currprice) > (float(state.vars.watched) + float(state.vars.profit)):
#ic(state.time)
#ic("prodavame", currprice)
print("PRODAVAME")
##vymyslet jak odchytavat obecne chyby a vracet cislo objednavky
state.interface.sell(size=1)
state.vars.wait = True
print(10*"*","NEXT STOP",10*"*")
def init(state: StrategyState):
#place to declare new vars
print("INIT v main",state.name)
state.vars['novaprom'] = 4
state.indicators['ema'] = []
def main():
stratvars = AttributeDict(maxpozic = 1, chunk = 1, MA = 2, Trend = 2, profit = 0.005, lastbuyindex=-6, pendingbuys={},watched = None, wait = False)
s = StrategyOrderLimitWatched(name = "BackTEST", symbol = "BAC", next=next, init=init, stratvars=stratvars, debug=False)
s.set_mode(mode = Mode.PAPER,
start = datetime(2023, 3, 24, 11, 30, 0, 0, tzinfo=zoneNY),
end = datetime(2023, 3, 24, 11, 45, 0, 0, tzinfo=zoneNY),
cash=100000)
#na sekundovem baru nezaokrouhlovat MAcko
s.add_data(symbol="BAC",rectype=RecordType.CBAR,timeframe=5,filters=None,update_ltp=True,align=StartBarAlign.ROUND,mintick=0)
#s.add_data(symbol="C",rectype=RecordType.BAR,timeframe=1,filters=None,update_ltp=True,align=StartBarAlign.ROUND,mintick=0)
s.start()
if __name__ == "__main__":
main()

View File

@ -0,0 +1,70 @@
from strategy.base import Strategy
from strategy.base import StrategyState
from enums import RecordType, StartBarAlign, Mode
from config import API_KEY, SECRET_KEY, MAX_BATCH_SIZE, PAPER
from indicators import ema
from rich import print
from utils import ltp, isrising, isfalling,trunc,AttributeDict
from datetime import datetime
""""
Simple strategie pro měření roundtripu na konkrétním prostředí
- koupí 1 akcii a vypíše časy
- tradu který triggeroval
- čas triggeru buy
- příchod zpětné notifikace NEW
- příchod zpětné notifikace FILL
- vypíše trade, když přijde do agregátoru (vyžaduje do agregátoru na řádek 79: if int(data['s']) == 1: print(data))
- vyžaduje ve strategy base v orderupdate
- print("NOTIFICATION ARRIVED AT:", datetime.now().timestamp(), datetime.now())
- print(data)
výsledek latencyroudntrip.log
"""
def next(data, state: StrategyState):
print("avgp:", state.avgp)
print("positions", state.positions)
print("přišly tyto data", data)
print("bar updated time:", data['updated'], datetime.fromtimestamp(data['updated']))
print("state time(now):", state.time, datetime.fromtimestamp(state.time))
#print("trades history", state.trades)
#print("bar history", state.bars)
print("ltp", ltp.price["BAC"], ltp.time["BAC"])
try:
ema_output = ema(state.bars.hlcc4, state.vars.MA) #state.bars.vwap
ema_output = [trunc(i,3) for i in ema_output]
print("emacko na wvap",state.vars.MA,":", ema_output[-5:])
except:
print("No data for MA yet")
print("MA is falling",state.vars.Trend,"value:",isfalling(ema_output,state.vars.Trend))
print("MA is rising",state.vars.Trend,"value:",isrising(ema_output,state.vars.Trend))
if isfalling(ema_output,state.vars.Trend) and state.vars.blockbuy == 0:
print("kupujeme MARKET")
print("v baru mame cas posledniho tradu", data['updated'])
print("na LIVE je skutecny cas - tento ", state.time)
print("v nem odesilame")
state.interface.buy(time=state.time)
state.vars.blockbuy = 1
def init(state: StrategyState):
print("INIT strategie", state.name, "symbol", state.symbol)
def main():
stratvars = AttributeDict(maxpozic = 200, chunk = 10, MA = 3, Trend = 3, profit = 0.01, blockbuy=0, lastbuyindex=0, pendingbuys={})
s = Strategy(name = "BackTEST", symbol = "BAC", next=next, init=init, stratvars=stratvars)
#s.set_mode(mode = Mode.BT, start= datetime(2023, 3, 16, 15, 54, 30, 0), end=datetime(2023, 3, 16, 15, 54, 40, 999999))
s.add_data(symbol="BAC",rectype=RecordType.BAR,timeframe=5,filters=None,update_ltp=True,align=StartBarAlign.ROUND,mintick=0)
#s.add_data(symbol="C",rectype=RecordType.BAR,timeframe=1,filters=None,update_ltp=True,align=StartBarAlign.ROUND,mintick=0)
s.start()
if __name__ == "__main__":
main()

View File

@ -0,0 +1,5 @@
##pro refactor vykladaci strategie: tipy:
##pri CANCEL pendindbuys - lokalni pending buys zrušit hnedka po synchronním odeslání, nemusim cekat na potvrzeni
##ve zpetne notifikaci FILLU - je uvedena aktuální počet pozice - tzn. nemusím volat POS, ale jen si je dotahnu odsud. Pozor avgp tu neni.

View File

@ -0,0 +1,200 @@
from strategy import MyStrategy, StrategyState, Strategy
from enums import RecordType, StartBarAlign
from config import API_KEY, SECRET_KEY, MAX_BATCH_SIZE, PAPER
from indicators import ema
from rich import print
from utils import ltp, isrising, isfalling,trunc
""""
TBD - zpomalit - nekupovat okamzite nechat dychat
MA Vykládcí Strategie s LIMIT BUY
# aktualni nastaveni - VELMI AGRESIVNI, STALE KUPUJE, IDEALNI NA POTVRZENE RUSTOVE DNY
- jede na 10s
- BUY and HOLD alternative
- dat do seznamu hotovych strategii
atributy:
ticks2reset - počet ticků po kterých se resetnou prikazy pokud neni plneni
TODO:
- pridat reconciliaci po kazdem X tem potvrzenem baru - konzolidace otevrenych pozic a limitek
- do kazde asynchronni notifkace orderupdate dat ochranu, kdyz uz ten stav neplati (tzn. napr. pro potvrzeni buye se uz prodalo)
- podchytit: kdykoliv limitka neexistuje, ale mam pozice, tak ji vytvorit (podchytit situace v rush hours)
- cancel pendign buys - dictionary changed size during iteration podychytit. lock
"""
ticks2reset = 0.03
#TODO pokud bar klesne o jeden nebo vice - tak signál - DEFENZIVNI MOD
#TODO pouzivat tu objekt ochrana (ktery jen vlozim do kodu a kdyz vrati exceptionu tak jdeme do dalsi iterace)
# tak zustane strategie cista
#TODO rušit (pending buys) když oe.poz = 0 a od nejvetsi pending buys je
# ltp.price vice nez 5 ticků
def next(data, state: StrategyState):
def vyloz(pozic: int):
print("vykladame na pocet pozic", pozic)
# defenzivni krivka
curve = [0.01, 0.01, 0.01, 0.02, 0.02, 0.02, 0.02,0.03,0.03,0.03,0.03, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04]
#cent curve = [0.01, 0.01, 0.01,0.01, 0.01, 0.01,0.01, 0.01,0.01, 0.01, 0.01, 0.01,0.01, 0.01,0.01, 0.01,0.01, 0.01,0.01, 0.01,0.01, 0.01,0.01, 0.01,0.01, 0.01]
#defenzivnejsi s vetsimi mezerami v druhe tretine a vetsi vahou pro dokupy
# krivka pro AVG, tzn. exponencialne pridavame 0.00
curve = [0.01, 0, 0.01, 0, 0, 0.01, 0, 0, 0, 0.01, 0, 0, 0, 0, 0.01, 0, 0, 0, 0, 0, 0.01, 0,0,0,0,0,0, 0.01, 0,0,0,0,0,0,0,0,0.01,0,0,0,0,0,0,0,0,0, 0.01,0,0,0,0,0,0,0,0,0,0.01, 0,0,0,0,0,00,0,0,0, 0.5, 0,0,0,0,0.5,0,0,0]
# 10ty clen je o 0.05 tzn.triggeruje nam to tick2reset
#curve = [0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.02, 0.02, 0.05, 0.01, 0.04, 0.01, 0.01, 0.04, 0.05, 0.03, 0.05, 0.01, 0.03, 0.01,0.01, 0.04, 0.01, 0.05,0.01, 0.01,0.01, 0.01]
#defenzivni krivku nastavime vetsimi mezerami a v nich 0.01 - tim se prida vetsi mnostvi a vic se naredi
# 0.04, 0.01,
#curve = [0.01,0.01, 0.01, 0.02, 0.02, 0.02, 0.02]
#cena pro prvni objednavky
price = trunc(float(ltp.price[state.oe.symbol]),2)
print("aktualni cena pri vykladu - pro prvni", price)
qty = int(state.variables.chunk)
last_price = price
if len(curve) < pozic:
pozic = len(curve)
#stejné ceny posilame jako jednu objednávku
for i in range(0,pozic):
price = round(float(price - curve[i]),2)
if price == last_price:
qty = qty + int(state.variables.chunk)
else:
#flush last_price and stored qty
# OPT: pokud bude kupovat prilis brzy, osvedcila se prvni cena -0.01 (tzn. stavi prehodit last_price za price)
state.oe.buy_l(price=last_price, size=qty, force=1)
print(i,"BUY limitka - delta",curve[i]," cena:", price, "mnozstvi:", qty)
qty = int(state.variables.chunk)
last_price = price
#TODO pokud cena stejna jako predchozi, tak navys predchozi - abychom nemeli vice objednavek na stejne cene (zbytecne)
print("pending buys", state.oe.stratvars['pendingbuys'])
print("je vylozeno",state.oe.stratvars['jevylozeno'])
print("avg,poz,limitka",state.oe.avgp, state.oe.poz, state.oe.limitka)
print("last buy price", state.oe.lastbuy)
#CBAR protection, only 1x order per CBAR - then wait until another confirmed bar
if state.variables.blockbuy == 1:
if state.bars.confirmed[-1] == 0:
print("OCHR: multibuy protection. waiting for next bar")
return 0
# pop potvrzeni jeste jednou vratime (aby se nekoupilo znova, je stale ten stejny bar)
# a pak dalsi vejde az po minticku
else:
# pro vykladaci
state.variables.blockbuy = 0
return 0
#print(state.bars) .
# print("next")
# print(data)
#TODO zkusit hlcc4
try:
ema_output = ema(state.bars.vwap, state.variables.MA)
#trochu prasarna, EMAcko trunc na 3 mista - kdyz se osvedci, tak udelat efektivne
ema_output = [trunc(i,3) for i in ema_output]
print("emacko na wvap",state.variables.MA,":", ema_output[-5:])
except:
print("No data for MA yet")
print("MA is falling",state.variables.Trend,"value:",isfalling(ema_output,state.variables.Trend))
print("MA is rising",state.variables.Trend,"value:",isrising(ema_output,state.variables.Trend))
## 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
if state.oe.stratvars['jevylozeno'] == 1: # and int(state.oe.poz) == 0:
#pokud mame vylozeno a cena je vetsi nez 0.04
if len(state.oe.stratvars['pendingbuys'])>0:
a = max(state.oe.stratvars['pendingbuys'].values())
print("max cena v orderbuys", a)
if float(ltp.price[state.oe.symbol]) > float(a) + ticks2reset:
print("ujelo to vice nez o 4, rusime limit buye")
state.oe.cancel_pending_buys()
state.oe.stratvars['jevylozeno'] = 0
#pokud je vylozeno a mame pozice a neexistuje limitka - pak ji vytvorim
if int(state.oe.poz)>0 and state.oe.limitka == 0:
#pro jistotu updatujeme pozice
state.oe.avgp, state.oe.poz = state.oe.pos()
if int(state.oe.poz) > 0:
cena = round(float(state.oe.avgp) + float(state.oe.stratvars["profit"]),2)
print("BUGF: limitka neni vytvarime, a to za cenu",cena,"mnozstvi",state.oe.poz)
print("aktuzalni ltp",ltp.price[state.oe.symbol])
try:
state.oe.limitka = state.oe.sell_noasync(cena, state.oe.poz)
print("vytvorena limitka", state.oe.limitka)
except Exception as e:
print("Neslo vytvorit profitku. Problem,ale jedeme dal",str(e))
pass
##raise Exception(e)
if state.oe.stratvars['jevylozeno'] == 0:
print("neni vylozeno. Muzeme nakupovat")
# testuji variantu, ze kupuji okamzite, nehlede na vyvoj
if isfalling(ema_output,state.variables.Trend): # or 1==1:
## vyloz pro pocet pozic (maximalni minus aktualni)
#kolik nam zbyva pozic
#HOKUS: vykladame pouze polovinu pozic - dalsi polovinu davame v dalsimrunu
# a = available pozice a/2
a = int(int(state.variables.maxpozic)/int(state.variables.chunk)-(int(state.oe.poz)/int(state.variables.chunk)))
a = int(a)
print("Vykladame na pocet pozic", a)
vyloz(pozic=a)
#blokneme nakupy na dalsi bar
state.variables.blockbuy = 1
state.oe.stratvars['jevylozeno'] = 1
#ulozime id baru
# state.variables.lastbuyindex = state.bars.index[-1]
# je vylozeno
else:
## po kazde 4te pozici delame revykladani na aktualni zbytek pozic
if (int(state.oe.poz)/(int(state.variables.chunk)) % 4 == 0):
print("ctvrta pozice - v budoucnu realignujeme")
# state.oe.cancel_pending_buys()
# ##smazeme ihned pole - necekame na notifiaci
# vyloz((int(state.variables.maxpozic)-int(state.oe.poz)/state.variables.chunk))
#kazdy potvrzeny bar dotahneme pro jistotu otevřené objednávky a nahradíme si stav aktuálním
#pro jistotu update pozic - kdyz se nic nedeje nedeje
#pripadne dat pryc
#print("upatujeme pozice")
#state.oe.avgp, state.oe.poz = state.oe.pos()
def init(state: StrategyState):
print("init - zatim bez data")
print(state.oe.symbol)
print(state.oe.pos())
print()
def main():
stratvars = dict(maxpozic = 2000, chunk = 20, MA = 3, Trend = 4, profit = 0.01, blockbuy=0, lastbuyindex=0, pendingbuys={}, jevylozeno=0)
s = MyStrategy("BAC",paper=PAPER, next=next, init=init, stratvars=stratvars)
s.add_data(symbol="BAC",rectype=RecordType.CBAR,timeframe=12,filters=None,update_ltp=True,align=StartBarAlign.ROUND,mintick=4)
s.start()
if __name__ == "__main__":
main()

View File

@ -0,0 +1,27 @@
from strategy import MyStrategy, StrategyState
from enums import RecordType, StartBarAlign
from config import API_KEY, SECRET_KEY, MAX_BATCH_SIZE, PAPER
from indicators import ema
from rich import print
def next(data, state: StrategyState):
print("next")
print(state.variables.MA)
print(state.variables.maxpozic)
print(data)
print(state.oe.pos())
def init(state: StrategyState):
print("init - zatim bez data")
print(state.oe.symbol)
print(state.oe.pos())
print()
def main():
stratvars = dict(maxpozic = 10, chunk = 1, MA = 3, Trend = 4,profit = 0.01)
s = MyStrategy("TSLA",paper=PAPER, next=next, init=init, stratvars=stratvars)
s.add_data(symbol="TSLA",rectype=RecordType.TRADE,timeframe=5,filters=None,update_ltp=True,align=StartBarAlign.ROUND,mintick=0)
s.start()
if __name__ == "__main__":
main()