ready2live test

This commit is contained in:
David Brazda
2023-04-25 17:31:04 +02:00
parent a40b899b1d
commit 4edcb31a7b
7 changed files with 90 additions and 25 deletions

View File

@ -33,10 +33,12 @@ Do budoucna vice ridit nakupy pri klesani - napr. vyložení jen 2-3 pozic a dal
# #
""" """
stratvars = AttributeDict(maxpozic = 400, stratvars = AttributeDict(maxpozic = 400,
def_mode_from = 200,
chunk = 10, chunk = 10,
MA = 2, MA = 2,
Trend = 2, Trend = 2,
profit = 0.02, profit = 0.02,
def_profit = 0.01,
lastbuyindex=-6, lastbuyindex=-6,
pendingbuys={}, pendingbuys={},
limitka = None, limitka = None,
@ -93,6 +95,27 @@ def next(data, state: StrategyState):
#ic(state.vars) #ic(state.vars)
#ic(data) #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))
#mozna presunout o level vys #mozna presunout o level vys
def vyloz(): def vyloz():
##prvni se vyklada na aktualni cenu, další jdou podle krivky, nula v krivce zvyšuje množství pro následující iteraci ##prvni se vyklada na aktualni cenu, další jdou podle krivky, nula v krivce zvyšuje množství pro následující iteraci
@ -104,25 +127,22 @@ def next(data, state: StrategyState):
vykladka = state.vars.vykladka vykladka = state.vars.vykladka
#kolik muzu max vylozit #kolik muzu max vylozit
kolikmuzu = int((int(state.vars.maxpozic) - int(state.positions))/int(state.vars.chunk)) kolikmuzu = int((int(state.vars.maxpozic) - int(state.positions))/int(state.vars.chunk))
akt_pozic = int((int(state.positions))/int(state.vars.chunk)) #20 akt_pozic = int(state.positions)
max_pozic = int((int(state.vars.maxpozic))/int(state.vars.chunk)) #40 max_pozic = int(state.vars.maxpozic)
#mame polovinu a vic vylozeno, pouzivame defenzicni krivku #mame polovinu a vic vylozeno, pouzivame defenzicni krivku
if (akt_pozic >= max_pozic/2): if is_defensive_mode():
state.ilog(e="DEF: Mame pul a vic vylozeno, pouzivame defenzivni krivku", akt_pozic=akt_pozic, max_pozic=max_pozic, curve_def=curve_def) state.ilog(e="DEF: Pouzivame defenzivni krivku", akt_pozic=akt_pozic, max_pozic=max_pozic, curve_def=curve_def)
curve = curve_def curve = curve_def
#zaroven docasne menime ticks2reset na defenzivni 0.06 #zaroven docasne menime ticks2reset na defenzivni 0.06
state.vars.ticks2reset = 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) state.ilog(e="DEF: Menime tick2reset na 0.06", ticks2reset=state.vars.ticks2reset, ticks2reset_backup=state.vars.ticks2reset_backup)
defense = True
else: else:
defense = False
#vracime zpet, pokud bylo zmeneno #vracime zpet, pokud bylo zmeneno
if state.vars.ticks2reset != state.vars.ticks2reset_backup: if state.vars.ticks2reset != state.vars.ticks2reset_backup:
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) 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 kolikmuzu < vykladka: vykladka = kolikmuzu
if len(curve) < vykladka: if len(curve) < vykladka:
@ -137,9 +157,11 @@ def next(data, state: StrategyState):
##VAR - na zaklade conf. muzeme jako prvni posilat MARKET order ##VAR - na zaklade conf. muzeme jako prvni posilat MARKET order
if safe_get(state.vars, "first_buy_market") == True: if safe_get(state.vars, "first_buy_market") == True:
#pri defenzivnim rezimu pouzivame vzdy LIMIT order #pri defenzivnim rezimu pouzivame vzdy LIMIT order
if defense: if is_defensive_mode():
state.ilog(e="DEF mode on, odesilame jako prvni limitku")
state.buy_l(price=price, size=qty) state.buy_l(price=price, size=qty)
else: else:
state.ilog(e="Posilame jako prvni MARKET order")
state.buy(size=qty) state.buy(size=qty)
else: else:
state.buy_l(price=price, size=qty) state.buy_l(price=price, size=qty)
@ -277,7 +299,7 @@ def next(data, state: StrategyState):
#neni limitka, ale mela by byt - vytváříme ji #neni limitka, ale mela by byt - vytváříme ji
if int(state.positions) > 0 and state.vars.limitka is None: 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=}") state.ilog(e="Limitka neni, ale mela by být.", msg=f"{state.positions=}")
price=price2dec(float(state.avgp)+state.vars.profit) price=get_limitka_price()
state.vars.limitka = asyncio.run(state.interface.sell_l(price=price, size=int(state.positions))) state.vars.limitka = asyncio.run(state.interface.sell_l(price=price, size=int(state.positions)))
state.vars.limitka_price = price state.vars.limitka_price = price
if state.vars.limitka == -1: if state.vars.limitka == -1:
@ -287,12 +309,13 @@ def next(data, state: StrategyState):
else: else:
state.ilog(e="Vytvořena nová limitka", limitka=str(state.vars.limitka), limtka_price=state.vars.limitka_price, qty=state.positions) state.ilog(e="Vytvořena nová limitka", limitka=str(state.vars.limitka), limtka_price=state.vars.limitka_price, qty=state.positions)
elif state.vars.limitka is not None and int(state.positions) > 0 and (int(state.positions) != int(limitka_qty)): #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 #limitka existuje, ale spatne mnostvi - updatujeme
state.ilog(e=f"Limitka existuje, ale spatne mnozstvi - updatujeme", msg=f"{state.positions=} {limitka_qty=}", pos=state.positions, limitka_qty=limitka_qty) 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 #snad to nespadne, kdyztak pridat exception handling
puvodni = state.vars.limitka puvodni = state.vars.limitka
state.vars.limitka = asyncio.run(state.interface.repl(price=state.vars.limitka_price, orderid=state.vars.limitka, size=int(state.positions))) 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: if state.vars.limitka == -1:
state.ilog(e="Replace limitky neprobehl, vracime puvodni", msg=f"{state.vars.limitka=}", puvodni=puvodni) state.ilog(e="Replace limitky neprobehl, vracime puvodni", msg=f"{state.vars.limitka=}", puvodni=puvodni)
@ -334,7 +357,7 @@ def next(data, state: StrategyState):
#HLAVNI ITERACNI LOG JESTE PRED AKCI - obsahuje aktualni hodnoty vetsiny parametru #HLAVNI ITERACNI LOG JESTE PRED AKCI - obsahuje aktualni hodnoty vetsiny parametru
lp = state.interface.get_last_price(symbol=state.symbol) lp = state.interface.get_last_price(symbol=state.symbol)
state.ilog(e="ENTRY", msg=f"LP:{lp} P:{state.positions}/{round(float(state.avgp),2)} profit:{round(float(state.profit),2)} Trades:{len(state.tradeList)}", last_price=lp, stratvars=state.vars) state.ilog(e="ENTRY", msg=f"LP:{lp} P:{state.positions}/{round(float(state.avgp),2)} profit:{round(float(state.profit),2)} Trades:{len(state.tradeList)} DEF:{str(is_defensive_mode())}", last_price=lp, stratvars=state.vars)
#maxSlopeMA = -0.03 #maxSlopeMA = -0.03
#SLOPE ANGLE PROTECTIONs #SLOPE ANGLE PROTECTIONs
@ -362,10 +385,11 @@ def next(data, state: StrategyState):
if state.vars.jevylozeno == 0: if state.vars.jevylozeno == 0:
print("Neni vylozeno, muzeme testovat nakup") 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: if isfalling(state.indicators.ema,state.vars.Trend) and slope > minimum_slope:
print("BUY MARKET")
#zatim vykladame full
#positions = int(int(state.vars.maxpozic)/int(state.vars.chunk))
vyloz() vyloz()
## testuje aktualni cenu od nejvyssi visici limitky ## testuje aktualni cenu od nejvyssi visici limitky

