| Overall Statistics |
|
Total Orders 62 Average Win 1.46% Average Loss -1.67% Compounding Annual Return -1.613% Drawdown 7.000% Expectancy 0.004 Start Equity 100000 End Equity 98786.38 Net Profit -1.214% Sharpe Ratio -0.535 Sortino Ratio -0.657 Probabilistic Sharpe Ratio 11.741% Loss Rate 46% Win Rate 54% Profit-Loss Ratio 0.87 Alpha -0.039 Beta 0.033 Annual Standard Deviation 0.07 Annual Variance 0.005 Information Ratio -0.483 Tracking Error 0.149 Treynor Ratio -1.127 Total Fees $0.00 Estimated Strategy Capacity $0 Lowest Capacity Asset XAGUSD 8I Portfolio Turnover 19.83% |
#region imports
using Newtonsoft.Json;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Globalization;
using System.Drawing;
using QuantConnect;
using QuantConnect.Algorithm.Framework;
using QuantConnect.Algorithm.Framework.Selection;
using QuantConnect.Algorithm.Framework.Alphas;
using QuantConnect.Algorithm.Framework.Portfolio;
using QuantConnect.Algorithm.Framework.Portfolio.SignalExports;
using QuantConnect.Algorithm.Framework.Execution;
using QuantConnect.Algorithm.Framework.Risk;
using QuantConnect.Algorithm.Selection;
using QuantConnect.Api;
using QuantConnect.Parameters;
using QuantConnect.Benchmarks;
using QuantConnect.Brokerages;
using QuantConnect.Configuration;
using QuantConnect.Util;
using QuantConnect.Interfaces;
using QuantConnect.Algorithm;
using QuantConnect.Indicators;
using QuantConnect.Data;
using QuantConnect.Data.Auxiliary;
using QuantConnect.Data.Consolidators;
using QuantConnect.Data.Custom;
using QuantConnect.Data.Custom.IconicTypes;
using QuantConnect.DataSource;
using QuantConnect.Data.Fundamental;
using QuantConnect.Data.Market;
using QuantConnect.Data.Shortable;
using QuantConnect.Data.UniverseSelection;
using QuantConnect.Notifications;
using QuantConnect.Orders;
using QuantConnect.Orders.Fees;
using QuantConnect.Orders.Fills;
using QuantConnect.Orders.OptionExercise;
using QuantConnect.Orders.Slippage;
using QuantConnect.Orders.TimeInForces;
using QuantConnect.Python;
using QuantConnect.Scheduling;
using QuantConnect.Securities;
using QuantConnect.Securities.Equity;
using QuantConnect.Securities.Future;
using QuantConnect.Securities.Option;
using QuantConnect.Securities.Positions;
using QuantConnect.Securities.Forex;
using QuantConnect.Securities.Crypto;
using QuantConnect.Securities.CryptoFuture;
using QuantConnect.Securities.Interfaces;
using QuantConnect.Securities.Volatility;
using QuantConnect.Storage;
using QuantConnect.Statistics;
using QCAlgorithmFramework = QuantConnect.Algorithm.QCAlgorithm;
using QCAlgorithmFrameworkBridge = QuantConnect.Algorithm.QCAlgorithm;
#endregion
namespace QuantConnect
{
public class GoldSilverPairsTradingAlgorithm : QCAlgorithm
{
// Use 500-step mean and SD indicator on determine the spread relative difference for trading signal generation
private SimpleMovingAverage _spreadMean = new SimpleMovingAverage(500);
private StandardDeviation _spreadStd = new StandardDeviation(500);
private Security[] _pair = new Security[2];
public override void Initialize()
{
SetStartDate(2018, 7, 1);
SetEndDate(2019, 3, 31);
SetCash(100000);
// Request gold and sliver spot CFDs for trading their spread difference, assuming their spread series is cointegrated
AddCfd("XAUUSD", Resolution.Hour);
AddCfd("XAGUSD", Resolution.Hour);
}
public override void OnData(Slice slice)
{
// Update the indicator with updated spread difference, such that the an updated cointegration threshold is calculated for trade inception
var spread = _pair[1].Price - _pair[0].Price;
_spreadMean.Update(Time, spread);
_spreadStd.Update(Time, spread);
var upperthreshold = _spreadMean + _spreadStd;
var lowerthreshold = _spreadMean - _spreadStd;
// If the spread is higher than upper threshold, bet theie spread series will revert to mean
if (spread > upperthreshold)
{
SetHoldings(_pair[0].Symbol, 1);
SetHoldings(_pair[1].Symbol, -1);
}
else if (spread < lowerthreshold)
{
SetHoldings(_pair[0].Symbol, -1);
SetHoldings(_pair[1].Symbol, 1);
}
// Close positions if mean reverted
else if ((Portfolio[_pair[0].Symbol].Quantity > 0m && spread < _spreadMean)
|| (Portfolio[_pair[0].Symbol].Quantity < 0m && spread > _spreadMean))
{
Liquidate();
}
}
public override void OnSecuritiesChanged(SecurityChanges changes)
{
_pair = changes.AddedSecurities.ToArray();
//1. Call for 500 days of history data for each symbol in the pair and save to the variable history
var history = History(_pair.Select(x => x.Symbol), 500);
//2. Iterate through the history tuple and update the mean and standard deviation with historical data
foreach(var slice in history)
{
var spread = slice[_pair[1].Symbol].Close - slice[_pair[0].Symbol].Close;
_spreadMean.Update(slice.Time, spread);
_spreadStd.Update(slice.Time, spread);
}
}
}
}