max profit a loss to quit incorporated

This commit is contained in:
David Brazda
2023-09-01 12:07:11 +02:00
parent a668033138
commit e067a43dda
6 changed files with 78 additions and 14 deletions

View File

@ -1121,6 +1121,7 @@ def next(data, state: StrategyState):
#check activation #check activation
if activated is False: if activated is False:
state.ilog(e=f"{signalname} not ACTIVATED")
cond_dict = state.vars.conditions[KW.activate][signalname] cond_dict = state.vars.conditions[KW.activate][signalname]
result, conditions_met = evaluate_directive_conditions(cond_dict, "OR") result, conditions_met = evaluate_directive_conditions(cond_dict, "OR")
state.ilog(e=f"EVAL ACTIVATION CONDITION =OR= {result}", **conditions_met, cond_dict=cond_dict) state.ilog(e=f"EVAL ACTIVATION CONDITION =OR= {result}", **conditions_met, cond_dict=cond_dict)
@ -1134,7 +1135,8 @@ def next(data, state: StrategyState):
state.ilog(e=f"not ACTIVATED") state.ilog(e=f"not ACTIVATED")
return False return False
else: else:
state.vars.signals[signalname].activated = True state.ilog(e=f"{signalname} JUST ACTIVATED")
state.vars.signals[signalname]["activated"] = True
# OBECNE PRECONDITIONS - typu dont_do_when # OBECNE PRECONDITIONS - typu dont_do_when
precond_check = dict(AND=dict(), OR=dict()) precond_check = dict(AND=dict(), OR=dict())
@ -1148,19 +1150,19 @@ def next(data, state: StrategyState):
# dont_buy_when['jevylozeno_active'] = (state.vars.jevylozeno == 1) # dont_buy_when['jevylozeno_active'] = (state.vars.jevylozeno == 1)
#obecne open_rush platne pro vsechny #obecne open_rush platne pro vsechny
precond_check['on_confirmed_only'] = safe_get(options, 'on_confirmed_only', False) #precond_check['on_confirmed_only'] = safe_get(options, 'on_confirmed_only', False) - chybi realizace podminky, pripadne dodelat na short_on_confirmed
precond_check['short_enabled'] = safe_get(options, "short_enabled",safe_get(state.vars, "short_enabled",True))
precond_check['long_enabled'] = safe_get(options, "long_enabled",safe_get(state.vars, "long_enabled",True))
# #testing preconditions # #testing preconditions
result, cond_met = eval_cond_dict(precond_check) result, cond_met = eval_cond_dict(precond_check)
if result: if result:
state.ilog(e=f"PRECOND GENERAL not met {cond_met}", message=cond_met, precond_check=precond_check) state.ilog(e=f"PRECOND GENERAL not met {cond_met}", message=cond_met, precond_check=precond_check)
return False return False
state.ilog(e=f"{signalname} ALL PRECOND MET")
return True return True
def execute_signal_generator(name): def execute_signal_generator(name):
state.ilog(e=f"SIGNAL SEARCH for {name}") state.ilog(e=f"SIGNAL SEARCH for {name}", cond_go=state.vars.conditions[KW.go][name], cond_dontgo=state.vars.conditions[KW.dont_go][name], cond_activate=state.vars.conditions[KW.activate][name] )
options = safe_get(state.vars.signals, name, None) options = safe_get(state.vars.signals, name, None)
if options is None: if options is None:
@ -1176,9 +1178,15 @@ def next(data, state: StrategyState):
if plugin: if plugin:
execute_signal_generator_plugin(name) execute_signal_generator_plugin(name)
else: else:
short_enabled = safe_get(options, "short_enabled",safe_get(state.vars, "short_enabled",True))
long_enabled = safe_get(options, "long_enabled",safe_get(state.vars, "long_enabled",True))
#common signals based on 1) configured signals in stratvars #common signals based on 1) configured signals in stratvars
#toto umoznuje jednoduchy prescribed trade bez ceny #toto umoznuje jednoduchy prescribed trade bez ceny
if go_conditions_met(signalname=name, direction=TradeDirection.LONG): if short_enabled is False:
state.ilog(e=f"{name} SHORT DISABLED")
if long_enabled is False:
state.ilog(e=f"{name} LONG DISABLED")
if long_enabled and go_conditions_met(signalname=name, direction=TradeDirection.LONG):
state.vars.prescribedTrades.append(Trade( state.vars.prescribedTrades.append(Trade(
id=uuid4(), id=uuid4(),
last_update=datetime.fromtimestamp(state.time).astimezone(zoneNY), last_update=datetime.fromtimestamp(state.time).astimezone(zoneNY),
@ -1187,7 +1195,7 @@ def next(data, state: StrategyState):
direction=TradeDirection.LONG, direction=TradeDirection.LONG,
entry_price=None, entry_price=None,
stoploss_value = None)) stoploss_value = None))
elif go_conditions_met(signalname=name, direction=TradeDirection.SHORT): elif short_enabled and go_conditions_met(signalname=name, direction=TradeDirection.SHORT):
state.vars.prescribedTrades.append(Trade( state.vars.prescribedTrades.append(Trade(
id=uuid4(), id=uuid4(),
last_update=datetime.fromtimestamp(state.time).astimezone(zoneNY), last_update=datetime.fromtimestamp(state.time).astimezone(zoneNY),
@ -1196,6 +1204,8 @@ def next(data, state: StrategyState):
direction=TradeDirection.SHORT, direction=TradeDirection.SHORT,
entry_price=None, entry_price=None,
stoploss_value = None)) stoploss_value = None))
else:
state.ilog(e=f"{name} NO SIGNAL")
def signal_search(): def signal_search():
# SIGNAL sekce ve stratvars obsahuje signaly: Ty se skladaji z obecnych parametru a podsekce podminek. # SIGNAL sekce ve stratvars obsahuje signaly: Ty se skladaji z obecnych parametru a podsekce podminek.
@ -1244,8 +1254,7 @@ def next(data, state: StrategyState):
#MAIN LOOP #MAIN LOOP
lp = data['close'] lp = data['close']
ispending = "N" if state.vars.pending is None else "Y" state.ilog(e="ENTRY", msg=f"LP:{lp} P:{state.positions}/{round(float(state.avgp),3)} SL:{state.vars.activeTrade.stoploss_value if state.vars.activeTrade is not None else None} profit:{round(float(state.profit),2)} Trades:{len(state.tradeList)} pend:{state.vars.pending}", activeTrade=json.loads(json.dumps(state.vars.activeTrade, default=json_serial)), prescribedTrades=json.loads(json.dumps(state.vars.prescribedTrades, default=json_serial)), pending=str(state.vars.pending), last_price=lp, data=data, stratvars=state.vars)
state.ilog(e="ENTRY", msg=f"LP:{lp} P:{state.positions}/{round(float(state.avgp),3)} SL:{state.vars.activeTrade.stoploss_value if state.vars.activeTrade is not None else None} profit:{round(float(state.profit),2)} Trades:{len(state.tradeList)} pending:{ispending}", activeTrade=json.loads(json.dumps(state.vars.activeTrade, default=json_serial)), prescribedTrades=json.loads(json.dumps(state.vars.prescribedTrades, default=json_serial)), pending=str(state.vars.pending), conditions=state.vars.conditions, last_price=lp, data=data, stratvars=str(state.vars))
inds = get_last_ind_vals() inds = get_last_ind_vals()
state.ilog(e="Indikatory", **inds) state.ilog(e="Indikatory", **inds)
@ -1253,6 +1262,7 @@ def next(data, state: StrategyState):
#pokud mame prazdne pozice a neceka se na nic #pokud mame prazdne pozice a neceka se na nic
if state.positions == 0 and state.vars.pending is None: if state.positions == 0 and state.vars.pending is None:
execute_prescribed_trades() execute_prescribed_trades()
#pokud se neaktivoval nejaky trade, poustime signal search - ale jen jednou za bar? #pokud se neaktivoval nejaky trade, poustime signal search - ale jen jednou za bar?
#if conf_bar == 1: #if conf_bar == 1:
@ -1265,7 +1275,7 @@ def next(data, state: StrategyState):
elif state.vars.activeTrade and state.vars.pending is None: elif state.vars.activeTrade and state.vars.pending is None:
manage_active_trade() #optimalize, close manage_active_trade() #optimalize, close
# - close means change status in prescribed Trends,update profit, delete from activeTrade # - close means change status in prescribed Trends,update profit, delete from activeTrade
def init(state: StrategyState): def init(state: StrategyState):
#place to declare new vars #place to declare new vars