View File

@ -251,7 +251,11 @@ class Backtester:
#(1679081919.381649, 27.88) #(1679081919.381649, 27.88)
#ic(i) #ic(i)
fill_time = i[0] fill_time = i[0]
fill_price = i[1]
#v BT nikdy nekoupime za lepsi cenu nez LIMIT price (TBD mozna zmenit na parametr)
fill_price = o.limit_price
#fill_price = i[1]
print("FILL LIMIT BUY at", fill_time, datetime.fromtimestamp(fill_time).astimezone(zoneNY), "at",i[1]) print("FILL LIMIT BUY at", fill_time, datetime.fromtimestamp(fill_time).astimezone(zoneNY), "at",i[1])
if BT_FILL_LOG_SURROUNDING_TRADES != 0: if BT_FILL_LOG_SURROUNDING_TRADES != 0:
#TODO loguru #TODO loguru
@ -281,7 +285,13 @@ class Backtester:
#(1679081919.381649, 27.88) #(1679081919.381649, 27.88)
#ic(i) #ic(i)
fill_time = i[0] fill_time = i[0]
fill_price = i[1]
#support pomaleho plneni
#v BT nikdy neprodame za lepsi cenu nez LIMIT price (TBD mozna zmenit na parametr)
fill_price = o.limit_price
#fill_price = i[1]
print("FILL LIMIT SELL at", fill_time, datetime.fromtimestamp(fill_time).astimezone(zoneNY), "at",i[1]) print("FILL LIMIT SELL at", fill_time, datetime.fromtimestamp(fill_time).astimezone(zoneNY), "at",i[1])
if BT_FILL_LOG_SURROUNDING_TRADES != 0: if BT_FILL_LOG_SURROUNDING_TRADES != 0:
#TODO loguru #TODO loguru
@ -572,6 +582,7 @@ class Backtester:
res.append(o) res.append(o)
return res return res
##toto bude predelano na display_results(ve variantach) umozni zobrazit result jak BT tak LIVE
def display_backtest_result(self, state): def display_backtest_result(self, state):
""" """
Displays backtest results chart, trades and orders with option to save the result as static HTML. Displays backtest results chart, trades and orders with option to save the result as static HTML.
@ -755,6 +766,13 @@ class Backtester:
Open orders:''' + str(len(self.open_orders))) Open orders:''' + str(len(self.open_orders)))
textik7 = html.Div(''' textik7 = html.Div('''
Trades:''' + str(len(self.trades))) Trades:''' + str(len(self.trades)))
textik8 = html.Div('''
Profit:''' + str(state.profit))
textik9 = html.Div(f"{BT_FILL_CONS_TRADES_REQUIRED=}")
textik10 = html.Div(f"{BT_FILL_LOG_SURROUNDING_TRADES=}")
textik11 = html.Div(f"{BT_FILL_CONDITION_BUY_LIMIT=}")
textik12 = html.Div(f"{BT_FILL_CONDITION_SELL_LIMIT=}")
orders_title = dcc.Markdown('## Open orders') orders_title = dcc.Markdown('## Open orders')
trades_title = dcc.Markdown('## Trades') trades_title = dcc.Markdown('## Trades')
## Define the graph ## Define the graph
@ -867,7 +885,7 @@ class Backtester:
return 'saved' return 'saved'
## Customize your layout ## Customize your layout
app.layout = dbc.Container([mytitle,button,saved, textik1, textik2, textik3, textik35, textik4, textik5, textik55, textik6,textik7, mygraph, trades_title, trades_table, orders_title, open_orders_table]) app.layout = dbc.Container([mytitle,button,saved, textik1, textik2, textik3, textik35, textik4, textik5, textik55, textik6,textik7, textik8, textik9, textik10, textik11, textik12, mygraph, trades_title, trades_table, orders_title, open_orders_table])
port = 9050 port = 9050
print("Backtest FINSIHED"+str(self.backtest_end-self.backtest_start)) print("Backtest FINSIHED"+str(self.backtest_end-self.backtest_start))

