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,
def_mode_from = 200,
chunk = 10,
MA = 2,
Trend = 2,
profit = 0.02,
def_profit = 0.01,
lastbuyindex=-6,
pendingbuys={},
limitka = None,
@ -93,6 +95,27 @@ def next(data, state: StrategyState):
#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))
#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
@ -104,25 +127,22 @@ def next(data, state: StrategyState):
vykladka = state.vars.vykladka
#kolik muzu max vylozit
kolikmuzu = int((int(state.vars.maxpozic) - int(state.positions))/int(state.vars.chunk))
akt_pozic = int((int(state.positions))/int(state.vars.chunk)) #20
max_pozic = int((int(state.vars.maxpozic))/int(state.vars.chunk)) #40
akt_pozic = int(state.positions)
max_pozic = int(state.vars.maxpozic)
#mame polovinu a vic vylozeno, pouzivame defenzicni krivku
if (akt_pozic >= max_pozic/2):
state.ilog(e="DEF: Mame pul a vic vylozeno, pouzivame defenzivni krivku", akt_pozic=akt_pozic, max_pozic=max_pozic, curve_def=curve_def)
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)
defense = True
else:
defense = False
#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:
@ -137,9 +157,11 @@ def next(data, state: StrategyState):
##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 defense:
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)
@ -277,7 +299,7 @@ def next(data, state: StrategyState):
#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=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_price = price
if state.vars.limitka == -1:
@ -287,12 +309,13 @@ def next(data, state: StrategyState):
else:
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
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
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:
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
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
#SLOPE ANGLE PROTECTIONs
@ -362,10 +385,11 @@ def next(data, state: StrategyState):
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:
print("BUY MARKET")
#zatim vykladame full
#positions = int(int(state.vars.maxpozic)/int(state.vars.chunk))
vyloz()
## testuje aktualni cenu od nejvyssi visici limitky

View File

@ -251,7 +251,11 @@ class Backtester:
#(1679081919.381649, 27.88)
#ic(i)
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])
if BT_FILL_LOG_SURROUNDING_TRADES != 0:
#TODO loguru
@ -281,7 +285,13 @@ class Backtester:
#(1679081919.381649, 27.88)
#ic(i)
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])
if BT_FILL_LOG_SURROUNDING_TRADES != 0:
#TODO loguru
@ -572,6 +582,7 @@ class Backtester:
res.append(o)
return res
##toto bude predelano na display_results(ve variantach) umozni zobrazit result jak BT tak LIVE
def display_backtest_result(self, state):
"""
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)))
textik7 = html.Div('''
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')
trades_title = dcc.Markdown('## Trades')
## Define the graph
@ -867,7 +885,7 @@ class Backtester:
return 'saved'
## 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
print("Backtest FINSIHED"+str(self.backtest_end-self.backtest_start))

View File

@ -9,14 +9,14 @@ QUIET_MODE = False
#N - N consecutive trades required
#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
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
BT_FILL_LOG_SURROUNDING_TRADES = 10
#fill condition for limit order in bt
# fast - price has to be equal or bigger <=
# slow - price has to be bigger <
BT_FILL_CONDITION_BUY_LIMIT = FillCondition.FAST
BT_FILL_CONDITION_SELL_LIMIT = FillCondition.FAST
BT_FILL_CONDITION_BUY_LIMIT = FillCondition.SLOW
BT_FILL_CONDITION_SELL_LIMIT = FillCondition.SLOW
#backend counter of api requests
COUNT_API_REQUESTS = False
#stratvars that cannot be changed in gui

View File

@ -1,5 +1,5 @@
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.enums.enums import Mode, Order, Account
from alpaca.trading.models import TradeUpdate
@ -37,7 +37,8 @@ class StrategyOrderLimitVykladaci(Strategy):
self.state.positions = data.position_qty
if self.state.vars.limitka is None:
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)
#obcas live vrati "held for orders", odchytime chybu a limitku nevytvarime - spravi to dalsi notifikace nebo konzolidace
if self.state.vars.limitka == -1:
@ -49,7 +50,8 @@ class StrategyOrderLimitVykladaci(Strategy):
else:
#avgp, 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:
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))
@ -175,3 +177,24 @@ class StrategyOrderLimitVykladaci(Strategy):
self.state.vars.jevylozeno = 0
print("cancel pending buys end")
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))