treti commit

This commit is contained in:
David Brazda
2024-08-25 18:06:47 +02:00
parent 30044dc4ea
commit a10d5b8a64
9 changed files with 91 additions and 33 deletions

View File

@ -414,6 +414,8 @@ class SLHistory(BaseModel):
id: Optional[UUID] = None
time: datetime
sl_val: float
direction: TradeDirection
account: Account
#Contains archive of running strategies (runner) - detail data
class RunArchiveDetail(BaseModel):

View File

@ -11,6 +11,44 @@ var markersLine = null
var avgBuyLine = null
var profitLine = null
var slLine = []
//create function which for each ACCOUNT1, ACCOUNT2 or ACCOUNT3 returns color for buy and color for sell - which can be strings representing color
//HELPERS FUNCTION - will go to utils
/**
* Returns an object containing the colors for buy and sell for the specified account.
*
* Parameters:
* account (string): The account for which to retrieve the colors (ACCOUNT1, ACCOUNT2, or ACCOUNT3).
*
* Returns:
* object: An object with 'buy' and 'sell' properties containing the corresponding color strings.
*
* Account 1:
#FF6B6B, #FF9999
Account 2:
#4ECDC4, #83E8E1
Account 3:
#FFD93D, #FFE787
Account 4:
#6C5CE7, #A29BFE
Another option for colors:
#1F77B4 (Entry) and #AEC7E8 (Exit)
#FF7F0E (Entry) and #FFBB78 (Exit)
#2CA02C (Entry) and #98DF8A (Exit)
#D62728 (Entry) and #FF9896 (Exit)
*/
function getAccountColors(account) {
const accountColors = {
ACCOUNT1: { accid: 'A1', buy: '#FF7F0E', sell: '#FFBB78' },
ACCOUNT2: { accid: 'A2',buy: '#1F77B4', sell: '#AEC7E8' },
ACCOUNT3: { accid: 'A3',buy: '#2CA02C', sell: '#98DF8A' },
ACCOUNT4: { accid: 'A4',buy: '#D62728', sell: '#FF9896' },
ACCOUNT5: { accid: 'A5',buy: 'purple', sell: 'orange' }
};
return accountColors[account] || { buy: '#37cade', sell: 'red' };
}
//TRANSFORM object returned from REST API get_arch_run_detail
//to series and markers required by lightweigth chart
//input array object bars = { high: [1,2,3], time: [1,2,3], close: [2,2,2]...}
@ -34,6 +72,11 @@ function transform_data(data) {
//cas of first record, nekdy jsou stejny - musim pridat setinku
prev_cas = 0
if ((data.ext_data !== null) && (data.ext_data.sl_history)) {
///sort sl_history according to order id string - i need all same order id together
data.ext_data.sl_history.sort(function (a, b) {
return a.id.localeCompare(b.id);
});
data.ext_data.sl_history.forEach((histRecord, index, array) => {
//console.log("plnime")
@ -48,6 +91,7 @@ function transform_data(data) {
//init nova sada
sl_line_sada = []
sl_line_markers_sada = []
sline_color = "#f5aa42"
}
prev_id = histRecord.id
@ -65,12 +109,21 @@ function transform_data(data) {
sline = {}
sline["time"] = cas
sline["value"] = histRecord.sl_val
if (histRecord.account) {
const accColors = getAccountColors(histRecord.account)
sline_color = histRecord.direction == "long" ? accColors.buy : accColors.sell //idealne
sline["color"] = sline_color
}
sl_line_sada.push(sline)
//ZDE JSEM SKONCIL
//COLOR SE NASTAVUJE V SERIES OPTIONS POZDEJI - nejak vymyslet
sline_markers = {}
sline_markers["time"] = cas
sline_markers["position"] = "inBar"
sline_markers["color"] = "#f5aa42"
sline_markers["color"] = sline_color
//sline_markers["shape"] = "circle"
//console.log("SHOW_SL_DIGITS",SHOW_SL_DIGITS)
sline_markers["text"] = SHOW_SL_DIGITS ? histRecord.sl_val.toFixed(3) : ""
@ -239,31 +292,33 @@ function transform_data(data) {
// //a_markers["text"] = CHART_SHOW_TEXT ? trade.position_qty + "/" + parseFloat(trade.pos_avg_price).toFixed(3) :trade.position_qty
// avgp_markers.push(a_markers)
}
}
}
const { accid: accountId,buy: buyColor, sell: sellColor } = getAccountColors(trade.account);
//buy sell markery
marker = {}
marker["time"] = timestamp;
// marker["position"] = (trade.order.side == "buy") ? "belowBar" : "aboveBar"
marker["position"] = (trade.order.side == "buy") ? "aboveBar" : "aboveBar"
marker["color"] = (trade.order.side == "buy") ? "#37cade" : "red"
marker["color"] = (trade.order.side == "buy") ? buyColor : sellColor
//marker["shape"] = (trade.order.side == "buy") ? "arrowUp" : "arrowDown"
marker["shape"] = (trade.order.side == "buy") ? "arrowUp" : "arrowDown"
//marker["text"] = trade.qty + "/" + trade.price
qt_optimized = (trade.order.qty % 1000 === 0) ? (trade.order.qty / 1000).toFixed(1) + 'K' : trade.order.qty
marker["text"] = accountId + " " //account shortcut
if (CHART_SHOW_TEXT) {
//včetně qty
//marker["text"] = qt_optimized + "@" + trade.price
//bez qty
marker["text"] = trade.price
marker["text"] += trade.price
closed_trade_marker_and_profit = (trade.profit) ? "c" + trade.profit.toFixed(1) + "/" + trade.profit_sum.toFixed(1) : "c"
marker["text"] += (trade.position_qty == 0) ? closed_trade_marker_and_profit : ""
} else {
closed_trade_marker_and_profit = (trade.profit) ? "c" + trade.profit.toFixed(1) + "/" + trade.profit_sum.toFixed(1) : "c"
marker["text"] = (trade.position_qty == 0) ? closed_trade_marker_and_profit : trade.price.toFixed(3)
marker["text"] += (trade.position_qty == 0) ? closed_trade_marker_and_profit : trade.price.toFixed(3)
}
markers.push(marker)
@ -844,7 +899,7 @@ function display_buy_markers(data) {
//console.log("uvnitr")
slLine_temp = chart.addLineSeries({
// title: "avgpbuyline",
color: '#e4c76d',
color: slRecord[0]["color"] ? slRecord[0]["color"] : '#e4c76d',
// color: 'transparent',
lineWidth: 1,
lastValueVisible: false

View File

@ -344,7 +344,7 @@ class StrategyClassicSL(Strategy):
self.state.vars["transferables"]["martingale"]["cont_loss_series_cnt"] = 0 if rel_profit > 0 else self.state.vars["transferables"]["martingale"]["cont_loss_series_cnt"]+1
self.state.ilog(lvl=1, e=f"update cont_loss_series_cnt na {self.state.vars['transferables']['martingale']['cont_loss_series_cnt']}")
self.state.ilog(e=f"SELL notif {account}- LONG PROFIT {partial_exit=} {partial_last=}:{round(float(trade_profit),3)} celkem:{round(float(self.state.profit),3)} rel:{float(rel_profit)} rel_cum:{round(rel_profit_cum_calculated,7)}", msg=str(data.event), rel_profit_cum = str(self.state.rel_profit_cum), sold_amount=sold_amount, avg_costs=avg_costs, trade_qty=data.qty, trade_price=data.price, orderid=str(data.order.id))
self.state.ilog(e=f"SELL notif {account.name}- LONG PROFIT {partial_exit=} {partial_last=}:{round(float(trade_profit),3)} celkem:{round(float(self.state.profit),3)} rel:{float(rel_profit)} rel_cum:{round(rel_profit_cum_calculated,7)}", msg=str(data.event), rel_profit_cum = str(self.state.rel_profit_cum), sold_amount=sold_amount, avg_costs=avg_costs, trade_qty=data.qty, trade_price=data.price, orderid=str(data.order.id))
#zapsat profit do prescr.trades
for trade in self.state.vars.prescribedTrades:
@ -431,7 +431,7 @@ class StrategyClassicSL(Strategy):
if data.event == TradeEvent.FILL or data.event == TradeEvent.CANCELED:
print("Příchozí SELL notifikace - complete FILL nebo CANCEL", data.event)
self.state.account_variables[account.name].pending = None
a,p = self.interface[account.name].pos()
a,p = self.interface[account.name].pos() #TBD maybe optimize for speed
#pri chybe api nechavame puvodni hodnoty
if a != -1:
self.state.account_variables[account.name].avgp, self.state.account_variables[account.name].positions = a,p

View File

@ -26,20 +26,20 @@ def close_position(state: StrategyState, activeTrade: Trade, data, direction: Tr
positions = state.account_variables[activeTrade.account.name].positions
state.ilog(lvl=1,e=f"CLOSING TRADE {followup_text} {reason} {str(direction)}", curr_price=data["close"], trade=activeTrade)
if direction == TradeDirection.SHORT:
res = state.buy(size=abs(int(positions)))
res = state.buy(account=activeTrade.account, size=abs(int(positions)))
if isinstance(res, int) and res < 0:
raise Exception(f"error in required operation {reason} {res}")
elif direction == TradeDirection.LONG:
res = state.sell(size=positions)
res = state.sell(account=activeTrade.account, size=positions)
if isinstance(res, int) and res < 0:
raise Exception(f"error in required operation STOPLOSS SELL {res}")
raise Exception(f"error in required operation STOPLOSS SELL {res}") #TBD error handling
else:
raise Exception(f"unknow TradeDirection in close_position")
#pri uzavreni tradu zapisujeme SL history - lepsi zorbazeni v grafu
insert_SL_history(state)
insert_SL_history(state, activeTrade)
state.account_variables[activeTrade.account.name].pending = activeTrade.id
state.account_variables[activeTrade.account.name].activeTrade = None
#state.account_variables[activeTrade.account.name].last_exit_index = data["index"]
@ -56,19 +56,19 @@ def close_position_partial(state, activeTrade: Trade,data, direction: TradeDirec
size_abs = abs(int(int(positions)*size))
state.ilog(lvl=1,e=f"CLOSING TRADE PART: {size_abs} {size} {reason} {str(direction)}", curr_price=data["close"], trade=activeTrade)
if direction == TradeDirection.SHORT:
res = state.buy(size=size_abs)
res = state.buy(account=activeTrade.account, size=size_abs)
if isinstance(res, int) and res < 0:
raise Exception(f"error in required operation STOPLOSS PARTIAL BUY {reason} {res}")
elif direction == TradeDirection.LONG:
res = state.sell(size=size_abs)
res = state.sell(account=activeTrade.account, size=size_abs)
if isinstance(res, int) and res < 0:
raise Exception(f"error in required operation STOPLOSS PARTIAL SELL {res}")
else:
raise Exception(f"unknow TradeDirection in close_position")
#pri uzavreni tradu zapisujeme SL history - lepsi zorbazeni v grafu
insert_SL_history(state)
insert_SL_history(state, activeTrade)
state.account_variables[activeTrade.account.name].pending = activeTrade.id
state.account_variables[activeTrade.account.name].activeTrade = None
state.account_variables[activeTrade.account.name].dont_exit_already_activated = False

View File

@ -40,9 +40,9 @@ def eval_close_position(state: StrategyState, accountsWithActiveTrade, data):
if activeTrade.goal_price is not None:
goal_price = activeTrade.goal_price
else:
goal_price = get_profit_target_price(state, data, TradeDirection.SHORT, activeTrade)
goal_price = get_profit_target_price(state, data, activeTrade, TradeDirection.SHORT)
max_price = get_max_profit_price(state, data, TradeDirection.SHORT, activeTrade)
max_price = get_max_profit_price(state, activeTrade, data, TradeDirection.SHORT)
state.ilog(lvl=1,e=f"Def Goal price {str(TradeDirection.SHORT)} {goal_price} max price {max_price}")
#SL OPTIMALIZATION - PARTIAL EXIT
@ -63,7 +63,7 @@ def eval_close_position(state: StrategyState, accountsWithActiveTrade, data):
if reverse_for_SL_exit == "always":
followup_action = Followup.REVERSE
elif reverse_for_SL_exit == "cond":
followup_action = Followup.REVERSE if keyword_conditions_met(state, data=data, activeTrade=activeTrade.generated_by, direction=TradeDirection.SHORT, keyword=KW.slreverseonly, skip_conf_validation=True) else None
followup_action = Followup.REVERSE if keyword_conditions_met(state, data=data, activeTrade=activeTrade, direction=TradeDirection.SHORT, keyword=KW.slreverseonly, skip_conf_validation=True) else None
else:
followup_action = None
close_position(state=state, activeTrade=activeTrade, data=data, direction=TradeDirection.SHORT, reason="SL REACHED", followup=followup_action)
@ -71,28 +71,28 @@ def eval_close_position(state: StrategyState, accountsWithActiveTrade, data):
#REVERSE BASED ON REVERSE CONDITIONS
if keyword_conditions_met(state, data, activeTrade=activeTrade.generated_by, direction=TradeDirection.SHORT, keyword=KW.reverse):
if keyword_conditions_met(state, data, activeTrade=activeTrade, direction=TradeDirection.SHORT, keyword=KW.reverse):
close_position(state=state, activeTrade=activeTrade,data=data, direction=TradeDirection.SHORT, reason="REVERSE COND MET", followup=Followup.REVERSE)
return
#EXIT ADD CONDITIONS MET (exit and add)
if keyword_conditions_met(state, data, activeTrade=activeTrade.generated_by, direction=TradeDirection.SHORT, keyword=KW.exitadd):
if keyword_conditions_met(state, data, activeTrade=activeTrade, direction=TradeDirection.SHORT, keyword=KW.exitadd):
close_position(state=state, activeTrade=activeTrade, data=data, direction=TradeDirection.SHORT, reason="EXITADD COND MET", followup=Followup.ADD)
return
#CLOSING BASED ON EXIT CONDITIONS
if exit_conditions_met(state, data, TradeDirection.SHORT):
if exit_conditions_met(state, activeTrade, data, TradeDirection.SHORT):
directive_name = 'reverse_for_cond_exit_short'
reverse_for_cond_exit_short = get_signal_section_directive(state=state, signal_name=activeTrade.signal_name, directive_name=directive_name, default_value=safe_get(state.vars, directive_name, False))
reverse_for_cond_exit_short = get_signal_section_directive(state=state, signal_name=activeTrade.generated_by, directive_name=directive_name, default_value=safe_get(state.vars, directive_name, False))
directive_name = 'add_for_cond_exit_short'
add_for_cond_exit_short = get_signal_section_directive(state=state, signal_name=activeTrade.signal_name, directive_name=directive_name, default_value=safe_get(state.vars, directive_name, False))
add_for_cond_exit_short = get_signal_section_directive(state=state, signal_name=activeTrade.generated_by, directive_name=directive_name, default_value=safe_get(state.vars, directive_name, False))
if reverse_for_cond_exit_short:
followup_action = Followup.REVERSE
elif add_for_cond_exit_short:
followup_action = Followup.ADD
else:
followup_action = None
close_position(state=state, data=data, direction=TradeDirection.SHORT, reason="EXIT COND MET", followup=followup_action)
close_position(state=state, activeTrae=activeTrade, data=data, direction=TradeDirection.SHORT, reason="EXIT COND MET", followup=followup_action)
return
#PROFIT
@ -102,7 +102,7 @@ def eval_close_position(state: StrategyState, accountsWithActiveTrade, data):
#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 dontexit_protection_met(state=state, data=data,direction=TradeDirection.SHORT) is False:
if max_price_signal or dontexit_protection_met(state=state, activeTrade=activeTrade, data=data,direction=TradeDirection.SHORT) is False:
close_position(state=state, activeTrade=activeTrade, data=data, direction=TradeDirection.SHORT, reason=f"PROFIT or MAXPROFIT REACHED {max_price_signal=}")
return
#pokud je cena horsi, ale byla uz dont exit aktivovany - pak prodavame také
@ -137,7 +137,7 @@ def eval_close_position(state: StrategyState, accountsWithActiveTrade, data):
position = positions * exit_adjustment
state.ilog(lvl=1,e=f"SL OPTIMIZATION ENGAGED {str(TradeDirection.LONG)} {position=} {level_met=} {exit_adjustment}", initial_levels=str(state.sl_optimizer_long.get_initial_abs_levels(state, activeTrade)), rem_levels=str(state.sl_optimizer_long.get_remaining_abs_levels(state, activeTrade)), exit_levels=str(state.sl_optimizer_long.exit_levels), exit_sizes=str(state.sl_optimizer_long.exit_sizes))
printanyway(f"SL OPTIMIZATION ENGAGED {str(TradeDirection.LONG)} {position=} {level_met=} {exit_adjustment}")
close_position_partial(state=state, data=data, direction=TradeDirection.LONG, reason=f"SL OPT LEVEL {level_met} REACHED", size=exit_adjustment)
close_position_partial(state=state, activeTrade=activeTrade, data=data, direction=TradeDirection.LONG, reason=f"SL OPT LEVEL {level_met} REACHED", size=exit_adjustment)
return
#SL FULL execution
@ -190,7 +190,7 @@ def eval_close_position(state: StrategyState, accountsWithActiveTrade, data):
#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 dontexit_protection_met(state, data, direction=TradeDirection.LONG) is False:
if max_price_signal or dontexit_protection_met(state, activeTrade=activeTrade, data=data, direction=TradeDirection.LONG) is False:
close_position(state=state, activeTrade=activeTrade, data=data, direction=TradeDirection.LONG, reason=f"PROFIT or MAXPROFIT REACHED {max_price_signal=}")
return
#pokud je cena horsi, ale byl uz dont exit aktivovany - pak prodavame také

View File

@ -111,7 +111,7 @@ def keyword_conditions_met(state, data, activeTrade: Trade, direction: TradeDire
#mozna do SL helpers tuto
def insert_SL_history(state, activeTrade: Trade):
#insert stoploss history as key sl_history into runner archive extended data
state.extData["sl_history"].append(SLHistory(id=activeTrade.id, time=state.time, sl_val=activeTrade.stoploss_value))
state.extData["sl_history"].append(SLHistory(id=activeTrade.id, time=state.time, sl_val=activeTrade.stoploss_value, direction=activeTrade.direction, account=activeTrade.account))
def get_default_sl_value(state, signal_name, direction: TradeDirection):

View File

@ -87,12 +87,12 @@ def trail_SL_management(state: StrategyState, accountsWithActiveTrade, data):
state.ilog(lvl=1,e=f"SL TRAIL EVAL {smer} SL:{round(activeTrade.stoploss_value,3)} TRAILGOAL:{move_SL_threshold}", def_SL=def_SL, offset=offset, offset_normalized=offset_normalized, step_normalized=step_normalized, def_SL_normalized=def_SL_normalized)
if (move_SL_threshold) < data['close']:
activeTrade.stoploss_value += step_normalized
insert_SL_history(state)
insert_SL_history(state, activeTrade)
state.ilog(lvl=1,e=f"SL TRAIL TH {smer} reached {move_SL_threshold} SL moved to {activeTrade.stoploss_value}", offset_normalized=offset_normalized, step_normalized=step_normalized, def_SL_normalized=def_SL_normalized)
elif direction == TradeDirection.SHORT:
move_SL_threshold = activeTrade.stoploss_value - offset_normalized - def_SL_normalized
state.ilog(lvl=0,e=f"SL TRAIL EVAL {smer} SL:{round(activeTrade.stoploss_value,3)} TRAILGOAL:{move_SL_threshold}", def_SL=def_SL, offset=offset, offset_normalized=offset_normalized, step_normalized=step_normalized, def_SL_normalized=def_SL_normalized)
if (move_SL_threshold) > data['close']:
activeTrade.stoploss_value -= step_normalized
insert_SL_history(state)
insert_SL_history(state, activeTrade)
state.ilog(lvl=1,e=f"SL TRAIL GOAL {smer} reached {move_SL_threshold} SL moved to {activeTrade.stoploss_value}", offset_normalized=offset_normalized, step_normalized=step_normalized, def_SL_normalized=def_SL_normalized)

View File

@ -19,7 +19,8 @@ def execute_prescribed_trades(state: StrategyState, data):
accountsWithNoActiveTrade = gaka(state.account_variables, "activeTrade", None, lambda x: x is None)
if len(accountsWithNoActiveTrade.values()) == 0:
print("active trades on all accounts")
#print("active trades on all accounts")
return
#returns true if all values are not None
#all(v is not None for v in d.keys())

View File

@ -34,7 +34,7 @@ def signal_search(state: StrategyState, data):
accountsWithNoActiveTrade = gaka(state.account_variables, "activeTrade", None, lambda x: x is None)
if len(accountsWithNoActiveTrade.values()) == 0:
print("active trades on all accounts")
#print("active trades on all accounts")
return
for signalname, signalsettings in state.vars.signals.items():