View File

@ -9,14 +9,14 @@ QUIET_MODE = False
#N - N consecutive trades required #N - N consecutive trades required
#not impl.yet #not impl.yet
#minimum is 1, na alpace live to vetsinou vychazi 7-8 u BAC, je to hodne podobne tomu, nez je cena překonaná pul centu. tzn. 7-8 a nebo FillCondition.SLOW #minimum is 1, na alpace live to vetsinou vychazi 7-8 u BAC, je to hodne podobne tomu, nez je cena překonaná pul centu. tzn. 7-8 a nebo FillCondition.SLOW
BT_FILL_CONS_TRADES_REQUIRED = 3 BT_FILL_CONS_TRADES_REQUIRED = 2
#during bt trade execution logs X-surrounding trades of the one that triggers the fill #during bt trade execution logs X-surrounding trades of the one that triggers the fill
BT_FILL_LOG_SURROUNDING_TRADES = 10 BT_FILL_LOG_SURROUNDING_TRADES = 10
#fill condition for limit order in bt #fill condition for limit order in bt
# fast - price has to be equal or bigger <= # fast - price has to be equal or bigger <=
# slow - price has to be bigger < # slow - price has to be bigger <
BT_FILL_CONDITION_BUY_LIMIT = FillCondition.FAST BT_FILL_CONDITION_BUY_LIMIT = FillCondition.SLOW
BT_FILL_CONDITION_SELL_LIMIT = FillCondition.FAST BT_FILL_CONDITION_SELL_LIMIT = FillCondition.SLOW
#backend counter of api requests #backend counter of api requests
COUNT_API_REQUESTS = False COUNT_API_REQUESTS = False
#stratvars that cannot be changed in gui #stratvars that cannot be changed in gui

