543 lines
23 KiB
PHP
543 lines
23 KiB
PHP
<?php
|
|
/**
|
|
* Forex Trading Analytics Engine (Myfxbook Grade Calculations)
|
|
* Precision metrics, risk ratios, drawdown curves, and performance breakdowns.
|
|
*/
|
|
|
|
class AnalyticsEngine {
|
|
private PDO $db;
|
|
|
|
public function __construct(PDO $db) {
|
|
$this->db = $db;
|
|
}
|
|
|
|
public function getFullAnalytics(int $accountId, ?string $from = null, ?string $to = null, ?string $symbol = null, ?string $strategy = null): array {
|
|
// 1. Fetch Account Details
|
|
$stmtAcc = $this->db->prepare("SELECT * FROM accounts WHERE id = ?");
|
|
$stmtAcc->execute([$accountId]);
|
|
$account = $stmtAcc->fetch();
|
|
|
|
if (!$account) {
|
|
return ['error' => 'Account not found'];
|
|
}
|
|
|
|
$initialBalance = (float)$account['initial_balance'];
|
|
|
|
// 2. Fetch Trades Query Filtered
|
|
$sql = "SELECT * FROM trades WHERE account_id = ?";
|
|
$params = [$accountId];
|
|
|
|
if ($from) {
|
|
$sql .= " AND open_time >= ?";
|
|
$params[] = $from . ' 00:00:00';
|
|
}
|
|
if ($to) {
|
|
$sql .= " AND open_time <= ?";
|
|
$params[] = $to . ' 23:59:59';
|
|
}
|
|
if ($symbol && $symbol !== 'ALL') {
|
|
$sql .= " AND symbol = ?";
|
|
$params[] = $symbol;
|
|
}
|
|
if ($strategy && $strategy !== 'ALL') {
|
|
$sql .= " AND strategy = ?";
|
|
$params[] = $strategy;
|
|
}
|
|
|
|
$sql .= " ORDER BY open_time ASC, id ASC";
|
|
$stmtTrades = $this->db->prepare($sql);
|
|
$stmtTrades->execute($params);
|
|
$trades = $stmtTrades->fetchAll();
|
|
|
|
// 3. Process Metrics & Aggregations
|
|
$totalTrades = count($trades);
|
|
$closedTrades = [];
|
|
$openTrades = [];
|
|
|
|
$grossProfit = 0.0;
|
|
$grossLoss = 0.0;
|
|
$totalCommission = 0.0;
|
|
$totalSwap = 0.0;
|
|
$totalPips = 0.0;
|
|
$wonTradesCount = 0;
|
|
$lostTradesCount = 0;
|
|
$beTradesCount = 0;
|
|
|
|
$longTradesCount = 0;
|
|
$longWonCount = 0;
|
|
$longProfit = 0.0;
|
|
|
|
$shortTradesCount = 0;
|
|
$shortWonCount = 0;
|
|
$shortProfit = 0.0;
|
|
|
|
$bestTradeProfit = 0.0;
|
|
$worstTradeProfit = 0.0;
|
|
$bestTradePips = 0.0;
|
|
$worstTradePips = 0.0;
|
|
|
|
$winPipsSum = 0.0;
|
|
$lossPipsSum = 0.0;
|
|
|
|
$currentBalance = $initialBalance;
|
|
$peakBalance = $initialBalance;
|
|
$maxDrawdownAmount = 0.0;
|
|
$maxDrawdownPercent = 0.0;
|
|
|
|
$growthCurve = [];
|
|
$drawdownCurve = [];
|
|
|
|
$consecutiveWins = 0;
|
|
$consecutiveLosses = 0;
|
|
$maxConsecutiveWins = 0;
|
|
$maxConsecutiveLosses = 0;
|
|
|
|
$totalDurationSec = 0;
|
|
$winDurationSec = 0;
|
|
$lossDurationSec = 0;
|
|
|
|
$dailyReturns = []; // date => pnl
|
|
$symbolStats = [];
|
|
$strategyStats = [];
|
|
$emotionStats = [];
|
|
$sessionStats = ['London' => ['count' => 0, 'profit' => 0, 'wins' => 0], 'New York' => ['count' => 0, 'profit' => 0, 'wins' => 0], 'Asian' => ['count' => 0, 'profit' => 0, 'wins' => 0], 'Overlap' => ['count' => 0, 'profit' => 0, 'wins' => 0]];
|
|
$dayOfWeekStats = [
|
|
1 => ['name' => 'Monday', 'fa' => 'دوشنبه', 'count' => 0, 'profit' => 0, 'wins' => 0],
|
|
2 => ['name' => 'Tuesday', 'fa' => 'سهشنبه', 'count' => 0, 'profit' => 0, 'wins' => 0],
|
|
3 => ['name' => 'Wednesday', 'fa' => 'چهارشنبه', 'count' => 0, 'profit' => 0, 'wins' => 0],
|
|
4 => ['name' => 'Thursday', 'fa' => 'پنجشنبه', 'count' => 0, 'profit' => 0, 'wins' => 0],
|
|
5 => ['name' => 'Friday', 'fa' => 'جمعه', 'count' => 0, 'profit' => 0, 'wins' => 0],
|
|
6 => ['name' => 'Saturday', 'fa' => 'شنبه', 'count' => 0, 'profit' => 0, 'wins' => 0],
|
|
7 => ['name' => 'Sunday', 'fa' => 'یکشنبه', 'count' => 0, 'profit' => 0, 'wins' => 0],
|
|
];
|
|
$hourlyStats = [];
|
|
for ($h = 0; $h < 24; $h++) {
|
|
$hourlyStats[$h] = ['hour' => $h, 'count' => 0, 'profit' => 0, 'wins' => 0];
|
|
}
|
|
|
|
// Add starting point to growth curve
|
|
$growthCurve[] = [
|
|
'date' => date('Y-m-d H:i', strtotime($account['created_at'] ?? 'now')),
|
|
'trade_index' => 0,
|
|
'balance' => round($initialBalance, 2),
|
|
'equity' => round($initialBalance, 2),
|
|
'profit' => 0.0,
|
|
'gain_percent' => 0.0,
|
|
'symbol' => 'START',
|
|
'ticket' => '-'
|
|
];
|
|
|
|
$tradeIndex = 0;
|
|
|
|
foreach ($trades as $t) {
|
|
$profit = (float)$t['profit'];
|
|
$pips = (float)$t['pips'];
|
|
$comm = (float)$t['commission'];
|
|
$swap = (float)$t['swap'];
|
|
$sym = $t['symbol'];
|
|
$strat = $t['strategy'] ?: 'Price Action';
|
|
$emo = $t['emotion'] ?: 'Disciplined';
|
|
$sess = $t['session'] ?: 'London';
|
|
|
|
if ($t['status'] === 'open') {
|
|
$openTrades[] = $t;
|
|
continue;
|
|
}
|
|
|
|
$closedTrades[] = $t;
|
|
$tradeIndex++;
|
|
|
|
$totalCommission += $comm;
|
|
$totalSwap += $swap;
|
|
$totalPips += $pips;
|
|
|
|
// Balance & Equity Tracking
|
|
$netTradeProfit = $profit + $comm + $swap;
|
|
$currentBalance += $netTradeProfit;
|
|
|
|
if ($currentBalance > $peakBalance) {
|
|
$peakBalance = $currentBalance;
|
|
}
|
|
$currentDDAmount = $peakBalance - $currentBalance;
|
|
$currentDDPercent = $peakBalance > 0 ? ($currentDDAmount / $peakBalance) * 100 : 0;
|
|
|
|
if ($currentDDAmount > $maxDrawdownAmount) {
|
|
$maxDrawdownAmount = $currentDDAmount;
|
|
}
|
|
if ($currentDDPercent > $maxDrawdownPercent) {
|
|
$maxDrawdownPercent = $currentDDPercent;
|
|
}
|
|
|
|
$gainPercent = $initialBalance > 0 ? (($currentBalance - $initialBalance) / $initialBalance) * 100 : 0;
|
|
|
|
$closeDate = $t['close_time'] ?: $t['open_time'];
|
|
$growthCurve[] = [
|
|
'date' => date('Y-m-d H:i', strtotime($closeDate)),
|
|
'trade_index' => $tradeIndex,
|
|
'balance' => round($currentBalance, 2),
|
|
'equity' => round($currentBalance, 2),
|
|
'profit' => round($netTradeProfit, 2),
|
|
'gain_percent' => round($gainPercent, 2),
|
|
'symbol' => $sym,
|
|
'ticket' => $t['ticket'] ?: "#$tradeIndex"
|
|
];
|
|
|
|
$drawdownCurve[] = [
|
|
'date' => date('Y-m-d H:i', strtotime($closeDate)),
|
|
'trade_index' => $tradeIndex,
|
|
'drawdown_percent' => round(-$currentDDPercent, 2),
|
|
'drawdown_amount' => round($currentDDAmount, 2)
|
|
];
|
|
|
|
// Win / Loss classification
|
|
if ($profit > 0) {
|
|
$wonTradesCount++;
|
|
$grossProfit += $profit;
|
|
$winPipsSum += $pips;
|
|
$consecutiveWins++;
|
|
$consecutiveLosses = 0;
|
|
if ($consecutiveWins > $maxConsecutiveWins) {
|
|
$maxConsecutiveWins = $consecutiveWins;
|
|
}
|
|
if ($profit > $bestTradeProfit) {
|
|
$bestTradeProfit = $profit;
|
|
}
|
|
if ($pips > $bestTradePips) {
|
|
$bestTradePips = $pips;
|
|
}
|
|
} elseif ($profit < 0) {
|
|
$lostTradesCount++;
|
|
$grossLoss += abs($profit);
|
|
$lossPipsSum += abs($pips);
|
|
$consecutiveLosses++;
|
|
$consecutiveWins = 0;
|
|
if ($consecutiveLosses > $maxConsecutiveLosses) {
|
|
$maxConsecutiveLosses = $consecutiveLosses;
|
|
}
|
|
if ($profit < $worstTradeProfit) {
|
|
$worstTradeProfit = $profit;
|
|
}
|
|
if ($pips < $worstTradePips) {
|
|
$worstTradePips = $pips;
|
|
}
|
|
} else {
|
|
$beTradesCount++;
|
|
}
|
|
|
|
// Long / Short stats
|
|
if (strtolower($t['trade_type']) === 'buy') {
|
|
$longTradesCount++;
|
|
$longProfit += $netTradeProfit;
|
|
if ($profit > 0) $longWonCount++;
|
|
} else {
|
|
$shortTradesCount++;
|
|
$shortProfit += $netTradeProfit;
|
|
if ($profit > 0) $shortWonCount++;
|
|
}
|
|
|
|
// Duration calculation
|
|
if ($t['open_time'] && $t['close_time']) {
|
|
$dur = max(0, strtotime($t['close_time']) - strtotime($t['open_time']));
|
|
$totalDurationSec += $dur;
|
|
if ($profit > 0) $winDurationSec += $dur;
|
|
elseif ($profit < 0) $lossDurationSec += $dur;
|
|
}
|
|
|
|
// Daily return aggregation
|
|
$dayKey = date('Y-m-d', strtotime($t['open_time']));
|
|
if (!isset($dailyReturns[$dayKey])) {
|
|
$dailyReturns[$dayKey] = ['profit' => 0.0, 'pips' => 0.0, 'trades' => 0, 'wins' => 0, 'losses' => 0];
|
|
}
|
|
$dailyReturns[$dayKey]['profit'] += $netTradeProfit;
|
|
$dailyReturns[$dayKey]['pips'] += $pips;
|
|
$dailyReturns[$dayKey]['trades']++;
|
|
if ($profit > 0) $dailyReturns[$dayKey]['wins']++;
|
|
elseif ($profit < 0) $dailyReturns[$dayKey]['losses']++;
|
|
|
|
// By Symbol Breakdown
|
|
if (!isset($symbolStats[$sym])) {
|
|
$symbolStats[$sym] = ['symbol' => $sym, 'count' => 0, 'wins' => 0, 'losses' => 0, 'profit' => 0.0, 'pips' => 0.0, 'longs' => 0, 'shorts' => 0];
|
|
}
|
|
$symbolStats[$sym]['count']++;
|
|
$symbolStats[$sym]['profit'] += $netTradeProfit;
|
|
$symbolStats[$sym]['pips'] += $pips;
|
|
if ($profit > 0) $symbolStats[$sym]['wins']++;
|
|
elseif ($profit < 0) $symbolStats[$sym]['losses']++;
|
|
if (strtolower($t['trade_type']) === 'buy') $symbolStats[$sym]['longs']++;
|
|
else $symbolStats[$sym]['shorts']++;
|
|
|
|
// By Strategy Breakdown
|
|
if (!isset($strategyStats[$strat])) {
|
|
$strategyStats[$strat] = ['strategy' => $strat, 'count' => 0, 'wins' => 0, 'losses' => 0, 'profit' => 0.0, 'gross_profit' => 0.0, 'gross_loss' => 0.0];
|
|
}
|
|
$strategyStats[$strat]['count']++;
|
|
$strategyStats[$strat]['profit'] += $netTradeProfit;
|
|
if ($profit > 0) {
|
|
$strategyStats[$strat]['wins']++;
|
|
$strategyStats[$strat]['gross_profit'] += $profit;
|
|
} elseif ($profit < 0) {
|
|
$strategyStats[$strat]['losses']++;
|
|
$strategyStats[$strat]['gross_loss'] += abs($profit);
|
|
}
|
|
|
|
// By Emotion Breakdown
|
|
if (!isset($emotionStats[$emo])) {
|
|
$emotionStats[$emo] = ['emotion' => $emo, 'count' => 0, 'wins' => 0, 'profit' => 0.0, 'pips' => 0.0];
|
|
}
|
|
$emotionStats[$emo]['count']++;
|
|
$emotionStats[$emo]['profit'] += $netTradeProfit;
|
|
$emotionStats[$emo]['pips'] += $pips;
|
|
if ($profit > 0) $emotionStats[$emo]['wins']++;
|
|
|
|
// By Session Breakdown
|
|
if (isset($sessionStats[$sess])) {
|
|
$sessionStats[$sess]['count']++;
|
|
$sessionStats[$sess]['profit'] += $netTradeProfit;
|
|
if ($profit > 0) $sessionStats[$sess]['wins']++;
|
|
}
|
|
|
|
// By Day of Week & Hour
|
|
$openTs = strtotime($t['open_time']);
|
|
$dow = (int)date('N', $openTs); // 1 = Monday .. 7 = Sunday
|
|
if (isset($dayOfWeekStats[$dow])) {
|
|
$dayOfWeekStats[$dow]['count']++;
|
|
$dayOfWeekStats[$dow]['profit'] += $netTradeProfit;
|
|
if ($profit > 0) $dayOfWeekStats[$dow]['wins']++;
|
|
}
|
|
|
|
$hr = (int)date('G', $openTs); // 0 .. 23
|
|
if (isset($hourlyStats[$hr])) {
|
|
$hourlyStats[$hr]['count']++;
|
|
$hourlyStats[$hr]['profit'] += $netTradeProfit;
|
|
if ($profit > 0) $hourlyStats[$hr]['wins']++;
|
|
}
|
|
}
|
|
|
|
// Open floating calculation
|
|
$openFloatingProfit = 0.0;
|
|
foreach ($openTrades as $ot) {
|
|
$openFloatingProfit += (float)$ot['profit'] + (float)$ot['commission'] + (float)$ot['swap'];
|
|
}
|
|
$currentEquity = $currentBalance + $openFloatingProfit;
|
|
|
|
// Total Net Closed Profit
|
|
$totalClosedProfit = $currentBalance - $initialBalance;
|
|
$totalGainPercent = $initialBalance > 0 ? (($currentEquity - $initialBalance) / $initialBalance) * 100 : 0;
|
|
$closedGainPercent = $initialBalance > 0 ? ($totalClosedProfit / $initialBalance) * 100 : 0;
|
|
|
|
$closedCount = count($closedTrades);
|
|
$winRate = $closedCount > 0 ? ($wonTradesCount / $closedCount) * 100 : 0;
|
|
$lossRate = $closedCount > 0 ? ($lostTradesCount / $closedCount) * 100 : 0;
|
|
|
|
$profitFactor = $grossLoss > 0 ? round($grossProfit / $grossLoss, 2) : ($grossProfit > 0 ? 99.9 : 0.0);
|
|
$avgWin = $wonTradesCount > 0 ? $grossProfit / $wonTradesCount : 0.0;
|
|
$avgLoss = $lostTradesCount > 0 ? $grossLoss / $lostTradesCount : 0.0;
|
|
$winLossRatio = $avgLoss > 0 ? round($avgWin / $avgLoss, 2) : 0.0;
|
|
|
|
$expectancy = ($winRate / 100 * $avgWin) - ($lossRate / 100 * $avgLoss);
|
|
|
|
$avgPipsWin = $wonTradesCount > 0 ? $winPipsSum / $wonTradesCount : 0.0;
|
|
$avgPipsLoss = $lostTradesCount > 0 ? $lossPipsSum / $lostTradesCount : 0.0;
|
|
|
|
$longWinRate = $longTradesCount > 0 ? ($longWonCount / $longTradesCount) * 100 : 0;
|
|
$shortWinRate = $shortTradesCount > 0 ? ($shortWonCount / $shortTradesCount) * 100 : 0;
|
|
|
|
$avgTradeDuration = $closedCount > 0 ? round($totalDurationSec / $closedCount) : 0;
|
|
$avgWinDuration = $wonTradesCount > 0 ? round($winDurationSec / $wonTradesCount) : 0;
|
|
$avgLossDuration = $lostTradesCount > 0 ? round($lossDurationSec / $lostTradesCount) : 0;
|
|
|
|
// Sharpe & Sortino Ratio estimation
|
|
$dailyPnLValues = array_column($dailyReturns, 'profit');
|
|
$sharpeRatio = 0.0;
|
|
$sortinoRatio = 0.0;
|
|
if (count($dailyPnLValues) > 2) {
|
|
$meanDaily = array_sum($dailyPnLValues) / count($dailyPnLValues);
|
|
$variance = 0.0;
|
|
$downsideVariance = 0.0;
|
|
foreach ($dailyPnLValues as $dp) {
|
|
$diff = $dp - $meanDaily;
|
|
$variance += ($diff * $diff);
|
|
if ($dp < 0) {
|
|
$downsideVariance += ($dp * $dp);
|
|
}
|
|
}
|
|
$stdDev = sqrt($variance / count($dailyPnLValues));
|
|
$downsideStdDev = sqrt($downsideVariance / count($dailyPnLValues));
|
|
|
|
if ($stdDev > 0) {
|
|
$sharpeRatio = round(($meanDaily / $stdDev) * sqrt(252), 2); // Annualized (252 trading days)
|
|
}
|
|
if ($downsideStdDev > 0) {
|
|
$sortinoRatio = round(($meanDaily / $downsideStdDev) * sqrt(252), 2);
|
|
}
|
|
}
|
|
|
|
// Today, This Week, This Month profit
|
|
$todayStr = date('Y-m-d');
|
|
$thisWeekStart = date('Y-m-d', strtotime('monday this week'));
|
|
$thisMonthStart = date('Y-m-01');
|
|
|
|
$todayProfit = $dailyReturns[$todayStr]['profit'] ?? 0.0;
|
|
$thisWeekProfit = 0.0;
|
|
$thisMonthProfit = 0.0;
|
|
|
|
foreach ($dailyReturns as $dDate => $dData) {
|
|
if ($dDate >= $thisWeekStart) {
|
|
$thisWeekProfit += $dData['profit'];
|
|
}
|
|
if ($dDate >= $thisMonthStart) {
|
|
$thisMonthProfit += $dData['profit'];
|
|
}
|
|
}
|
|
|
|
// Monthly Returns Table (Year x Months Heatmap)
|
|
$monthlyReturns = [];
|
|
foreach ($dailyReturns as $dDate => $dData) {
|
|
$yr = (int)date('Y', strtotime($dDate));
|
|
$mo = (int)date('n', strtotime($dDate));
|
|
if (!isset($monthlyReturns[$yr])) {
|
|
$monthlyReturns[$yr] = [
|
|
'year' => $yr,
|
|
'months' => array_fill(1, 12, ['profit' => 0.0, 'gain_percent' => 0.0, 'trades' => 0]),
|
|
'total_profit' => 0.0,
|
|
'total_gain_percent' => 0.0,
|
|
'total_trades' => 0
|
|
];
|
|
}
|
|
$monthlyReturns[$yr]['months'][$mo]['profit'] += $dData['profit'];
|
|
$monthlyReturns[$yr]['months'][$mo]['trades'] += $dData['trades'];
|
|
$monthlyReturns[$yr]['total_profit'] += $dData['profit'];
|
|
$monthlyReturns[$yr]['total_trades'] += $dData['trades'];
|
|
}
|
|
|
|
foreach ($monthlyReturns as $yr => &$yData) {
|
|
foreach ($yData['months'] as $mo => &$mVal) {
|
|
if ($initialBalance > 0) {
|
|
$mVal['gain_percent'] = round(($mVal['profit'] / $initialBalance) * 100, 2);
|
|
}
|
|
}
|
|
if ($initialBalance > 0) {
|
|
$yData['total_gain_percent'] = round(($yData['total_profit'] / $initialBalance) * 100, 2);
|
|
}
|
|
}
|
|
unset($yData, $mVal);
|
|
|
|
// Format Breakdown Lists
|
|
$symbolsList = array_values($symbolStats);
|
|
usort($symbolsList, fn($a, $b) => $b['profit'] <=> $a['profit']);
|
|
foreach ($symbolsList as &$sItem) {
|
|
$sItem['win_rate'] = $sItem['count'] > 0 ? round(($sItem['wins'] / $sItem['count']) * 100, 1) : 0;
|
|
$sItem['avg_profit'] = $sItem['count'] > 0 ? round($sItem['profit'] / $sItem['count'], 2) : 0;
|
|
}
|
|
|
|
$strategiesList = array_values($strategyStats);
|
|
usort($strategiesList, fn($a, $b) => $b['profit'] <=> $a['profit']);
|
|
foreach ($strategiesList as &$stItem) {
|
|
$stItem['win_rate'] = $stItem['count'] > 0 ? round(($stItem['wins'] / $stItem['count']) * 100, 1) : 0;
|
|
$stItem['profit_factor'] = $stItem['gross_loss'] > 0 ? round($stItem['gross_profit'] / $stItem['gross_loss'], 2) : ($stItem['gross_profit'] > 0 ? 99.9 : 0.0);
|
|
}
|
|
|
|
$emotionsList = array_values($emotionStats);
|
|
usort($emotionsList, fn($a, $b) => $b['profit'] <=> $a['profit']);
|
|
foreach ($emotionsList as &$emItem) {
|
|
$emItem['win_rate'] = $emItem['count'] > 0 ? round(($emItem['wins'] / $emItem['count']) * 100, 1) : 0;
|
|
}
|
|
|
|
$sessionsList = [];
|
|
foreach ($sessionStats as $sessKey => $sessData) {
|
|
$sessionsList[] = [
|
|
'session' => $sessKey,
|
|
'count' => $sessData['count'],
|
|
'profit' => round($sessData['profit'], 2),
|
|
'win_rate' => $sessData['count'] > 0 ? round(($sessData['wins'] / $sessData['count']) * 100, 1) : 0
|
|
];
|
|
}
|
|
|
|
$daysOfWeekList = [];
|
|
foreach ($dayOfWeekStats as $dowKey => $dowData) {
|
|
$daysOfWeekList[] = [
|
|
'day_num' => $dowKey,
|
|
'name' => $dowData['name'],
|
|
'name_fa' => $dowData['fa'],
|
|
'count' => $dowData['count'],
|
|
'profit' => round($dowData['profit'], 2),
|
|
'win_rate' => $dowData['count'] > 0 ? round(($dowData['wins'] / $dowData['count']) * 100, 1) : 0
|
|
];
|
|
}
|
|
|
|
$hourlyList = array_values($hourlyStats);
|
|
foreach ($hourlyList as &$hrItem) {
|
|
$hrItem['profit'] = round($hrItem['profit'], 2);
|
|
$hrItem['win_rate'] = $hrItem['count'] > 0 ? round(($hrItem['wins'] / $hrItem['count']) * 100, 1) : 0;
|
|
}
|
|
|
|
return [
|
|
'account' => $account,
|
|
'summary' => [
|
|
'initial_balance' => round($initialBalance, 2),
|
|
'current_balance' => round($currentBalance, 2),
|
|
'current_equity' => round($currentEquity, 2),
|
|
'open_floating_profit' => round($openFloatingProfit, 2),
|
|
'total_closed_profit' => round($totalClosedProfit, 2),
|
|
'total_gain_percent' => round($totalGainPercent, 2),
|
|
'closed_gain_percent' => round($closedGainPercent, 2),
|
|
'today_profit' => round($todayProfit, 2),
|
|
'this_week_profit' => round($thisWeekProfit, 2),
|
|
'this_month_profit' => round($thisMonthProfit, 2),
|
|
'total_trades' => $totalTrades,
|
|
'closed_trades' => $closedCount,
|
|
'open_trades' => count($openTrades),
|
|
'won_trades' => $wonTradesCount,
|
|
'lost_trades' => $lostTradesCount,
|
|
'breakeven_trades' => $beTradesCount,
|
|
'win_rate' => round($winRate, 1),
|
|
'loss_rate' => round($lossRate, 1),
|
|
'profit_factor' => $profitFactor,
|
|
'gross_profit' => round($grossProfit, 2),
|
|
'gross_loss' => round($grossLoss, 2),
|
|
'avg_win' => round($avgWin, 2),
|
|
'avg_loss' => round($avgLoss, 2),
|
|
'win_loss_ratio' => $winLossRatio,
|
|
'expectancy' => round($expectancy, 2),
|
|
'total_pips' => round($totalPips, 1),
|
|
'avg_pips_win' => round($avgPipsWin, 1),
|
|
'avg_pips_loss' => round($avgPipsLoss, 1),
|
|
'best_trade_profit' => round($bestTradeProfit, 2),
|
|
'worst_trade_profit' => round($worstTradeProfit, 2),
|
|
'best_trade_pips' => round($bestTradePips, 1),
|
|
'worst_trade_pips' => round($worstTradePips, 1),
|
|
'max_consecutive_wins' => $maxConsecutiveWins,
|
|
'max_consecutive_losses' => $maxConsecutiveLosses,
|
|
'max_drawdown_amount' => round($maxDrawdownAmount, 2),
|
|
'max_drawdown_percent' => round($maxDrawdownPercent, 2),
|
|
'sharpe_ratio' => $sharpeRatio,
|
|
'sortino_ratio' => $sortinoRatio,
|
|
'total_commission' => round($totalCommission, 2),
|
|
'total_swap' => round($totalSwap, 2),
|
|
'long_trades' => $longTradesCount,
|
|
'long_won' => $longWonCount,
|
|
'long_win_rate' => round($longWinRate, 1),
|
|
'long_profit' => round($longProfit, 2),
|
|
'short_trades' => $shortTradesCount,
|
|
'short_won' => $shortWonCount,
|
|
'short_win_rate' => round($shortWinRate, 1),
|
|
'short_profit' => round($shortProfit, 2),
|
|
'avg_trade_duration_seconds' => $avgTradeDuration,
|
|
'avg_win_duration_seconds' => $avgWinDuration,
|
|
'avg_loss_duration_seconds' => $avgLossDuration,
|
|
],
|
|
'growth_curve' => $growthCurve,
|
|
'drawdown_curve' => $drawdownCurve,
|
|
'monthly_returns' => array_values($monthlyReturns),
|
|
'daily_pnl' => $dailyReturns,
|
|
'by_symbol' => $symbolsList,
|
|
'by_strategy' => $strategiesList,
|
|
'by_emotion' => $emotionsList,
|
|
'by_session' => $sessionsList,
|
|
'by_day_of_week' => $daysOfWeekList,
|
|
'by_hour' => $hourlyList,
|
|
'open_trades' => $openTrades
|
|
];
|
|
}
|
|
}
|