diff --git a/v2realbot/ENTRY_backtest_strategyVykladaci.py b/v2realbot/ENTRY_backtest_strategyVykladaci.py index de54ef1..6e06116 100644 --- a/v2realbot/ENTRY_backtest_strategyVykladaci.py +++ b/v2realbot/ENTRY_backtest_strategyVykladaci.py @@ -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 diff --git a/v2realbot/__pycache__/config.cpython-310.pyc b/v2realbot/__pycache__/config.cpython-310.pyc index 8a9750e..31817bd 100644 Binary files a/v2realbot/__pycache__/config.cpython-310.pyc and b/v2realbot/__pycache__/config.cpython-310.pyc differ diff --git a/v2realbot/backtesting/__pycache__/backtester.cpython-310.pyc b/v2realbot/backtesting/__pycache__/backtester.cpython-310.pyc index cbb92f7..c64b33f 100644 Binary files a/v2realbot/backtesting/__pycache__/backtester.cpython-310.pyc and b/v2realbot/backtesting/__pycache__/backtester.cpython-310.pyc differ diff --git a/v2realbot/backtesting/backtester.py b/v2realbot/backtesting/backtester.py index 9852c0a..7f5cd8b 100644 --- a/v2realbot/backtesting/backtester.py +++ b/v2realbot/backtesting/backtester.py @@ -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)) diff --git a/v2realbot/config.py b/v2realbot/config.py index 6e15f25..a272a83 100644 --- a/v2realbot/config.py +++ b/v2realbot/config.py @@ -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 diff --git a/v2realbot/strategy/StrategyOrderLimitVykladaci.py b/v2realbot/strategy/StrategyOrderLimitVykladaci.py index 53bac50..add4877 100644 --- a/v2realbot/strategy/StrategyOrderLimitVykladaci.py +++ b/v2realbot/strategy/StrategyOrderLimitVykladaci.py @@ -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)) \ No newline at end of file diff --git a/v2realbot/strategy/__pycache__/StrategyOrderLimitVykladaci.cpython-310.pyc b/v2realbot/strategy/__pycache__/StrategyOrderLimitVykladaci.cpython-310.pyc index 9a896e1..ad85ab9 100644 Binary files a/v2realbot/strategy/__pycache__/StrategyOrderLimitVykladaci.cpython-310.pyc and b/v2realbot/strategy/__pycache__/StrategyOrderLimitVykladaci.cpython-310.pyc differ