View File

@ -168,6 +168,7 @@ class TradeUpdate(BaseModel):
pos_avg_price: Optional[float] pos_avg_price: Optional[float]
profit: Optional[float] profit: Optional[float]
profit_sum: Optional[float] profit_sum: Optional[float]
signal_name: Optional[str]
class RunArchiveChange(BaseModel): class RunArchiveChange(BaseModel):

View File

@ -57,6 +57,12 @@ function transform_data(data) {
sline_markers["text"] = histRecord.sl_val.toFixed(3) sline_markers["text"] = histRecord.sl_val.toFixed(3)
sl_line_markers_sada.push(sline_markers) sl_line_markers_sada.push(sline_markers)
if (index === array.length - 1) {
//pro posledni zaznam push sadu do pole
sl_line.push(sl_line_sada)
sl_line_markers.push(sl_line_markers_sada)
}
}); });
data.bars.time.forEach((element, index, array) => { data.bars.time.forEach((element, index, array) => {

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, safe_get, get_tick from v2realbot.utils.utils import parse_alpaca_timestamp, ltp, AttributeDict,trunc,price2dec, zoneNY, print, json_serial, safe_get, get_tick, send_to_telegram
from v2realbot.utils.tlog import tlog, tlog_exception from v2realbot.utils.tlog import tlog, tlog_exception
from v2realbot.enums.enums import Mode, Order, Account, RecordType from v2realbot.enums.enums import Mode, Order, Account, RecordType
#from alpaca.trading.models import TradeUpdate #from alpaca.trading.models import TradeUpdate
@ -23,10 +23,28 @@ class StrategyClassicSL(Strategy):
def __init__(self, name: str, symbol: str, next: callable, init: callable, account: Account, mode: Mode = Mode.PAPER, stratvars: AttributeDict = None, open_rush: int = 30, close_rush: int = 30, pe: Event = None, se: Event = None, runner_id: UUID = None, ilog_save: bool = False) -> None: def __init__(self, name: str, symbol: str, next: callable, init: callable, account: Account, mode: Mode = Mode.PAPER, stratvars: AttributeDict = None, open_rush: int = 30, close_rush: int = 30, pe: Event = None, se: Event = None, runner_id: UUID = None, ilog_save: bool = False) -> None:
super().__init__(name, symbol, next, init, account, mode, stratvars, open_rush, close_rush, pe, se, runner_id, ilog_save) super().__init__(name, symbol, next, init, account, mode, stratvars, open_rush, close_rush, pe, se, runner_id, ilog_save)
#todo dodelat profit, podle toho jestli jde o short nebo buy #zkontroluje zda aktualni profit/loss - nedosahnul limit a pokud ano tak vypne strategii
async def check_max_profit_loss(self):
self.state.ilog(e="CHECK MAX PROFIT")
max_sum_profit_to_quit = safe_get(self.state.vars, "max_sum_profit_to_quit", None)
max_sum_loss_to_quit = safe_get(self.state.vars, "max_sum_loss_to_quit", None)
if max_sum_profit_to_quit is not None:
if float(self.state.profit) >= float(max_sum_profit_to_quit):
self.state.ilog(e=f"QUITTING MAX SUM PROFIT REACHED {max_sum_profit_to_quit=} {self.state.profit=}")
self.state.vars.pending = "max_sum_profit_to_quit"
send_to_telegram(f"QUITTING MAX SUM PROFIT REACHED {max_sum_profit_to_quit=} {self.state.profit=}")
self.se.set()
if max_sum_loss_to_quit is not None:
if float(self.state.profit) < 0 and float(self.state.profit) <= float(max_sum_loss_to_quit):
self.state.ilog(e=f"QUITTING MAX SUM LOSS REACHED {max_sum_loss_to_quit=} {self.state.profit=}")
self.state.vars.pending = "max_sum_loss_to_quit"
send_to_telegram(f"QUITTING MAX SUM LOSS REACHED {max_sum_loss_to_quit=} {self.state.profit=}")
self.se.set()
async def orderUpdateBuy(self, data: TradeUpdate): async def orderUpdateBuy(self, data: TradeUpdate):
o: Order = data.order o: Order = data.order
signal_name = None
##nejak to vymyslet, aby se dal poslat cely Trade a serializoval se ##nejak to vymyslet, aby se dal poslat cely Trade a serializoval se
self.state.ilog(e="Příchozí BUY notif", msg=o.status, trade=json.loads(json.dumps(data, default=json_serial))) self.state.ilog(e="Příchozí BUY notif", msg=o.status, trade=json.loads(json.dumps(data, default=json_serial)))
@ -54,6 +72,7 @@ class StrategyClassicSL(Strategy):
trade.last_update = datetime.fromtimestamp(self.state.time).astimezone(zoneNY) trade.last_update = datetime.fromtimestamp(self.state.time).astimezone(zoneNY)
trade.profit += trade_profit trade.profit += trade_profit
trade.profit_sum = self.state.profit trade.profit_sum = self.state.profit
signal_name = trade.generated_by
#zapsat update profitu do tradeList #zapsat update profitu do tradeList
for tradeData in self.state.tradeList: for tradeData in self.state.tradeList:
@ -61,9 +80,23 @@ class StrategyClassicSL(Strategy):
#pridat jako attribut, aby proslo i na LIVE a PAPPER, kde se bere TradeUpdate z Alpaca #pridat jako attribut, aby proslo i na LIVE a PAPPER, kde se bere TradeUpdate z Alpaca
setattr(tradeData, "profit", trade_profit) setattr(tradeData, "profit", trade_profit)
setattr(tradeData, "profit_sum", self.state.profit) setattr(tradeData, "profit_sum", self.state.profit)
setattr(tradeData, "signal_name", signal_name)
#self.state.ilog(f"updatnut tradeList o profit", tradeData=json.loads(json.dumps(tradeData, default=json_serial))) #self.state.ilog(f"updatnut tradeList o profit", tradeData=json.loads(json.dumps(tradeData, default=json_serial)))
#test na maximalni profit/loss
await self.check_max_profit_loss()
else: else:
#zjistime nazev signalu a updatneme do tradeListu - abychom meli svazano
for trade in self.state.vars.prescribedTrades:
if trade.id == self.state.vars.pending:
signal_name = trade.generated_by
#zapsat update profitu do tradeList
for tradeData in self.state.tradeList:
if tradeData.execution_id == data.execution_id:
setattr(tradeData, "signal_name", signal_name)
self.state.ilog(e="BUY: Jde o LONG nakuú nepocitame profit zatim") self.state.ilog(e="BUY: Jde o LONG nakuú nepocitame profit zatim")
#ic("vstupujeme do orderupdatebuy") #ic("vstupujeme do orderupdatebuy")
@ -102,6 +135,7 @@ class StrategyClassicSL(Strategy):
trade.last_update = datetime.fromtimestamp(self.state.time).astimezone(zoneNY) trade.last_update = datetime.fromtimestamp(self.state.time).astimezone(zoneNY)
trade.profit += trade_profit trade.profit += trade_profit
trade.profit_sum = self.state.profit trade.profit_sum = self.state.profit
signal_name = trade.generated_by
#zapsat update profitu do tradeList #zapsat update profitu do tradeList
for tradeData in self.state.tradeList: for tradeData in self.state.tradeList:
@ -109,9 +143,22 @@ class StrategyClassicSL(Strategy):
#pridat jako attribut, aby proslo i na LIVE a PAPPER, kde se bere TradeUpdate z Alpaca #pridat jako attribut, aby proslo i na LIVE a PAPPER, kde se bere TradeUpdate z Alpaca
setattr(tradeData, "profit", trade_profit) setattr(tradeData, "profit", trade_profit)
setattr(tradeData, "profit_sum", self.state.profit) setattr(tradeData, "profit_sum", self.state.profit)
self.state.ilog(f"updatnut tradeList o profi {str(tradeData)}") setattr(tradeData, "signal_name", signal_name)
#self.state.ilog(f"updatnut tradeList o profi {str(tradeData)}")
await self.check_max_profit_loss()
else: else:
#zjistime nazev signalu a updatneme do tradeListu - abychom meli svazano
for trade in self.state.vars.prescribedTrades:
if trade.id == self.state.vars.pending:
signal_name = trade.generated_by
#zapsat update profitu do tradeList
for tradeData in self.state.tradeList:
if tradeData.execution_id == data.execution_id:
setattr(tradeData, "signal_name", signal_name)
self.state.ilog(e="SELL: Jde o SHORT nepocitame profit zatim") self.state.ilog(e="SELL: Jde o SHORT nepocitame profit zatim")
#update pozic, v trade update je i pocet zbylych pozic #update pozic, v trade update je i pocet zbylych pozic