Thêm thống kê cho bot
This commit is contained in:
+39
-3
@@ -3,7 +3,7 @@
|
||||
//| BOS = Continue | CHoCH = Reversal |
|
||||
//+------------------------------------------------------------------+
|
||||
#property copyright "ICT 2026"
|
||||
#property version "1.138"
|
||||
#property version "1.142"
|
||||
#property description "ICT2026 MSS limit entry + SL swing CHoCH + TP intraday"
|
||||
|
||||
#include <ICT2026/Config.mqh>
|
||||
@@ -27,15 +27,18 @@ int OnInit()
|
||||
if(!lowOk)
|
||||
Print("[ICT2026] LowTF/FVG: chưa đủ dữ liệu ", EnumToString(InpFvgTf));
|
||||
|
||||
IctMssStats_Recompute(_Symbol, InpMssMagic);
|
||||
|
||||
if(biasOk || intraOk)
|
||||
{
|
||||
IctEaState_Refresh(_Symbol);
|
||||
PrintFormat("[ICT2026] Init — EA=%s | Bias=%s | H1=%s | Allow=%s | FVG=%d",
|
||||
PrintFormat("[ICT2026] Init — EA=%s | Bias=%s | H1=%s | Allow=%s | FVG=%d | Stats=%d trades",
|
||||
IctEaState_Code(IctEaState_Current()),
|
||||
IctBiasDisplayShort(g_ictDailyBias.bias),
|
||||
IctTrendDisplayShort(g_ictIntraday.trend),
|
||||
g_ictIntraday.isAllowTrade ? "true" : "false",
|
||||
g_ictLowTf.availableCount);
|
||||
g_ictLowTf.availableCount,
|
||||
g_ictMssStats.total);
|
||||
IctPanel_Render(_Symbol);
|
||||
IctDraw_Render(_Symbol);
|
||||
}
|
||||
@@ -87,6 +90,39 @@ void OnChartEvent(const int id, const long &lparam, const double &dparam, const
|
||||
}
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Bắt close (SL/TP/manual) → mark M5 FVG Used + reset MSS pipeline |
|
||||
//+------------------------------------------------------------------+
|
||||
void OnTradeTransaction(const MqlTradeTransaction &trans,
|
||||
const MqlTradeRequest &request,
|
||||
const MqlTradeResult &result)
|
||||
{
|
||||
if(trans.type != TRADE_TRANSACTION_DEAL_ADD)
|
||||
return;
|
||||
|
||||
const ulong deal = trans.deal;
|
||||
if(deal == 0 || !HistoryDealSelect(deal))
|
||||
return;
|
||||
if(HistoryDealGetString(deal, DEAL_SYMBOL) != _Symbol)
|
||||
return;
|
||||
if((ulong)HistoryDealGetInteger(deal, DEAL_MAGIC) != InpMssMagic)
|
||||
return;
|
||||
if(HistoryDealGetInteger(deal, DEAL_ENTRY) != DEAL_ENTRY_OUT)
|
||||
return;
|
||||
|
||||
const long reason = HistoryDealGetInteger(deal, DEAL_REASON);
|
||||
const double net = HistoryDealGetDouble(deal, DEAL_PROFIT)
|
||||
+ HistoryDealGetDouble(deal, DEAL_SWAP)
|
||||
+ HistoryDealGetDouble(deal, DEAL_COMMISSION);
|
||||
|
||||
IctMss_OnPositionClosed(_Symbol, reason, net);
|
||||
IctMssStats_Recompute(_Symbol, InpMssMagic);
|
||||
IctEaState_Refresh(_Symbol);
|
||||
IctPanel_Render(_Symbol);
|
||||
IctMssDraw_Render(_Symbol);
|
||||
IctFvgDraw_Render(_Symbol);
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
ENUM_ICT_BIAS ICT2026_GetDailyBias() { return g_ictDailyBias.bias; }
|
||||
|
||||
|
||||
@@ -81,6 +81,9 @@ input double InpMssSlAtrMult = 0.5; // SL: buffer ngo
|
||||
input double InpMssMinRR = 2.0; // TP tối thiểu (× risk entry→SL)
|
||||
input int InpMssPendingExpireHours = 24; // Hết hạn pending (giờ, 0=không)
|
||||
input bool InpMssOnePosition = true; // Một position/pending MSS
|
||||
input bool InpMssCancelPendingEod = true; // Hủy pending cuối phiên Mỹ (nếu chưa khớp)
|
||||
input int InpMssEodHour = 23; // Giờ EOD theo SERVER time (24h, vd EET broker = 23h ≈ 16:00 ET DST)
|
||||
input int InpMssEodMinute = 0; // Phút EOD
|
||||
|
||||
input group "══ Debug ══"
|
||||
input bool InpDebug = true;
|
||||
|
||||
@@ -136,7 +136,7 @@ bool IctMssEntry_ComputeLevels(const string sym, const IctFvgZone &m5Zone,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IctMssEntry_HasOpenExposure(const string sym)
|
||||
bool IctMssEntry_HasOpenPositionMagic(const string sym)
|
||||
{
|
||||
for(int i = PositionsTotal() - 1; i >= 0; i--)
|
||||
{
|
||||
@@ -148,6 +148,13 @@ bool IctMssEntry_HasOpenExposure(const string sym)
|
||||
if((ulong)PositionGetInteger(POSITION_MAGIC) == InpMssMagic)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IctMssEntry_HasOpenExposure(const string sym)
|
||||
{
|
||||
if(IctMssEntry_HasOpenPositionMagic(sym))
|
||||
return true;
|
||||
|
||||
for(int i = OrdersTotal() - 1; i >= 0; i--)
|
||||
{
|
||||
@@ -165,6 +172,109 @@ bool IctMssEntry_HasOpenExposure(const string sym)
|
||||
return false;
|
||||
}
|
||||
|
||||
string IctMssEntry_DealReasonText(const long r)
|
||||
{
|
||||
switch((ENUM_DEAL_REASON)r)
|
||||
{
|
||||
case DEAL_REASON_SL: return "SL";
|
||||
case DEAL_REASON_TP: return "TP";
|
||||
case DEAL_REASON_SO: return "Stop Out";
|
||||
case DEAL_REASON_EXPERT: return "Expert close";
|
||||
case DEAL_REASON_CLIENT: return "Manual";
|
||||
case DEAL_REASON_MOBILE: return "Mobile";
|
||||
case DEAL_REASON_WEB: return "Web";
|
||||
default: return (r < 0) ? "Detected" : "Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
void IctMssEntry_MarkM5FvgUsed(const string sym, const ulong fvgId)
|
||||
{
|
||||
if(fvgId == 0)
|
||||
return;
|
||||
const int idx = IctConfirmFvg_FindById(fvgId);
|
||||
if(idx < 0)
|
||||
return;
|
||||
g_ictConfirmFvgZones[idx].state = ICT_FVG_USED;
|
||||
if(g_ictConfirmFvgZones[idx].fvgUsedTime == 0)
|
||||
g_ictConfirmFvgZones[idx].fvgUsedTime = iTime(sym, InpConfirmTf, 0);
|
||||
}
|
||||
|
||||
void IctMss_OnEodCancel(const string sym, const ulong ticket)
|
||||
{
|
||||
const ulong m5Id = g_ictLowTf.mss.m5FvgId;
|
||||
const ulong h1Id = g_ictLowTf.mss.h1FvgId;
|
||||
|
||||
if(ticket > 0 && OrderSelect(ticket))
|
||||
g_ictMssTrade.OrderDelete(ticket);
|
||||
|
||||
IctMss_ResetState();
|
||||
g_ictLowTf.mss.displayReason = StringFormat(
|
||||
"EOD cancel pending #%I64u | H1 #%I64u — reset, chờ phiên mới",
|
||||
ticket, h1Id);
|
||||
|
||||
if(InpMssLogJournal)
|
||||
PrintFormat("[ICT2026/MSS] EOD cancel limit #%I64u | H1 #%I64u | M5 #%I64u | reset → WAIT_FVG_TOUCH",
|
||||
ticket, h1Id, m5Id);
|
||||
}
|
||||
|
||||
void IctMssEntry_CheckEodCancel(const string sym)
|
||||
{
|
||||
if(!InpMssCancelPendingEod)
|
||||
return;
|
||||
if(g_ictLowTf.mss.pendingTicket == 0)
|
||||
return;
|
||||
if(IctMssEntry_HasOpenPositionMagic(sym))
|
||||
return;
|
||||
|
||||
const ulong ticket = g_ictLowTf.mss.pendingTicket;
|
||||
if(!OrderSelect(ticket))
|
||||
{
|
||||
g_ictLowTf.mss.pendingTicket = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
MqlDateTime mdt;
|
||||
TimeToStruct(TimeCurrent(), mdt);
|
||||
const int nowMinutes = mdt.hour * 60 + mdt.min;
|
||||
const int eodMinutes = InpMssEodHour * 60 + InpMssEodMinute;
|
||||
if(nowMinutes < eodMinutes)
|
||||
return;
|
||||
|
||||
MqlDateTime d0;
|
||||
d0.year = mdt.year;
|
||||
d0.mon = mdt.mon;
|
||||
d0.day = mdt.day;
|
||||
d0.hour = 0;
|
||||
d0.min = 0;
|
||||
d0.sec = 0;
|
||||
const datetime dayStart = StructToTime(d0);
|
||||
|
||||
static datetime s_lastEodHandledDate = 0;
|
||||
if(s_lastEodHandledDate == dayStart)
|
||||
return;
|
||||
s_lastEodHandledDate = dayStart;
|
||||
|
||||
IctMss_OnEodCancel(sym, ticket);
|
||||
}
|
||||
|
||||
void IctMss_OnPositionClosed(const string sym, const long reason, const double netProfit)
|
||||
{
|
||||
const ulong m5Id = g_ictLowTf.mss.m5FvgId;
|
||||
const ulong h1Id = g_ictLowTf.mss.h1FvgId;
|
||||
const string rt = IctMssEntry_DealReasonText(reason);
|
||||
|
||||
IctMssEntry_MarkM5FvgUsed(sym, m5Id);
|
||||
|
||||
IctMss_ResetState();
|
||||
g_ictLowTf.mss.displayReason = StringFormat(
|
||||
"Đóng %s (net %.2f) | M5 FVG #%I64u → Used | chờ POI mới",
|
||||
rt, netProfit, m5Id);
|
||||
|
||||
if(InpMssLogJournal)
|
||||
PrintFormat("[ICT2026/MSS] Close (%s, net=%.2f) | H1 #%I64u | M5 #%I64u → Used | reset → WAIT_FVG_TOUCH",
|
||||
rt, netProfit, h1Id, m5Id);
|
||||
}
|
||||
|
||||
bool IctMssEntry_CancelTicket(const ulong ticket)
|
||||
{
|
||||
if(ticket == 0)
|
||||
@@ -216,6 +326,18 @@ void IctMssEntry_Init()
|
||||
|
||||
void IctMssEntry_Update(const string sym)
|
||||
{
|
||||
static bool s_hadPosition = false;
|
||||
const bool nowPosition = IctMssEntry_HasOpenPositionMagic(sym);
|
||||
|
||||
if(s_hadPosition && !nowPosition && g_ictLowTf.mss.phase != ICT_MSS_IDLE)
|
||||
{
|
||||
// Fallback nếu OnTradeTransaction miss (reload, disconnect, …)
|
||||
IctMss_OnPositionClosed(sym, -1L, 0.0);
|
||||
}
|
||||
s_hadPosition = nowPosition;
|
||||
|
||||
IctMssEntry_CheckEodCancel(sym);
|
||||
|
||||
if(g_ictLowTf.mss.phase == ICT_MSS_IDLE && g_ictLowTf.mss.pendingTicket > 0)
|
||||
{
|
||||
IctMssEntry_CancelTicket(g_ictLowTf.mss.pendingTicket);
|
||||
|
||||
@@ -10,10 +10,11 @@
|
||||
#include <ICT2026/IntradayStructure.mqh>
|
||||
#include <ICT2026/LowTfTrend.mqh>
|
||||
#include <ICT2026/EaState.mqh>
|
||||
#include <ICT2026/Stats.mqh>
|
||||
|
||||
const string ICT26_PANEL_PFX = "ICT26_PNL_";
|
||||
const string ICT26_PANEL_LEGACY = "ICT26_BIAS_PANEL";
|
||||
const int ICT26_PANEL_MAXLINE = 16;
|
||||
const int ICT26_PANEL_MAXLINE = 20;
|
||||
|
||||
const color ICT_PANEL_CLR_UP = clrLime;
|
||||
const color ICT_PANEL_CLR_DOWN = clrOrangeRed;
|
||||
@@ -197,6 +198,25 @@ void IctPanel_Render(const string sym)
|
||||
lines[n] = StringFormat("H1 FVG: %s", g_ictLowTf.displayReason);
|
||||
colors[n++] = (g_ictLowTf.availableCount > 0) ? ICT_PANEL_CLR_ALLOW : ICT_PANEL_CLR_MUTED;
|
||||
|
||||
ArrayResize(lines, n + 1);
|
||||
ArrayResize(colors, n + 1);
|
||||
lines[n] = "-------------------------";
|
||||
colors[n++] = ICT_PANEL_CLR_NEUTRAL;
|
||||
|
||||
const color clrStatsCounts = (g_ictMssStats.total > 0) ? ICT_PANEL_CLR_ALLOW : ICT_PANEL_CLR_MUTED;
|
||||
const color clrStatsPerf = (g_ictMssStats.netProfit > 0.0) ? ICT_PANEL_CLR_UP :
|
||||
(g_ictMssStats.netProfit < 0.0) ? ICT_PANEL_CLR_DOWN : ICT_PANEL_CLR_MUTED;
|
||||
|
||||
ArrayResize(lines, n + 1);
|
||||
ArrayResize(colors, n + 1);
|
||||
lines[n] = IctMssStats_LineCounts();
|
||||
colors[n++] = clrStatsCounts;
|
||||
|
||||
ArrayResize(lines, n + 1);
|
||||
ArrayResize(colors, n + 1);
|
||||
lines[n] = IctMssStats_LinePerf();
|
||||
colors[n++] = clrStatsPerf;
|
||||
|
||||
for(int i = 0; i < n; i++)
|
||||
IctPanel_SetLine(ch, i, i * lh, lines[i], colors[i]);
|
||||
|
||||
|
||||
@@ -566,6 +566,36 @@ ENUM_ICT_BIAS ICT2026_GetDailyBias();
|
||||
|
||||
## Changelog
|
||||
|
||||
### v1.142 — Fix Stats đếm thiếu lệnh
|
||||
|
||||
- Bug v1.141: `IctMssStats_ComputeR` gọi `HistorySelectByPosition` **bên trong vòng quét history toàn cục**
|
||||
→ selection bị thay → các index sau đọc từ history của 1 position → chỉ đếm được lệnh đầu tiên
|
||||
- Fix: 2-pass — collect ticket/reason/net trước (selection toàn cục còn nguyên), tính R sau
|
||||
- Thêm log journal `[ICT2026/Stats] Recompute …` để verify mỗi lần quét
|
||||
|
||||
### v1.141 — Stats lệnh MSS trên panel
|
||||
|
||||
- `Stats.mqh`: `IctMssStats_Recompute` quét HistoryDeals theo magic
|
||||
- Tính: total, TP, SL, khác, win, loss, sumR, netProfit
|
||||
- R thực = (close - entry)/(entry - SL) lấy từ deal IN + order SL
|
||||
- WR = TP / (TP+SL); Ravg = sumR/total
|
||||
- Hiển thị 2 dòng cuối panel: counts + WR/Ravg/Net
|
||||
- Recompute trên `OnInit` và sau mỗi `OnTradeTransaction` close
|
||||
|
||||
### v1.140 — Hủy pending cuối phiên Mỹ (EOD)
|
||||
|
||||
- Input: `InpMssCancelPendingEod` (true), `InpMssEodHour` (23), `InpMssEodMinute` (0) — **server time**
|
||||
- Mỗi tick: nếu có `pendingTicket` chưa fill + thời gian ≥ EOD → `OrderDelete` + `IctMss_ResetState`
|
||||
- Idempotent theo ngày: dùng `s_lastEodHandledDate` để không lặp
|
||||
- Bỏ qua nếu đang có position magic (chỉ hủy pending, không động vào lệnh đã khớp)
|
||||
|
||||
### v1.139 — Reset MSS pipeline sau SL/TP/close (option A)
|
||||
|
||||
- `OnTradeTransaction` lọc `DEAL_ENTRY_OUT` + magic → `IctMss_OnPositionClosed`
|
||||
- Mark **M5 FVG → Used**, `IctMss_ResetState`, journal lý do (SL/TP/Manual/…)
|
||||
- Fallback: detect transition `hadPosition → false` trong `IctMssEntry_Update` (miss OnTradeTransaction)
|
||||
- Sau close: EaState = `WAIT_FVG_TOUCH` → `SelectNearestH1Poi` (H1 cũ đã Used từ v1.136 → bỏ qua)
|
||||
|
||||
### v1.138 — POI H1 = FVG chưa Used **gần giá nhất**
|
||||
|
||||
- `IctMss_SelectNearestH1Poi`: khoảng cách bid → FVG; bỏ qua Used; tie → FVG mới hơn
|
||||
|
||||
@@ -0,0 +1,182 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| Stats.mqh — thống kê lệnh MSS từ history (theo magic) |
|
||||
//+------------------------------------------------------------------+
|
||||
#ifndef ICT2026_STATS_MQH
|
||||
#define ICT2026_STATS_MQH
|
||||
|
||||
#include <ICT2026/Config.mqh>
|
||||
|
||||
struct IctMssStats
|
||||
{
|
||||
int total;
|
||||
int tpCount;
|
||||
int slCount;
|
||||
int otherCount; // manual / expert / mobile / web
|
||||
int winCount; // profit > 0
|
||||
int lossCount; // profit < 0
|
||||
double sumR; // tổng R đạt được (đã quy chuẩn theo risk lúc vào lệnh)
|
||||
double netProfit;
|
||||
|
||||
void Clear()
|
||||
{
|
||||
total = tpCount = slCount = otherCount = 0;
|
||||
winCount = lossCount = 0;
|
||||
sumR = 0.0;
|
||||
netProfit = 0.0;
|
||||
}
|
||||
};
|
||||
|
||||
IctMssStats g_ictMssStats;
|
||||
static datetime g_ictMssStatsLastScan = 0;
|
||||
|
||||
double IctMssStats_ComputeR(const ulong outDeal)
|
||||
{
|
||||
const ulong posId = (ulong)HistoryDealGetInteger(outDeal, DEAL_POSITION_ID);
|
||||
const double closePrice = HistoryDealGetDouble(outDeal, DEAL_PRICE);
|
||||
if(posId == 0 || closePrice <= 0.0)
|
||||
return 0.0;
|
||||
|
||||
if(!HistorySelectByPosition(posId))
|
||||
return 0.0;
|
||||
|
||||
double entryPrice = 0.0;
|
||||
double slPrice = 0.0;
|
||||
bool isBuy = false;
|
||||
|
||||
const int n = HistoryDealsTotal();
|
||||
for(int i = 0; i < n; i++)
|
||||
{
|
||||
const ulong d = HistoryDealGetTicket(i);
|
||||
if(d == 0)
|
||||
continue;
|
||||
if((ulong)HistoryDealGetInteger(d, DEAL_POSITION_ID) != posId)
|
||||
continue;
|
||||
if(HistoryDealGetInteger(d, DEAL_ENTRY) != DEAL_ENTRY_IN)
|
||||
continue;
|
||||
|
||||
entryPrice = HistoryDealGetDouble(d, DEAL_PRICE);
|
||||
isBuy = (HistoryDealGetInteger(d, DEAL_TYPE) == DEAL_TYPE_BUY);
|
||||
|
||||
const ulong orderTicket = (ulong)HistoryDealGetInteger(d, DEAL_ORDER);
|
||||
if(orderTicket > 0 && HistoryOrderSelect(orderTicket))
|
||||
slPrice = HistoryOrderGetDouble(orderTicket, ORDER_SL);
|
||||
break;
|
||||
}
|
||||
|
||||
if(entryPrice <= 0.0 || slPrice <= 0.0)
|
||||
return 0.0;
|
||||
|
||||
const double risk = isBuy ? (entryPrice - slPrice) : (slPrice - entryPrice);
|
||||
if(risk <= _Point)
|
||||
return 0.0;
|
||||
|
||||
const double move = isBuy ? (closePrice - entryPrice) : (entryPrice - closePrice);
|
||||
return move / risk;
|
||||
}
|
||||
|
||||
void IctMssStats_Recompute(const string sym, const ulong magic)
|
||||
{
|
||||
g_ictMssStats.Clear();
|
||||
|
||||
if(!HistorySelect(0, TimeCurrent()))
|
||||
return;
|
||||
|
||||
// Pass 1: thu thập ticket + dữ liệu cơ bản trong khi global history selection còn nguyên.
|
||||
// Lưu ý: nếu gọi HistorySelectByPosition (trong ComputeR) ở đây → selection bị thay,
|
||||
// các index sau sẽ đọc từ history của 1 position → đếm thiếu lệnh.
|
||||
ulong outTickets[];
|
||||
long reasons[];
|
||||
double nets[];
|
||||
int cached = 0;
|
||||
|
||||
const int n = HistoryDealsTotal();
|
||||
ArrayResize(outTickets, n);
|
||||
ArrayResize(reasons, n);
|
||||
ArrayResize(nets, n);
|
||||
|
||||
for(int i = 0; i < n; i++)
|
||||
{
|
||||
const ulong d = HistoryDealGetTicket(i);
|
||||
if(d == 0)
|
||||
continue;
|
||||
if(HistoryDealGetString(d, DEAL_SYMBOL) != sym)
|
||||
continue;
|
||||
if((ulong)HistoryDealGetInteger(d, DEAL_MAGIC) != magic)
|
||||
continue;
|
||||
if(HistoryDealGetInteger(d, DEAL_ENTRY) != DEAL_ENTRY_OUT)
|
||||
continue;
|
||||
|
||||
outTickets[cached] = d;
|
||||
reasons[cached] = HistoryDealGetInteger(d, DEAL_REASON);
|
||||
nets[cached] = HistoryDealGetDouble(d, DEAL_PROFIT)
|
||||
+ HistoryDealGetDouble(d, DEAL_SWAP)
|
||||
+ HistoryDealGetDouble(d, DEAL_COMMISSION);
|
||||
cached++;
|
||||
}
|
||||
|
||||
// Pass 2: tính R cho từng deal (mỗi lần gọi sẽ thay selection — không ảnh hưởng vì đã cache xong).
|
||||
for(int k = 0; k < cached; k++)
|
||||
{
|
||||
const double r = IctMssStats_ComputeR(outTickets[k]);
|
||||
|
||||
g_ictMssStats.total++;
|
||||
g_ictMssStats.netProfit += nets[k];
|
||||
g_ictMssStats.sumR += r;
|
||||
|
||||
const ENUM_DEAL_REASON rs = (ENUM_DEAL_REASON)reasons[k];
|
||||
if(rs == DEAL_REASON_TP)
|
||||
g_ictMssStats.tpCount++;
|
||||
else if(rs == DEAL_REASON_SL)
|
||||
g_ictMssStats.slCount++;
|
||||
else
|
||||
g_ictMssStats.otherCount++;
|
||||
|
||||
if(nets[k] > 0.0)
|
||||
g_ictMssStats.winCount++;
|
||||
else if(nets[k] < 0.0)
|
||||
g_ictMssStats.lossCount++;
|
||||
}
|
||||
|
||||
g_ictMssStatsLastScan = TimeCurrent();
|
||||
|
||||
if(InpMssLogJournal)
|
||||
PrintFormat("[ICT2026/Stats] Recompute %s magic=%I64u | total=%d TP=%d SL=%d khác=%d | net=%.2f sumR=%.2f",
|
||||
sym, magic,
|
||||
g_ictMssStats.total, g_ictMssStats.tpCount,
|
||||
g_ictMssStats.slCount, g_ictMssStats.otherCount,
|
||||
g_ictMssStats.netProfit, g_ictMssStats.sumR);
|
||||
}
|
||||
|
||||
double IctMssStats_WinratePct()
|
||||
{
|
||||
const int decided = g_ictMssStats.tpCount + g_ictMssStats.slCount;
|
||||
if(decided == 0)
|
||||
return 0.0;
|
||||
return 100.0 * (double)g_ictMssStats.tpCount / (double)decided;
|
||||
}
|
||||
|
||||
double IctMssStats_AvgR()
|
||||
{
|
||||
if(g_ictMssStats.total <= 0)
|
||||
return 0.0;
|
||||
return g_ictMssStats.sumR / (double)g_ictMssStats.total;
|
||||
}
|
||||
|
||||
string IctMssStats_LineCounts()
|
||||
{
|
||||
return StringFormat("Stats: %d lệnh | TP %d | SL %d | khác %d",
|
||||
g_ictMssStats.total,
|
||||
g_ictMssStats.tpCount,
|
||||
g_ictMssStats.slCount,
|
||||
g_ictMssStats.otherCount);
|
||||
}
|
||||
|
||||
string IctMssStats_LinePerf()
|
||||
{
|
||||
const double wr = IctMssStats_WinratePct();
|
||||
const double ar = IctMssStats_AvgR();
|
||||
return StringFormat("WR %.1f%% | Ravg %+.2fR | Net %+.2f",
|
||||
wr, ar, g_ictMssStats.netProfit);
|
||||
}
|
||||
|
||||
#endif
|
||||
BIN
Binary file not shown.
Reference in New Issue
Block a user