Overall Statistics |
Total Trades 16285 Average Win 0.15% Average Loss -0.88% Compounding Annual Return 281.049% Drawdown 23.000% Expectancy 0.012 Net Profit 117.261% Sharpe Ratio 2.659 Loss Rate 13% Win Rate 87% Profit-Loss Ratio 0.17 Alpha 1.157 Beta -0.149 Annual Standard Deviation 0.442 Annual Variance 0.195 Information Ratio 2.792 Tracking Error 0.462 Treynor Ratio -7.896 Total Fees $651.40 |
/* * QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals. * Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ using System; using System.Collections.Generic; using QuantConnect.Brokerages; using QuantConnect.Data; using QuantConnect.Data.Custom; using QuantConnect.Data.Market; using QuantConnect.Indicators; using QuantConnect.Orders; using QuantConnect.Orders.Fees; using QuantConnect.Securities; namespace QuantConnect.Algorithm.CSharp { /// <summary> /// Basic template algorithm simply initializes the date range and cash /// </summary> public class BasicTemplateAlgorithm : QCAlgorithm, IRequiredOrderMethods { //Configure which securities you'd like to use: public string[] Symbols = { "EURUSD", "NZDUSD", "GBPUSD" , "NZDCHF"}; //Risk in dollars per trade ($ or the quote currency of the assets) public decimal RiskPerTrade = 40; //Sets the profit to loss ratio we want to hit before we exit public decimal TargetProfitLossRatio = 0.125m; //Cap the investment maximum size ($). public decimal MaximumTradeSize = 10000; private Resolution _dataResolution = Resolution.Minute; private Dictionary<Symbol, TradingAsset> _tradingAssets; private WilliamsFractals _williamsFractals; public override void Initialize() { SetStartDate(2015, 1, 1); SetEndDate(2015, 8, 1); SetCash(3000); _tradingAssets = new Dictionary<Symbol, TradingAsset>(); //Add as many securities as you like. All the data will be passed into the event handler: foreach (var symbol in Symbols) { AddSecurity(SecurityType.Forex, symbol, _dataResolution); Securities[symbol].FeeModel = new ConstantFeeModel(0.04m); // Securities[symbol].FeeModel = new FxcmFeeModel(); //SetBrokerageModel(BrokerageName.FxcmBrokerage); _williamsFractals = new WilliamsFractals(); Securities[symbol].VolatilityModel = new ThreeSigmaVolatilityModel(STD(symbol, 60, _dataResolution)); _tradingAssets.Add(symbol, new TradingAsset(Securities[symbol], new OneShotTrigger(new FractalSignal(_williamsFractals, Portfolio[symbol])), // new FractalExit(null, _williamsFractals, Portfolio[symbol]), new ProfitTargetSignalExit(null, TargetProfitLossRatio), RiskPerTrade, MaximumTradeSize, this )); } SetBenchmark("EURUSD"); } /// <summary> /// OnData event is the primary entry point for your algorithm. Each new data point will be pumped in here. /// </summary> public void OnData(TradeBars data) { if (data.Count < Symbols.Length) return; // if (!_williamsFractals.IsReady) return; foreach (var symbol in Symbols) { _williamsFractals.Update(data[symbol]); //Create a trading asset package for each symbol _tradingAssets[symbol].Scan(data[symbol]); } } // public void OnData(Quandl data) // { // // } } /// <summary> /// Interface for the two types of orders required to make the trade /// </summary> public interface IRequiredOrderMethods { OrderTicket StopMarketOrder(Symbol symbol, int quantity, decimal stopPrice, string tag = ""); OrderTicket MarketOrder(Symbol symbol, int quantity, bool asynchronous = false, string tag = ""); } }
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using QuantConnect.Data.Market; using QuantConnect.Indicators; namespace QuantConnect.Algorithm.CSharp { class WilliamsFractals : TradeBarIndicator { private readonly RollingWindow<TradeBar> _fractal; private readonly int _fractalMidIndex; private decimal _barryUp; private decimal _barryDown; public decimal BarryUp => _barryUp; public decimal BarryDown => _barryDown; public decimal MidPoint => (_barryUp - _barryDown) / 2m; public override bool IsReady => _fractal.IsReady; public WilliamsFractals(int fractalLength = 5) : this("WilliamsFractals" + fractalLength, fractalLength) { } public WilliamsFractals(string name, int fractalLength = 5) : base(name) { _fractal = new RollingWindow<TradeBar>(fractalLength); _fractalMidIndex = fractalLength / 2 - (fractalLength % 2 == 0 ? 1 : 0); } protected override decimal ComputeNextValue(TradeBar input) { _fractal.Add(input); if (!_fractal.IsReady) return MidPoint; if (_fractal.Max(bar => bar.High) == _fractal[_fractalMidIndex].High) { _barryUp = input.High; } if (_fractal.Min(bar => bar.Low) == _fractal[_fractalMidIndex].Low) { _barryDown = input.Low; } return MidPoint; } } }
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using QuantConnect.Data.Market; using QuantConnect.Securities; namespace QuantConnect.Algorithm.CSharp { class FractalExit :IExitSignal { private TradeProfile _tradeProfile; private WilliamsFractals _williamsFractals; private SecurityHolding _securityHolding; public FractalExit(TradeProfile tradeProfile, WilliamsFractals williamsFractals, SecurityHolding securityHolding) { _tradeProfile = tradeProfile; _williamsFractals = williamsFractals; _securityHolding = securityHolding; } public void Scan(TradeBar data) { _williamsFractals.Update(data); if (_securityHolding.IsLong) { Signal = data.Price >= _williamsFractals.BarryUp ? SignalType.Exit : SignalType.NoSignal; } else if (_securityHolding.IsShort) { Signal = data.Price <= _williamsFractals.BarryDown ? SignalType.Exit : SignalType.NoSignal; } else { Signal = SignalType.NoSignal; } } public SignalType Signal { get; private set; } public ISignal ExitSignalFactory(TradeProfile tradeProfile) { return new FractalExit(tradeProfile, _williamsFractals, _securityHolding); } } }
using QuantConnect.Orders; namespace QuantConnect.Algorithm.CSharp { public class TradeProfile { //Ticket tracking the open order public OrderTicket OpenTicket, StopTicket, ExitTicket; //Keeps track of the current price and the direction of the trade public Symbol TradeSymbol; public int TradeDirection; public decimal CurrentPrice; private readonly decimal _risk; private readonly int _maximumTradeQuantity; protected decimal Volatility; /// <summary> /// Calclate the quantity based on the target risk in dollars. /// </summary> public int Quantity { get { if (Volatility == 0) return 0; long quantity = (long)(_risk / Volatility); if (quantity > _maximumTradeQuantity) { return _maximumTradeQuantity < 1000 ? 1000 : _maximumTradeQuantity; } return (int) quantity < 1000 ? 1000 : (int) quantity; } } /// <summary> /// What is the stoploss move from current price /// </summary> public decimal DeltaStopLoss { get { if (Quantity == 0) return 0m; return _risk / Quantity; } } /// <summary> /// Calculates the Profit:Loss ratio /// </summary> public decimal ProfitLossRatio { get { if(OpenTicket != null) { return OpenTicket.Quantity*(CurrentPrice - OpenTicket.AverageFillPrice) /_risk; } return 0m; } } /// <summary> /// Exit signal for each trade /// </summary> public ISignal ExitSignal { get; set; } public bool IsTradeFinished { get; set; } /// <summary> /// Create a new tradeProfile and limit the maximum risk. /// </summary> /// <param name="symbol"></param> /// <param name="volatility"></param> /// <param name="risk"></param> /// <param name="currentPrice"></param> /// <param name="maximumTradeSize"></param> /// <param name="exitSignal"></param> public TradeProfile(Symbol symbol, decimal volatility, decimal risk, decimal currentPrice, decimal maximumTradeSize) { TradeSymbol = symbol; Volatility = volatility; _risk = risk; CurrentPrice = currentPrice; _maximumTradeQuantity = (int) (maximumTradeSize/CurrentPrice); } } }
using QuantConnect.Data.Market; using QuantConnect.Securities; namespace QuantConnect.Algorithm.CSharp { class FractalSignal : ISignal { private WilliamsFractals _williamsFractals; private SecurityHolding _securityHolding; public FractalSignal(WilliamsFractals williamsFractals, SecurityHolding securityHolding) { _williamsFractals = williamsFractals; _securityHolding = securityHolding; } public void Scan(TradeBar data) { _williamsFractals.Update(data); if (_williamsFractals.IsReady) { if (data.Price >= _williamsFractals.BarryUp && !_securityHolding.Invested) { Signal = SignalType.Short; } else if (data.Price <= _williamsFractals.BarryDown && !_securityHolding.Invested) { Signal = SignalType.Long; } else { Signal = SignalType.NoSignal; } } else { Signal = SignalType.NoSignal; } } public SignalType Signal { get; private set; } } }
using System.Collections.Generic; using System.Linq; using QuantConnect.Data.Market; using QuantConnect.Orders; using QuantConnect.Securities; namespace QuantConnect.Algorithm.CSharp { class TradingAsset { public IExitSignal ExitSignal; public ISignal EnterSignal; private readonly decimal _risk; private readonly Symbol _symbol; private readonly Security _security; private readonly decimal _maximumTradeSize; private List<TradeProfile> _tradeProfiles; private readonly IRequiredOrderMethods _orderMethods; /// <summary> /// Initializes each Trading Asset /// </summary> /// <param name="security"></param> /// <param name="enterSignal"></param> /// <param name="exitSignal"></param> /// <param name="risk"></param> /// <param name="maximumTradeSize"></param> /// <param name="orderMethods"></param> public TradingAsset(Security security, ISignal enterSignal, IExitSignal exitSignal, decimal risk, decimal maximumTradeSize, IRequiredOrderMethods orderMethods) { _security = security; _symbol = _security.Symbol; EnterSignal = enterSignal; ExitSignal = exitSignal; _risk = risk; _maximumTradeSize = maximumTradeSize; _orderMethods = orderMethods; _tradeProfiles = new List<TradeProfile>(); } /// <summary> /// Scan /// </summary> /// <param name="data"></param> public void Scan(TradeBar data) { UpdateCurrentPrice(data); MarkStopTicketsFilled(); EnterTradeSignal(data); ExitTradeSignal(data); RemoveAllFinishedTrades(); } /// <summary> /// Executes all the logic when the Enter Signal is triggered /// </summary> /// <param name="data"></param> public void EnterTradeSignal(TradeBar data) { EnterSignal.Scan(data); if (EnterSignal.Signal == SignalType.Long || EnterSignal.Signal == SignalType.Short) { //Creates a new trade profile once it enters a trade var profile = new TradeProfile(_symbol, _security.VolatilityModel.Volatility, _risk, data.Close, _maximumTradeSize); //Creates a new instance of the exit signal profile.ExitSignal = ExitSignal.ExitSignalFactory(profile); var profileQuantity = profile.Quantity; if (profileQuantity <= 0) return; profile.OpenTicket = _orderMethods.MarketOrder(_symbol, (int)EnterSignal.Signal * profile.Quantity); profile.StopTicket = _orderMethods.StopMarketOrder(_symbol, -(int)EnterSignal.Signal * profile.Quantity, profile.OpenTicket.AverageFillPrice - (int)EnterSignal.Signal * profile.DeltaStopLoss); _tradeProfiles.Add(profile); } } /// <summary> /// Executes all the logic when the Exit Signal is triggered /// </summary> /// <param name="data"></param> public void ExitTradeSignal(TradeBar data) { foreach (var tradeProfile in _tradeProfiles.Where(x => x.IsTradeFinished == false)) { tradeProfile.ExitSignal.Scan(data); if (tradeProfile.ExitSignal.Signal == SignalType.Exit) { if (tradeProfile.StopTicket.Status != OrderStatus.Filled) { tradeProfile.ExitTicket = _orderMethods.MarketOrder(_symbol, -(int)tradeProfile.OpenTicket.QuantityFilled); tradeProfile.StopTicket.Cancel(); tradeProfile.IsTradeFinished = true; } } } } /// <summary> /// Marks all the trades as finished which are completed due to hitting the stop loss /// </summary> public void MarkStopTicketsFilled() { foreach (var tradeProfile in _tradeProfiles) { if (tradeProfile.StopTicket.Status == OrderStatus.Filled) { tradeProfile.IsTradeFinished = true; } } } /// <summary> /// Removes all the completed trades from the trade profile list /// </summary> public void RemoveAllFinishedTrades() { _tradeProfiles = _tradeProfiles.Where(x => !x.IsTradeFinished).ToList(); } /// <summary> /// Update the current price of the asset /// </summary> /// <param name="data"></param> public void UpdateCurrentPrice(TradeBar data) { foreach (var tradeProfile in _tradeProfiles) { tradeProfile.CurrentPrice = data.Close; } } } }
using QuantConnect.Data.Market; namespace QuantConnect.Algorithm.CSharp { class OneShotTrigger : ISignal { private readonly ISignal _signal; private SignalType _previousSignalType; /// <summary> /// Initializes our one shot trigger /// </summary> /// <param name="signal"></param> public OneShotTrigger(ISignal signal) { _signal = signal; Signal = SignalType.NoSignal; _previousSignalType = SignalType.NoSignal; } /// <summary> /// Scans if the trigger is hit /// </summary> /// <param name="data"></param> public void Scan(TradeBar data) { _signal.Scan(data); if(_signal.Signal != _previousSignalType) { Signal = _signal.Signal; } else { Signal = SignalType.NoSignal; } _previousSignalType = _signal.Signal; } public SignalType Signal { get; private set; } } }
/* * QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals. * Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ using QuantConnect.Data; using QuantConnect.Indicators; namespace QuantConnect.Securities { /// <summary> /// Provides an implementation of <see cref="IVolatilityModel"/> that computes the /// relative standard deviation as the volatility of the security /// </summary> public class ThreeSigmaVolatilityModel : IVolatilityModel { private readonly StandardDeviation _standardDeviation; /// <summary> /// Gets the volatility of the security /// </summary> public decimal Volatility { get { return _standardDeviation*2.5m; } } /// <summary> /// Initializes an instance of the standard deviation /// </summary> /// <param name="standardDeviation"></param> public ThreeSigmaVolatilityModel(StandardDeviation standardDeviation) { _standardDeviation = standardDeviation; } /// <summary> /// Updates this model using the new price information in /// the specified security instance /// </summary> /// <param name="security">The security to calculate volatility for</param> /// <param name="data"></param> public void Update(Security security, BaseData data) {} } }
using QuantConnect.Data.Market; namespace QuantConnect.Algorithm.CSharp { /// <summary> /// Base Signal Interface /// </summary> public interface ISignal { void Scan(TradeBar data); SignalType Signal { get; } } /// <summary> /// Exit Signal for the trade /// </summary> public interface IExitSignal : ISignal { ISignal ExitSignalFactory(TradeProfile tradeProfile); } /// <summary> /// Indicates the type of signal /// </summary> public enum SignalType { Long = 1, Short = -1, Exit = 2, NoSignal = 0 } }
using QuantConnect.Data.Market; using QuantConnect.Indicators; using QuantConnect.Securities; namespace QuantConnect.Algorithm.CSharp { class ProfitTargetSignalExit : IExitSignal { private readonly TradeProfile _tradeProfile; private readonly decimal _targetProfitLossRatio; public ProfitTargetSignalExit() { } /// <summary> /// Initializes the profit target indicator for the exits /// </summary> /// <param name="tradeProfile"></param> /// <param name="targetProfitLossRatio"></param> public ProfitTargetSignalExit(TradeProfile tradeProfile, decimal targetProfitLossRatio) { _tradeProfile = tradeProfile; _targetProfitLossRatio = targetProfitLossRatio; } /// <summary> /// Scans if the current profit ratio goes above the target ratio /// </summary> /// <param name="data"></param> public void Scan(TradeBar data) { if (_tradeProfile.ProfitLossRatio > _targetProfitLossRatio) { Signal = SignalType.Exit; } else { Signal = SignalType.NoSignal; } } public SignalType Signal { get; private set; } /// <summary> /// Create a new instance of our exit signal /// </summary> /// <param name="tradeProfile"></param> /// <returns></returns> public ISignal ExitSignalFactory(TradeProfile tradeProfile) { return new ProfitTargetSignalExit(tradeProfile, _targetProfitLossRatio); } } }