504 righe
19 KiB
MQL5
504 righe
19 KiB
MQL5
#ifndef SYMBOL_POLICY_MQH
|
|
#define SYMBOL_POLICY_MQH
|
|
|
|
string GWJsonEscape(const string s);
|
|
|
|
double ClampDouble(const double value, const double min_value, const double max_value)
|
|
{
|
|
return MathMax(min_value, MathMin(max_value, value));
|
|
}
|
|
|
|
string UpperCopy(const string s)
|
|
{
|
|
string x = s;
|
|
StringToUpper(x);
|
|
return x;
|
|
}
|
|
|
|
bool SymbolNameHas(const string symbol, const string token)
|
|
{
|
|
return (StringFind(UpperCopy(symbol), UpperCopy(token)) >= 0);
|
|
}
|
|
|
|
string BoolJson(const bool value)
|
|
{
|
|
return value ? "true" : "false";
|
|
}
|
|
|
|
void ResetSymbolPolicy(SymbolPolicy &policy)
|
|
{
|
|
policy.symbol_name = _Symbol;
|
|
policy.symbol_class = "MANUAL";
|
|
policy.base_risk_percent = 0.50;
|
|
policy.max_spread_points = 60.0;
|
|
policy.min_stop_points = 80;
|
|
policy.preferred_sessions = "London,NY";
|
|
policy.news_sensitivity = 0.50;
|
|
policy.lot_floor = 0.01;
|
|
policy.lot_ceiling = 1.00;
|
|
policy.max_concurrent_exposure = 4;
|
|
policy.continuation_differs = true;
|
|
policy.continuation_risk_mult = 1.05;
|
|
policy.counter_risk_mult = 0.80;
|
|
policy.require_session_alignment = false;
|
|
policy.min_free_margin_pct = Min_Free_Margin_Pct;
|
|
policy.max_account_risk_pct = Max_Account_Risk_Pct;
|
|
policy.max_margin_pct = Max_Trade_Margin_Pct;
|
|
policy.notes = "fallback profile";
|
|
}
|
|
|
|
void ApplyPolicyForSymbolClass(const string symbol, SymbolPolicy &policy)
|
|
{
|
|
ResetSymbolPolicy(policy);
|
|
policy.symbol_name = symbol;
|
|
|
|
if(SymbolNameHas(symbol, "XAU"))
|
|
{
|
|
policy.symbol_class = "XAUUSD";
|
|
policy.base_risk_percent = 0.35;
|
|
policy.max_spread_points = 350.0;
|
|
policy.min_stop_points = 450;
|
|
policy.preferred_sessions = "London,NY";
|
|
policy.news_sensitivity = 0.95;
|
|
policy.lot_ceiling = 2.0;
|
|
policy.max_concurrent_exposure = 2;
|
|
policy.continuation_risk_mult = 1.10;
|
|
policy.counter_risk_mult = 0.70;
|
|
policy.require_session_alignment = true;
|
|
policy.min_free_margin_pct = 35.0;
|
|
policy.max_account_risk_pct = 1.0;
|
|
policy.max_margin_pct = 12.0;
|
|
policy.notes = "gold: macro sensitive";
|
|
}
|
|
else if(SymbolNameHas(symbol, "US30") || SymbolNameHas(symbol, "DJI"))
|
|
{
|
|
policy.symbol_class = "US30";
|
|
policy.base_risk_percent = 0.25;
|
|
policy.max_spread_points = 120.0;
|
|
policy.min_stop_points = 120;
|
|
policy.preferred_sessions = "NY";
|
|
policy.news_sensitivity = 0.90;
|
|
policy.lot_ceiling = 1.0;
|
|
policy.max_concurrent_exposure = 2;
|
|
policy.continuation_risk_mult = 1.10;
|
|
policy.counter_risk_mult = 0.75;
|
|
policy.require_session_alignment = true;
|
|
policy.min_free_margin_pct = 40.0;
|
|
policy.max_account_risk_pct = 0.90;
|
|
policy.max_margin_pct = 10.0;
|
|
policy.notes = "index: session sensitive";
|
|
}
|
|
else if(SymbolNameHas(symbol, "NAS100") || SymbolNameHas(symbol, "USTEC"))
|
|
{
|
|
policy.symbol_class = "NAS100";
|
|
policy.base_risk_percent = 0.25;
|
|
policy.max_spread_points = 150.0;
|
|
policy.min_stop_points = 150;
|
|
policy.preferred_sessions = "NY";
|
|
policy.news_sensitivity = 0.95;
|
|
policy.lot_ceiling = 1.0;
|
|
policy.max_concurrent_exposure = 2;
|
|
policy.continuation_risk_mult = 1.10;
|
|
policy.counter_risk_mult = 0.70;
|
|
policy.require_session_alignment = true;
|
|
policy.min_free_margin_pct = 40.0;
|
|
policy.max_account_risk_pct = 0.90;
|
|
policy.max_margin_pct = 10.0;
|
|
policy.notes = "index: macro and vol sensitive";
|
|
}
|
|
else if(SymbolNameHas(symbol, "USOIL") || SymbolNameHas(symbol, "WTI"))
|
|
{
|
|
policy.symbol_class = "USOIL";
|
|
policy.base_risk_percent = 0.40;
|
|
policy.max_spread_points = 80.0;
|
|
policy.min_stop_points = 100;
|
|
policy.preferred_sessions = "London,NY";
|
|
policy.news_sensitivity = 0.80;
|
|
policy.lot_ceiling = 1.5;
|
|
policy.max_concurrent_exposure = 3;
|
|
policy.continuation_risk_mult = 1.05;
|
|
policy.counter_risk_mult = 0.80;
|
|
policy.require_session_alignment = false;
|
|
policy.min_free_margin_pct = 30.0;
|
|
policy.max_account_risk_pct = 1.25;
|
|
policy.max_margin_pct = 15.0;
|
|
policy.notes = "oil: event sensitive";
|
|
}
|
|
else if(SymbolNameHas(symbol, "BTC") || SymbolNameHas(symbol, "ETH"))
|
|
{
|
|
policy.symbol_class = "CRYPTO";
|
|
policy.base_risk_percent = 0.30;
|
|
policy.max_spread_points = 2000.0;
|
|
policy.min_stop_points = 1500;
|
|
policy.preferred_sessions = "Interbank,NY";
|
|
policy.news_sensitivity = 0.70;
|
|
policy.lot_ceiling = 0.25;
|
|
policy.max_concurrent_exposure = 1;
|
|
policy.continuation_risk_mult = 1.05;
|
|
policy.counter_risk_mult = 0.75;
|
|
policy.require_session_alignment = false;
|
|
policy.min_free_margin_pct = 45.0;
|
|
policy.max_account_risk_pct = 0.75;
|
|
policy.max_margin_pct = 8.0;
|
|
policy.notes = "crypto: high volatility";
|
|
}
|
|
else if(SymbolNameHas(symbol, "JPY"))
|
|
{
|
|
policy.symbol_class = "JPY";
|
|
policy.base_risk_percent = 0.45;
|
|
policy.max_spread_points = 35.0;
|
|
policy.min_stop_points = 60;
|
|
policy.preferred_sessions = "Tokyo,London";
|
|
policy.news_sensitivity = 0.65;
|
|
policy.lot_ceiling = 2.0;
|
|
policy.max_concurrent_exposure = 4;
|
|
policy.continuation_risk_mult = 1.05;
|
|
policy.counter_risk_mult = 0.80;
|
|
policy.require_session_alignment = false;
|
|
policy.min_free_margin_pct = Min_Free_Margin_Pct;
|
|
policy.max_account_risk_pct = Max_Account_Risk_Pct;
|
|
policy.max_margin_pct = Max_Trade_Margin_Pct;
|
|
policy.notes = "yen-cross family";
|
|
}
|
|
else if(SymbolNameHas(symbol, "CAD"))
|
|
{
|
|
policy.symbol_class = "COMMODITY_FX";
|
|
policy.base_risk_percent = 0.50;
|
|
policy.max_spread_points = 30.0;
|
|
policy.min_stop_points = 40;
|
|
policy.preferred_sessions = "London,NY";
|
|
policy.news_sensitivity = 0.60;
|
|
policy.lot_ceiling = 2.0;
|
|
policy.max_concurrent_exposure = 4;
|
|
policy.continuation_risk_mult = 1.00;
|
|
policy.counter_risk_mult = 0.85;
|
|
policy.require_session_alignment = false;
|
|
policy.min_free_margin_pct = Min_Free_Margin_Pct;
|
|
policy.max_account_risk_pct = Max_Account_Risk_Pct;
|
|
policy.max_margin_pct = Max_Trade_Margin_Pct;
|
|
policy.notes = "commodity fx";
|
|
}
|
|
else
|
|
{
|
|
policy.symbol_class = "MAJOR_FX";
|
|
policy.base_risk_percent = 0.45;
|
|
policy.max_spread_points = 25.0;
|
|
policy.min_stop_points = 50;
|
|
policy.preferred_sessions = "London,NY";
|
|
policy.news_sensitivity = 0.55;
|
|
policy.lot_ceiling = 3.0;
|
|
policy.max_concurrent_exposure = 4;
|
|
policy.continuation_risk_mult = 1.00;
|
|
policy.counter_risk_mult = 0.85;
|
|
policy.require_session_alignment = false;
|
|
policy.min_free_margin_pct = Min_Free_Margin_Pct;
|
|
policy.max_account_risk_pct = Max_Account_Risk_Pct;
|
|
policy.max_margin_pct = Max_Trade_Margin_Pct;
|
|
policy.notes = "major fx fallback";
|
|
}
|
|
}
|
|
|
|
void ResolveSymbolPolicy()
|
|
{
|
|
if(!Use_Auto_Symbol_Config)
|
|
{
|
|
ResetSymbolPolicy(g_symbol_policy);
|
|
g_symbol_policy.symbol_name = _Symbol;
|
|
g_symbol_policy.symbol_class = "MANUAL";
|
|
g_symbol_policy.min_stop_points = Manual_SL_Points;
|
|
g_symbol_policy.lot_ceiling = BaseLotSize * 10.0;
|
|
g_symbol_policy.base_risk_percent = 0.50;
|
|
g_symbol_policy.notes = "manual fallback";
|
|
g_symbol_policy_ready = true;
|
|
Symbol_Profile_Name = "MANUAL";
|
|
Symbol_SL_Points = Manual_SL_Points;
|
|
Symbol_TP_Points = Manual_TP_Points;
|
|
return;
|
|
}
|
|
|
|
ApplyPolicyForSymbolClass(_Symbol, g_symbol_policy);
|
|
ApplySymbolPolicyFeedback(g_symbol_policy);
|
|
g_symbol_policy_ready = true;
|
|
Symbol_Profile_Name = g_symbol_policy.symbol_class;
|
|
Symbol_SL_Points = g_symbol_policy.min_stop_points;
|
|
Symbol_TP_Points = (int)MathMax((double)Symbol_SL_Points * 4.0, (double)Symbol_SL_Points * 2.5);
|
|
if(Symbol_Profile_Name == "XAUUSD")
|
|
Symbol_TP_Points = 3500;
|
|
else if(Symbol_Profile_Name == "US30")
|
|
Symbol_TP_Points = 1000;
|
|
else if(Symbol_Profile_Name == "NAS100")
|
|
Symbol_TP_Points = 1400;
|
|
}
|
|
|
|
bool SessionInPreferenceList(const string session, const string preferred_sessions)
|
|
{
|
|
if(StringLen(preferred_sessions) == 0)
|
|
return true;
|
|
|
|
string sess = UpperCopy(session);
|
|
string prefs = UpperCopy(preferred_sessions);
|
|
return (StringFind(prefs, sess) >= 0);
|
|
}
|
|
|
|
int GetSymbolFeedbackIndex(const string symbol_class)
|
|
{
|
|
string cls = UpperCopy(symbol_class);
|
|
if(cls == "XAUUSD") return 0;
|
|
if(cls == "US30") return 1;
|
|
if(cls == "NAS100") return 2;
|
|
if(cls == "USOIL") return 3;
|
|
if(cls == "CRYPTO") return 4;
|
|
if(cls == "JPY") return 5;
|
|
if(cls == "COMMODITY_FX") return 6;
|
|
return 7;
|
|
}
|
|
|
|
void InitSymbolPolicyFeedback()
|
|
{
|
|
if(g_symbol_feedback_ready)
|
|
return;
|
|
|
|
string names[8] = {"XAUUSD","US30","NAS100","USOIL","CRYPTO","JPY","COMMODITY_FX","MAJOR_FX"};
|
|
for(int i = 0; i < 8; i++)
|
|
{
|
|
g_symbol_feedback_states[i].symbol_class = names[i];
|
|
g_symbol_feedback_states[i].sample_count = 0;
|
|
g_symbol_feedback_states[i].win_count = 0;
|
|
g_symbol_feedback_states[i].loss_count = 0;
|
|
g_symbol_feedback_states[i].continuation_count = 0;
|
|
g_symbol_feedback_states[i].continuation_win_count = 0;
|
|
g_symbol_feedback_states[i].counter_count = 0;
|
|
g_symbol_feedback_states[i].counter_win_count = 0;
|
|
g_symbol_feedback_states[i].ema_profit = 0.0;
|
|
g_symbol_feedback_states[i].ema_spread_points = 0.0;
|
|
g_symbol_feedback_states[i].ema_margin_headroom_pct = 0.0;
|
|
g_symbol_feedback_states[i].ema_risk_amount_pct = 0.0;
|
|
g_symbol_feedback_states[i].ema_win_rate = 0.0;
|
|
g_symbol_feedback_states[i].last_update = 0;
|
|
}
|
|
g_symbol_feedback_ready = true;
|
|
}
|
|
|
|
void UpdateSymbolPolicyFeedback(const string symbol_class,
|
|
const double profit,
|
|
const double spread_points,
|
|
const double margin_headroom_pct,
|
|
const double risk_amount_pct,
|
|
const int category)
|
|
{
|
|
InitSymbolPolicyFeedback();
|
|
|
|
int idx = GetSymbolFeedbackIndex(symbol_class);
|
|
bool win = (profit > 0.0);
|
|
SymbolPolicyFeedbackState state = g_symbol_feedback_states[idx];
|
|
|
|
state.sample_count++;
|
|
if(win) state.win_count++;
|
|
else state.loss_count++;
|
|
|
|
if(category == 0)
|
|
{
|
|
state.continuation_count++;
|
|
if(win) state.continuation_win_count++;
|
|
}
|
|
else
|
|
{
|
|
state.counter_count++;
|
|
if(win) state.counter_win_count++;
|
|
}
|
|
|
|
double alpha = 0.15;
|
|
if(state.sample_count == 1)
|
|
{
|
|
state.ema_profit = profit;
|
|
state.ema_spread_points = spread_points;
|
|
state.ema_margin_headroom_pct = margin_headroom_pct;
|
|
state.ema_risk_amount_pct = risk_amount_pct;
|
|
state.ema_win_rate = win ? 1.0 : 0.0;
|
|
}
|
|
else
|
|
{
|
|
state.ema_profit = (alpha * profit) + ((1.0 - alpha) * state.ema_profit);
|
|
state.ema_spread_points = (alpha * spread_points) + ((1.0 - alpha) * state.ema_spread_points);
|
|
state.ema_margin_headroom_pct = (alpha * margin_headroom_pct) + ((1.0 - alpha) * state.ema_margin_headroom_pct);
|
|
state.ema_risk_amount_pct = (alpha * risk_amount_pct) + ((1.0 - alpha) * state.ema_risk_amount_pct);
|
|
state.ema_win_rate = (alpha * (win ? 1.0 : 0.0)) + ((1.0 - alpha) * state.ema_win_rate);
|
|
}
|
|
|
|
state.last_update = TimeCurrent();
|
|
g_symbol_feedback_states[idx] = state;
|
|
}
|
|
|
|
void ApplySymbolPolicyFeedback(SymbolPolicy &policy)
|
|
{
|
|
InitSymbolPolicyFeedback();
|
|
|
|
int idx = GetSymbolFeedbackIndex(policy.symbol_class);
|
|
SymbolPolicyFeedbackState state = g_symbol_feedback_states[idx];
|
|
if(state.sample_count < 12)
|
|
return;
|
|
|
|
double win_rate = (state.sample_count > 0) ? ((double)state.win_count / (double)state.sample_count) : 0.0;
|
|
double cont_wr = (state.continuation_count > 0) ? ((double)state.continuation_win_count / (double)state.continuation_count) : win_rate;
|
|
double counter_wr = (state.counter_count > 0) ? ((double)state.counter_win_count / (double)state.counter_count) : win_rate;
|
|
|
|
if(win_rate >= 0.58 && state.ema_margin_headroom_pct >= policy.min_free_margin_pct * 1.20)
|
|
policy.base_risk_percent *= 1.03;
|
|
else if(win_rate <= 0.45 || state.ema_margin_headroom_pct < policy.min_free_margin_pct)
|
|
policy.base_risk_percent *= 0.92;
|
|
|
|
if(win_rate >= 0.60 && state.ema_spread_points <= policy.max_spread_points * 0.75)
|
|
policy.max_spread_points *= 1.02;
|
|
else if(win_rate <= 0.45 && state.ema_spread_points >= policy.max_spread_points * 0.85)
|
|
policy.max_spread_points *= 0.95;
|
|
|
|
if(win_rate >= 0.58 && state.ema_risk_amount_pct <= policy.max_account_risk_pct * 0.75)
|
|
policy.min_stop_points = (int)MathMax(20.0, (double)policy.min_stop_points * 0.98);
|
|
else if(win_rate <= 0.45)
|
|
policy.min_stop_points = (int)MathMin(5000.0, (double)policy.min_stop_points * 1.03);
|
|
|
|
if(win_rate >= 0.58)
|
|
policy.news_sensitivity = ClampDouble(policy.news_sensitivity * 0.98, 0.25, 1.0);
|
|
else if(win_rate <= 0.45)
|
|
policy.news_sensitivity = ClampDouble(policy.news_sensitivity * 1.05, 0.25, 1.0);
|
|
|
|
if(state.continuation_count >= 6 && state.counter_count >= 6)
|
|
{
|
|
if(cont_wr > counter_wr + 0.05)
|
|
{
|
|
policy.continuation_risk_mult = ClampDouble(policy.continuation_risk_mult * 1.02, 0.75, 1.25);
|
|
policy.counter_risk_mult = ClampDouble(policy.counter_risk_mult * 0.98, 0.55, 1.05);
|
|
}
|
|
else if(counter_wr > cont_wr + 0.05)
|
|
{
|
|
policy.continuation_risk_mult = ClampDouble(policy.continuation_risk_mult * 0.98, 0.75, 1.25);
|
|
policy.counter_risk_mult = ClampDouble(policy.counter_risk_mult * 1.02, 0.55, 1.05);
|
|
}
|
|
}
|
|
|
|
policy.base_risk_percent = ClampDouble(policy.base_risk_percent, 0.10, 0.80);
|
|
policy.max_spread_points = ClampDouble(policy.max_spread_points, 5.0, 5000.0);
|
|
policy.min_stop_points = (int)ClampDouble((double)policy.min_stop_points, 10.0, 10000.0);
|
|
}
|
|
|
|
string SymbolPolicyFeedbackSummary()
|
|
{
|
|
InitSymbolPolicyFeedback();
|
|
|
|
int idx = GetSymbolFeedbackIndex(g_symbol_policy.symbol_class);
|
|
SymbolPolicyFeedbackState state = g_symbol_feedback_states[idx];
|
|
double win_rate = (state.sample_count > 0) ? ((double)state.win_count / (double)state.sample_count) * 100.0 : 0.0;
|
|
return "Adapt: " + g_symbol_policy.symbol_class +
|
|
" n=" + IntegerToString(state.sample_count) +
|
|
" wr=" + DoubleToString(win_rate, 0) + "%" +
|
|
" risk=" + DoubleToString(g_symbol_policy.base_risk_percent, 2) + "%" +
|
|
" stop=" + IntegerToString(g_symbol_policy.min_stop_points) +
|
|
" spr=" + DoubleToString(g_symbol_policy.max_spread_points, 0);
|
|
}
|
|
|
|
color SymbolPolicyFeedbackColor()
|
|
{
|
|
InitSymbolPolicyFeedback();
|
|
|
|
int idx = GetSymbolFeedbackIndex(g_symbol_policy.symbol_class);
|
|
SymbolPolicyFeedbackState state = g_symbol_feedback_states[idx];
|
|
if(state.sample_count < 12)
|
|
return clrOrange;
|
|
|
|
double win_rate = (state.sample_count > 0) ? ((double)state.win_count / (double)state.sample_count) * 100.0 : 0.0;
|
|
if(win_rate >= 60.0) return clrGold;
|
|
if(win_rate >= 52.0) return clrLime;
|
|
if(win_rate >= 45.0) return clrCyan;
|
|
return clrRed;
|
|
}
|
|
|
|
double GetBrokerMinStopPoints()
|
|
{
|
|
long stops = (long)SymbolInfoInteger(_Symbol, SYMBOL_TRADE_STOPS_LEVEL);
|
|
if(stops < 0) stops = 0;
|
|
return (double)stops;
|
|
}
|
|
|
|
double GetCurrentSpreadPoints()
|
|
{
|
|
double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
|
|
double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
|
|
if(_Point <= 0.0)
|
|
return 0.0;
|
|
return (ask - bid) / _Point;
|
|
}
|
|
|
|
double ClampLotsToBroker(double lots)
|
|
{
|
|
double min_lot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN);
|
|
double max_lot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MAX);
|
|
double lot_step = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP);
|
|
|
|
if(lot_step <= 0.0) lot_step = 0.01;
|
|
lots = ClampDouble(lots, min_lot, max_lot);
|
|
lots = MathFloor(lots / lot_step) * lot_step;
|
|
return NormalizeDouble(MathMax(min_lot, lots), 2);
|
|
}
|
|
|
|
double EstimateRiskPerLot(const bool is_buy, const double entry_price, const double stop_price)
|
|
{
|
|
double profit = 0.0;
|
|
ENUM_ORDER_TYPE order_type = is_buy ? ORDER_TYPE_BUY : ORDER_TYPE_SELL;
|
|
if(!OrderCalcProfit(order_type, _Symbol, 1.0, entry_price, stop_price, profit))
|
|
return 0.0;
|
|
return MathAbs(profit);
|
|
}
|
|
|
|
bool EstimateMarginForLots(const bool is_buy, const double lots, const double entry_price, double &margin_required)
|
|
{
|
|
margin_required = 0.0;
|
|
ENUM_ORDER_TYPE order_type = is_buy ? ORDER_TYPE_BUY : ORDER_TYPE_SELL;
|
|
return OrderCalcMargin(order_type, _Symbol, lots, entry_price, margin_required);
|
|
}
|
|
|
|
double BuildSymbolPolicyRiskMultiplier(const bool continuation, const string session_name, const string session_phase)
|
|
{
|
|
double mult = 1.0;
|
|
|
|
if(g_symbol_policy.continuation_differs)
|
|
mult *= (continuation ? g_symbol_policy.continuation_risk_mult : g_symbol_policy.counter_risk_mult);
|
|
|
|
if(!SessionInPreferenceList(session_name, g_symbol_policy.preferred_sessions))
|
|
mult *= g_symbol_policy.require_session_alignment ? 0.50 : 0.80;
|
|
|
|
string phase = UpperCopy(session_phase);
|
|
if(phase == "M")
|
|
mult *= 0.80;
|
|
else if(phase == "D" && continuation)
|
|
mult *= 1.08;
|
|
else if(phase == "A" && !continuation)
|
|
mult *= 0.92;
|
|
|
|
return ClampDouble(mult, Signal_Risk_Down_Floor, Signal_Risk_Up_Cap);
|
|
}
|
|
|
|
string SymbolPolicyToJson()
|
|
{
|
|
string json = "{";
|
|
json += "\"symbol\":\"" + GWJsonEscape(g_symbol_policy.symbol_name) + "\",";
|
|
json += "\"class\":\"" + GWJsonEscape(g_symbol_policy.symbol_class) + "\",";
|
|
json += "\"base_risk_percent\":" + DoubleToString(g_symbol_policy.base_risk_percent, 2) + ",";
|
|
json += "\"max_spread_points\":" + DoubleToString(g_symbol_policy.max_spread_points, 1) + ",";
|
|
json += "\"min_stop_points\":" + IntegerToString(g_symbol_policy.min_stop_points) + ",";
|
|
json += "\"preferred_sessions\":\"" + GWJsonEscape(g_symbol_policy.preferred_sessions) + "\",";
|
|
json += "\"news_sensitivity\":" + DoubleToString(g_symbol_policy.news_sensitivity, 2) + ",";
|
|
json += "\"lot_floor\":" + DoubleToString(g_symbol_policy.lot_floor, 2) + ",";
|
|
json += "\"lot_ceiling\":" + DoubleToString(g_symbol_policy.lot_ceiling, 2) + ",";
|
|
json += "\"max_concurrent_exposure\":" + IntegerToString(g_symbol_policy.max_concurrent_exposure) + ",";
|
|
json += "\"continuation_differs\":" + BoolJson(g_symbol_policy.continuation_differs) + ",";
|
|
json += "\"continuation_risk_mult\":" + DoubleToString(g_symbol_policy.continuation_risk_mult, 2) + ",";
|
|
json += "\"counter_risk_mult\":" + DoubleToString(g_symbol_policy.counter_risk_mult, 2) + ",";
|
|
json += "\"require_session_alignment\":" + BoolJson(g_symbol_policy.require_session_alignment) + ",";
|
|
json += "\"min_free_margin_pct\":" + DoubleToString(g_symbol_policy.min_free_margin_pct, 1) + ",";
|
|
json += "\"max_account_risk_pct\":" + DoubleToString(g_symbol_policy.max_account_risk_pct, 2) + ",";
|
|
json += "\"max_margin_pct\":" + DoubleToString(g_symbol_policy.max_margin_pct, 2);
|
|
json += "}";
|
|
return json;
|
|
}
|
|
|
|
#endif
|