static void CalculateAdditionalStats()
{
longBalance = new double[Bars];
shortBalance = new double[Bars];
longMoneyBalance = new double[Bars];
shortMoneyBalance = new double[Bars];
maxLongMoneyBalance = Configs.InitialAccount;
minLongMoneyBalance = Configs.InitialAccount;
maxShortMoneyBalance = Configs.InitialAccount;
minShortMoneyBalance = Configs.InitialAccount;
maxLongBalance = 0;
minLongBalance = 0;
maxShortBalance = 0;
minShortBalance = 0;
maxLongBalanceDate = Time[0];
minLongBalanceDate = Time[0];
maxShortBalanceDate = Time[0];
minShortBalanceDate = Time[0];
maxLongMoneyBalanceDate = Time[0];
minLongMoneyBalanceDate = Time[0];
maxShortMoneyBalanceDate = Time[0];
minShortMoneyBalanceDate = Time[0];
maxLongDrawdownDate = Time[0];
maxShortDrawdownDate = Time[0];
maxLongMoneyDrawdownDate = Time[0];
maxShortMoneyDrawdownDate = Time[0];
grossLongProfit = 0;
grossLongLoss = 0;
grossShortProfit = 0;
grossShortLoss = 0;
grossLongMoneyProfit = 0;
grossLongMoneyLoss = 0;
grossShortMoneyProfit = 0;
grossShortMoneyLoss = 0;
maxLongDrawdown = 0;
maxShortDrawdown = 0;
maxLongMoneyDrawdown = 0;
maxShortMoneyDrawdown = 0;
maxShortDrawdown = 0;
maxLongMoneyDrawdown = 0;
maxShortMoneyDrawdown = 0;
maxLongMoneyDrawdownPercent = 0;
maxShortMoneyDrawdownPercent = 0;
barsWithPos = 0;
barsWithLongPos = 0;
barsWithShortPos = 0;
winningLongTrades = 0;
winningShortTrades = 0;
losingLongTrades = 0;
losingShortTrades = 0;
totalLongTrades = 0;
totalShortTrades = 0;
maxLongWin = 0;
maxShortWin = 0;
maxLongMoneyWin = 0;
maxShortMoneyWin = 0;
maxLongLoss = 0;
maxShortLoss = 0;
maxLongMoneyLoss = 0;
maxShortMoneyLoss = 0;
for (int bar = 0; bar < FirstBar; bar++)
{
longBalance[bar] = 0;
shortBalance[bar] = 0;
longMoneyBalance[bar] = Configs.InitialAccount;
shortMoneyBalance[bar] = Configs.InitialAccount;
}
for (int bar = Data.FirstBar; bar < Bars; bar++)
{
double accountExchangeRate = AccountExchangeRate(Close[bar]);
double pipsToMoney = InstrProperties.Point * InstrProperties.LotSize / accountExchangeRate;
longBalance[bar] = longBalance[bar - 1];
shortBalance[bar] = shortBalance[bar - 1];
longMoneyBalance[bar] = longMoneyBalance[bar - 1];
shortMoneyBalance[bar] = shortMoneyBalance[bar - 1];
bool isLong = false;
bool isShort = false;
for (int pos = 0; pos < Positions(bar); pos++)
{
if (PosDir(bar, pos) == PosDirection.Long)
isLong = true;
if (PosDir(bar, pos) == PosDirection.Short)
isShort = true;
double positionProfitLoss = PosProfitLoss(bar, pos);
double positionMoneyProfitLoss = PosMoneyProfitLoss(bar, pos);
if (PosTransaction(bar, pos) == Transaction.Close ||
PosTransaction(bar, pos) == Transaction.Reduce ||
PosTransaction(bar, pos) == Transaction.Reverse)
{
if (OrdFromNumb(PosOrdNumb(bar, pos)).OrdDir == OrderDirection.Sell)
{ // Closing long position
longBalance[bar] += positionProfitLoss;
longMoneyBalance[bar] += positionMoneyProfitLoss;
if (positionProfitLoss > 0)
{
grossLongProfit += positionProfitLoss;
grossLongMoneyProfit += positionMoneyProfitLoss;
winningLongTrades++;
if (positionProfitLoss > maxLongWin)
maxLongWin = positionProfitLoss;
if (positionMoneyProfitLoss > maxLongMoneyWin)
maxLongMoneyWin = positionMoneyProfitLoss;
}
if (positionProfitLoss < 0)
{
grossLongLoss += positionProfitLoss;
grossLongMoneyLoss += positionMoneyProfitLoss;
losingLongTrades++;
if (positionProfitLoss < maxLongLoss)
maxLongLoss = positionProfitLoss;
if (positionMoneyProfitLoss < maxLongMoneyLoss)
maxLongMoneyLoss = positionMoneyProfitLoss;
}
totalLongTrades++;
}
if (OrdFromNumb(PosOrdNumb(bar, pos)).OrdDir == OrderDirection.Buy)
{ // Closing short position
shortBalance[bar] += positionProfitLoss;
shortMoneyBalance[bar] += positionMoneyProfitLoss;
if (positionProfitLoss > 0)
{
grossShortProfit += positionProfitLoss;
grossShortMoneyProfit += positionMoneyProfitLoss;
winningShortTrades++;
if (positionProfitLoss > maxShortWin)
maxShortWin = positionProfitLoss;
if (positionMoneyProfitLoss > maxShortMoneyWin)
maxShortMoneyWin = positionMoneyProfitLoss;
}
if (positionProfitLoss < 0)
{
grossShortLoss += positionProfitLoss;
grossShortMoneyLoss += positionMoneyProfitLoss;
losingShortTrades++;
if (positionProfitLoss < maxShortLoss)
maxShortLoss = positionProfitLoss;
if (positionMoneyProfitLoss < maxShortMoneyLoss)
maxShortMoneyLoss = positionMoneyProfitLoss;
}
totalShortTrades++;
}
}
}
barsWithPos += (isLong || isShort) ? 1 : 0;
barsWithLongPos += isLong ? 1 : 0;
barsWithShortPos += isShort ? 1 : 0;
if (maxLongBalance < longBalance[bar])
{
maxLongBalance = longBalance[bar];
maxLongBalanceDate = Time[bar];
}
if (minLongBalance > longBalance[bar])
{
minLongBalance = longBalance[bar];
minLongBalanceDate = Time[bar];
}
if (maxShortBalance < shortBalance[bar])
{
maxShortBalance = shortBalance[bar];
maxShortBalanceDate = Time[bar];
}
if (minShortBalance > shortBalance[bar])
{
minShortBalance = shortBalance[bar];
minShortBalanceDate = Time[bar];
}
if (maxLongMoneyBalance < longMoneyBalance[bar])
{
maxLongMoneyBalance = longMoneyBalance[bar];
maxLongMoneyBalanceDate = Time[bar];
}
if (minLongMoneyBalance > longMoneyBalance[bar])
{
minLongMoneyBalance = longMoneyBalance[bar];
minLongMoneyBalanceDate = Time[bar];
}
if (maxShortMoneyBalance < shortMoneyBalance[bar])
{
maxShortMoneyBalance = shortMoneyBalance[bar];
maxShortMoneyBalanceDate = Time[bar];
}
if (minShortMoneyBalance > shortMoneyBalance[bar])
{
minShortMoneyBalance = shortMoneyBalance[bar];
minShortMoneyBalanceDate = Time[bar];
}
// Maximum Drawdown
if (maxLongBalance - longBalance[bar] > maxLongDrawdown)
{
maxLongDrawdown = maxLongBalance - longBalance[bar];
maxLongDrawdownDate = Time[bar];
}
if (maxLongMoneyBalance - longMoneyBalance[bar] > maxLongMoneyDrawdown)
{
maxLongMoneyDrawdown = maxLongMoneyBalance - longMoneyBalance[bar];
maxLongMoneyDrawdownPercent = 100 * maxLongMoneyDrawdown / maxLongMoneyBalance;
maxLongMoneyDrawdownDate = Time[bar];
}
if (maxShortBalance - shortBalance[bar] > maxShortDrawdown)
{
maxShortDrawdown = maxShortBalance - shortBalance[bar];
maxShortDrawdownDate = Time[bar];
}
if (maxShortMoneyBalance - shortMoneyBalance[bar] > maxShortMoneyDrawdown)
{
maxShortMoneyDrawdown = maxShortMoneyBalance - shortMoneyBalance[bar];
maxShortMoneyDrawdownPercent = 100 * maxShortMoneyDrawdown / maxShortMoneyBalance;
maxShortMoneyDrawdownDate = Time[bar];
}
}
// Holding period returns
AHPR = 0;
AHPRLong = 0;
AHPRShort = 0;
double[] HPR = new double[totalTrades];
double[] HPRLong = new double[totalLongTrades];
double[] HPRShort = new double[totalShortTrades];
double totalHPR = 0;
double totalHPRLong = 0;
double totalHPRShort = 0;
double startBalance = Configs.InitialAccount;
double startBalanceLong = Configs.InitialAccount;
double startBalanceShort = Configs.InitialAccount;
int count = 0;
int countL = 0;
int countS = 0;
for (int pos = 0; pos < PositionsTotal; pos++)
{ // Charged fees
Position position = Backtester.PosFromNumb(pos);
// Winning losing trades.
if (position.Transaction == Transaction.Close ||
position.Transaction == Transaction.Reduce ||
position.Transaction == Transaction.Reverse)
{
if (OrdFromNumb(position.FormOrdNumb).OrdDir == OrderDirection.Sell)
{ // Closing long position
HPRLong[countL] = 1 + position.MoneyProfitLoss / startBalanceLong;
totalHPRLong += HPRLong[countL];
countL++;
startBalanceLong += position.MoneyProfitLoss;
}
if (OrdFromNumb(position.FormOrdNumb).OrdDir == OrderDirection.Buy)
{ // Closing short position
HPRShort[countS] = 1 + position.MoneyProfitLoss / startBalanceShort;
totalHPRShort += HPRShort[countS];
countS++;
startBalanceShort += position.MoneyProfitLoss;
}
HPR[count] = 1 + position.MoneyProfitLoss / startBalance;
totalHPR += HPR[count];
count++;
startBalance += position.MoneyProfitLoss;
}
}
double averageHPR = totalHPR / totalTrades;
double averageHPRLong = totalHPRLong / totalLongTrades;
double averageHPRShort = totalHPRShort / totalShortTrades;
AHPR = 100 * (averageHPR - 1);
AHPRLong = 100 * (averageHPRLong - 1);
AHPRShort = 100 * (averageHPRShort - 1);
GHPR = 100 * (Math.Pow((NetMoneyBalance / Configs.InitialAccount), (1f / totalTrades)) - 1);
GHPRLong = 100 * (Math.Pow((NetLongMoneyBalance / Configs.InitialAccount), (1f / totalLongTrades)) - 1);
GHPRShort = 100 * (Math.Pow((NetShortMoneyBalance / Configs.InitialAccount), (1f / totalShortTrades)) - 1);
// Sharpe Ratio
sharpeRatio = 0;
sharpeRatioLong = 0;
sharpeRatioShort = 0;
double sumPow = 0;
double sumPowLong = 0;
double sumPowShort = 0;
for (int i = 0; i < totalTrades; i++)
sumPow += Math.Pow((HPR[i] - averageHPR), 2);
for (int i = 0; i < totalLongTrades; i++)
sumPowLong += Math.Pow((HPRLong[i] - averageHPRLong), 2);
for (int i = 0; i < totalShortTrades; i++)
sumPowShort += Math.Pow((HPRShort[i] - averageHPRShort), 2);
double stDev = Math.Sqrt(sumPow / (totalTrades - 1));
double stDevLong = Math.Sqrt(sumPowLong / (totalLongTrades - 1));
double stDevShort = Math.Sqrt(sumPowShort / (totalShortTrades - 1));
sharpeRatio = (averageHPR - 1) / stDev;
sharpeRatioLong = (averageHPRLong - 1) / stDevLong;
sharpeRatioShort = (averageHPRShort - 1) / stDevShort;
}