View File

@ -1,5 +1,5 @@
from v2realbot.strategy.base import Strategy from v2realbot.strategy.base import Strategy
from v2realbot.utils.utils import parse_alpaca_timestamp, ltp, AttributeDict,trunc,price2dec, zoneNY, print, json_serial from v2realbot.utils.utils import parse_alpaca_timestamp, ltp, AttributeDict,trunc,price2dec, zoneNY, print, json_serial, safe_get
from v2realbot.utils.tlog import tlog, tlog_exception from v2realbot.utils.tlog import tlog, tlog_exception
from v2realbot.enums.enums import Mode, Order, Account from v2realbot.enums.enums import Mode, Order, Account
from alpaca.trading.models import TradeUpdate from alpaca.trading.models import TradeUpdate
@ -37,7 +37,8 @@ class StrategyOrderLimitVykladaci(Strategy):
self.state.positions = data.position_qty self.state.positions = data.position_qty
if self.state.vars.limitka is None: if self.state.vars.limitka is None:
self.state.avgp = float(data.price) self.state.avgp = float(data.price)
price=price2dec(float(o.filled_avg_price)+self.state.vars.profit) #price=price2dec(float(o.filled_avg_price)+self.state.vars.profit)
price = await self.get_limitka_price()
self.state.vars.limitka = await self.interface.sell_l(price=price, size=o.filled_qty) self.state.vars.limitka = await self.interface.sell_l(price=price, size=o.filled_qty)
#obcas live vrati "held for orders", odchytime chybu a limitku nevytvarime - spravi to dalsi notifikace nebo konzolidace #obcas live vrati "held for orders", odchytime chybu a limitku nevytvarime - spravi to dalsi notifikace nebo konzolidace
if self.state.vars.limitka == -1: if self.state.vars.limitka == -1:
@ -49,7 +50,8 @@ class StrategyOrderLimitVykladaci(Strategy):
else: else:
#avgp, pos #avgp, pos
self.state.avgp, self.state.positions = self.state.interface.pos() self.state.avgp, self.state.positions = self.state.interface.pos()
cena = price2dec(float(self.state.avgp) + float(self.state.vars.profit)) #cena = price2dec(float(self.state.avgp) + float(self.state.vars.profit))
cena = await self.get_limitka_price()
try: try:
puvodni = self.state.vars.limitka puvodni = self.state.vars.limitka
self.state.vars.limitka = await self.interface.repl(price=cena,orderid=self.state.vars.limitka,size=int(self.state.positions)) self.state.vars.limitka = await self.interface.repl(price=cena,orderid=self.state.vars.limitka,size=int(self.state.positions))
@ -175,3 +177,24 @@ class StrategyOrderLimitVykladaci(Strategy):
self.state.vars.jevylozeno = 0 self.state.vars.jevylozeno = 0
print("cancel pending buys end") print("cancel pending buys end")
self.state.ilog(e="Dokončeno zruseni vsech pb", pb=self.state.vars.pendingbuys) self.state.ilog(e="Dokončeno zruseni vsech pb", pb=self.state.vars.pendingbuys)
#kopie funkci co jsou v next jen async, nejak vymyslet, aby byly jen jedny
async def is_defensive_mode(self):
akt_pozic = int(self.state.positions)
max_pozic = int(self.state.vars.maxpozic)
def_mode_from = safe_get(self.state.vars, "def_mode_from")
if def_mode_from == None: def_mode_from = max_pozic/2
if akt_pozic >= int(def_mode_from):
self.state.ilog(e=f"DEFENSIVE MODE active {self.state.vars.def_mode_from=}", msg=self.state.positions)
return True
else:
self.state.ilog(e=f"STANDARD MODE active {self.state.vars.def_mode_from=}", msg=self.state.positions)
return False
async def get_limitka_price(self):
def_profit = safe_get(self.state.vars, "def_profit")
if def_profit == None: def_profit = self.state.vars.profit
if await self.is_defensive_mode():
return price2dec(float(self.state.avgp)+float(def_profit))
else:
return price2dec(float(self.state.avgp)+float(self.state.vars.profit))