| Overall Statistics |
|
Total Trades 346 Average Win 0.80% Average Loss -0.32% Compounding Annual Return -0.340% Drawdown 9.900% Expectancy -0.035 Net Profit -2.026% Sharpe Ratio -0.053 Probabilistic Sharpe Ratio 0.208% Loss Rate 72% Win Rate 28% Profit-Loss Ratio 2.48 Alpha -0.001 Beta -0.005 Annual Standard Deviation 0.038 Annual Variance 0.001 Information Ratio -0.844 Tracking Error 0.124 Treynor Ratio 0.387 Total Fees $0.00 |
using QuantConnect.Indicators.CandlestickPatterns;
namespace QuantConnect.Algorithm.CSharp
{
public partial class TestAlgo : QCAlgorithm
{
//****************************************************************************************************************************************
// INITIALIASE BLOCK
//****************************************************************************************************************************************
public override void Initialize()
{
SetStartDate(2014, 1, 1);
SetEndDate(2019, 12, 31);
SetAccountCurrency(_AccountCurrency);
SetCash(_StartingCash);
// Loop through our list of symbols and add them to our subscription manager
foreach (var _symbol in _MySymbolList)
{
var _Forex = AddForex(_symbol, _Res, Market.Oanda, true, 20m);
DataDico.Add(_symbol, new SymbolData(this, _Forex.Symbol, _Forex.BaseCurrencySymbol));
}
_Drawdown_EMA = new ExponentialMovingAverage(30);
SetWarmUp(TimeSpan.FromDays(_WarmUpPeriod));
SetBrokerageModel(BrokerageName.OandaBrokerage, AccountType.Margin);
}
//****************************************************************************************************************************************
// ONDATA BLOCK
//****************************************************************************************************************************************
public override void OnData(Slice data)
{
//Loop through our dictionary
foreach (var symbolData in DataDico.Values)
{
if(!data.ContainsKey(symbolData.Symbol)) { return; }
//Check if algorithm is warming up and if indicators are ready, if not break
if(IsWarmingUp) { return; }
if(!symbolData.IsReady()) { return; }
if(!symbolData.ConsolidatorFlag) { return; }
symbolData.ConsolidatorFlag = false;
//Update prices for dummy entry logic
symbolData.Price_P2 = symbolData.Price_P1;
symbolData.Price_P1 = symbolData.Price;
symbolData.Price = data[symbolData.Symbol].Close;
//Drawdown Calculation - Portfolio Level
_TotalEquity_P1 = _TotalEquity;
_TotalEquity = Portfolio.TotalPortfolioValue;
_CumulativeReturn_P1 = _CumulativeReturn;
try
{ _CumulativeReturn = (1 + _CumulativeReturn_P1) * (1 + (_TotalEquity/_TotalEquity_P1 - 1)) - 1; }
catch (DivideByZeroException)
{ _CumulativeReturn = 0m; }
_HighWatermark = Math.Max(_HighWatermark, _CumulativeReturn);
_Drawdown = (1 + _CumulativeReturn) / (1 + _HighWatermark) - 1;
_MaxDrawdown = Math.Min(_MaxDrawdown, _Drawdown);
_Drawdown_EMA.Update(data[symbolData.Symbol].EndTime, _Drawdown);
Plot($"Portfolio Equity Curve", "Cumulative Return", _CumulativeReturn);
Plot($"Portfolio Equity Curve", "Drawdown", _Drawdown);
Plot($"Portfolio Equity Curve", "Drawdown EMA", _Drawdown_EMA);
Plot($"Portfolio Equity Curve", "High Watermark", _HighWatermark);
Plot($"Portfolio Equity Curve", "Max Drawdown", _MaxDrawdown);
//Dummy entry logic / exit logic
if (!Portfolio[symbolData.Symbol].Invested
&& symbolData.ROC > 0.015m && symbolData.Price_P2 < symbolData.Price_P1 && symbolData.Price < symbolData.Price_P1 && symbolData.Price > symbolData.Price_P2)
{
symbolData.Holding = Math.Round(_TotalEquity / symbolData.Price, 6);
MarketOrder(symbolData.Symbol, symbolData.Holding);
}
if(Portfolio.Invested && symbolData.Price_P2 > symbolData.Price_P1 && symbolData.Price_P1 > symbolData.Price)
{
symbolData.Holding = Portfolio[symbolData.Symbol].Quantity;
MarketOrder(symbolData.Symbol, -symbolData.Holding);
}
}
}
}
}namespace QuantConnect.Algorithm.CSharp
{
public partial class TestAlgo : QCAlgorithm
{
//****************************************************************************************************************************************
//USER VARIABLES
//****************************************************************************************************************************************
private static string _AccountCurrency = "USD";
private static decimal _StartingCash = 100000m;
Resolution _Res = Resolution.Hour; // Reference resolution for our custom TradeBar
private int _WarmUpPeriod = 200;
public decimal _PctRisk = 0.10m;
private decimal _StopLossPct = 0.05m;
//***Symbol List***
Dictionary <string, SymbolData> DataDico = new Dictionary <string, SymbolData>();
List <string> _MySymbolList = new List <string>
{
"EURUSD",
"USDJPY",
"GBPUSD",
"USDCAD",
};
//***Indicators***
public static int _ROCperiod = 30;
//***Portfolio Variables for Drawdown calculation***
private decimal _TotalEquity;
private decimal _TotalEquity_P1;
private decimal _CumulativeReturn;
private decimal _CumulativeReturn_P1;
private decimal _HighWatermark;
private decimal _Drawdown;
private ExponentialMovingAverage _Drawdown_EMA;
private decimal _MaxDrawdown;
private decimal _TotalEquity2;
}
}namespace QuantConnect.Algorithm.CSharp
{
public partial class TestAlgo : QCAlgorithm
{
public class SymbolData
{
//***Consolidator parameters***
public static int barPerTimeSpan = 24; // Number of block of data per custum TradeBar
public readonly TimeSpan barPeriod = TimeSpan.FromHours(barPerTimeSpan); // Set the size of our custum TradeBar
public QuoteBarConsolidator Consolidator;
public bool ConsolidatorFlag = false; // Flag whether a new custom TradeBar has been fully consolidated; used to prevent ONDATA block code to be executed otherwise
//***General***
public readonly QCAlgorithm algorithm;
public readonly Symbol Symbol;
public readonly string BaseSymbol;
public readonly string AccountSymbol;
public readonly RollingWindow<IBaseDataBar> BarsWin;
public readonly int windowSize = 5;
public decimal Holding;
public decimal Price;
public decimal Price_P1;
public decimal Price_P2;
//***Indicators***
public RateOfChange ROC;
//***SymbolData class constructor which initializes a new instance of SymbolData***
public SymbolData(QCAlgorithm algorithm, Symbol symbol, string baseSymbol)
{
this.algorithm = algorithm;
Symbol = symbol;
BaseSymbol = baseSymbol;
Consolidator = new QuoteBarConsolidator(barPeriod);
BarsWin = new RollingWindow<IBaseDataBar>(windowSize);
ROC = new RateOfChange(Symbol, _ROCperiod);
Consolidator.DataConsolidated += (sender, baseData) =>
{
var _bar = (IBaseDataBar)baseData;
ConsolidatorFlag = true;
BarsWin.Add(_bar);
ROC.Update(_bar.Time, _bar.Close);
};
algorithm.SubscriptionManager.AddConsolidator(symbol, Consolidator); // Adding this consolidator to the Subscription Manager so it gets auto updates
}
//***Returns true if all the data in this instance is ready***
public bool IsReady()
{
return BarsWin.IsReady && ROC.IsReady;
}
}
}
}