Overall Statistics |
Total Trades 988 Average Win 0.02% Average Loss -0.02% Compounding Annual Return -0.843% Drawdown 1.100% Expectancy -0.092 Net Profit -0.844% Sharpe Ratio -0.988 Loss Rate 57% Win Rate 43% Profit-Loss Ratio 1.09 Alpha -0.006 Beta -0.005 Annual Standard Deviation 0.006 Annual Variance 0 Information Ratio -0.068 Tracking Error 0.132 Treynor Ratio 1.129 Total Fees $0.00 |
using QuantConnect.Data.Market; namespace QuantConnect.Algorithm.CSharp { /// <summary> /// Base Signal Interface /// </summary> public interface ISignal { void Scan(TradeBar data); int Signal { get; } } }
using System.Collections.Generic; using System.Linq; using QuantConnect.Data.Market; using QuantConnect.Orders; using QuantConnect.Securities; namespace QuantConnect.Algorithm.CSharp { class TradingAsset { public ISignal ExitSignal; public ISignal EnterSignal; private decimal _risk; private Symbol _symbol; private Security _security; private decimal _maximumTradeSize; private List<TradeProfile> _tradeProfiles; private 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, ISignal 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) { 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 != 0) { //Creates a new trade profile once it enters a trade var profile = new TradeProfile(_symbol, _security.VolatilityModel.Volatility, _risk, data.Close, _maximumTradeSize, ExitSignal); profile.OpenTicket = _orderMethods.MarketOrder(_symbol, EnterSignal.Signal * profile.Quantity); profile.StopTicket = _orderMethods.StopMarketOrder(_symbol, -EnterSignal.Signal * profile.Quantity, profile.OpenTicket.AverageFillPrice - 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 != 0) { 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(); } } }
using System; using QuantConnect.Data.Market; using QuantConnect.Orders; namespace QuantConnect.Algorithm.CSharp { /// <summary> /// This Time Signal Enters the trade at a particular time and exits the trade at a particular time set for the entery and exit /// </summary> public class TimeSignal : ISignal { private Random random = new Random(131); private TimeSpan _timeOfDay; public TimeSignal(TimeSpan timeOfDay) { _timeOfDay = timeOfDay; } /// <summary> /// Scans the new data coming in and randomly assigns direction if entry conditions are met /// </summary> /// <param name="data"></param> public void Scan(TradeBar data) { if (data.Time.TimeOfDay == _timeOfDay) { Signal = (RandomOrderDirection() == OrderDirection.Buy) ? 1 : -1; } else { Signal = 0; } } /// <summary> /// Signal value for the binary signal /// </summary> public int Signal { get; private set; } /// <summary> /// Produces a random direction for the signal to trade /// </summary> /// <returns></returns> private OrderDirection RandomOrderDirection() { if (random.NextDouble() > 0.5) return OrderDirection.Buy; return OrderDirection.Sell; } } }
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 decimal CurrentPrice; public int TradeDirection; public Symbol TradeSymbol; private bool isTradeFinished; private decimal _risk; private int _maximumTradeQuantity; protected decimal _volatility; // Calclate the quantity based on the target risk in dollars. public int Quantity { get { long quantity = (long)(_risk / _volatility); if (quantity > _maximumTradeQuantity) return _maximumTradeQuantity; return (int)quantity; } } //What is the stoploss move from current price public decimal DeltaStopLoss { get { 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 { return isTradeFinished; } set { isTradeFinished = value; } } /// <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, ISignal exitSignal) { TradeSymbol = symbol; _volatility = volatility; _risk = risk; CurrentPrice = currentPrice; _maximumTradeQuantity = (int)(maximumTradeSize / CurrentPrice); ExitSignal = exitSignal; } } }
/* * 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.Data.Market; 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", "GBPUSD"}; //Risk in dollars per trade ($ or the quote currency of the assets) public decimal RiskPerTrade = 10; //Sets the profit to loss ratio we want to hit before we exit public decimal TargetProfitLossRatio = 0.05m; //Roughly how long does our "alpha" take to run public TimeSpan AverageInvestmentPeriod = TimeSpan.FromHours(6.5); //Cap the investment maximum size ($). public decimal MaximumTradeSize = 10000; private Resolution _dataResolution = Resolution.Minute; private Dictionary<Symbol, TradingAsset> _tradingAssets; public override void Initialize() { SetStartDate(2015, 1, 1); SetEndDate(2016, 01, 01); SetCash(25000); _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.0m); //SetBrokerageModel(BrokerageName.FxcmBrokerage); Securities[symbol].VolatilityModel = new ThreeSigmaVolatilityModel(_dataResolution.ToTimeSpan(), (int)AverageInvestmentPeriod.TotalMinutes); _tradingAssets.Add(symbol, new TradingAsset(Securities[symbol], new TimeSignal(TimeSpan.FromHours(9.5)), new TimeSignal(TimeSpan.FromHours(16)), RiskPerTrade, MaximumTradeSize, this )); } } /// <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) { foreach (var symbol in Symbols) { //Create a trading asset package for each symbol _tradingAssets[symbol].Scan(data[symbol]); } } } /// <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 = ""); } }
/* * 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 MathNet.Numerics.Statistics; 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 bool _needsUpdate; private decimal _volatility; private DateTime _lastUpdate; private readonly TimeSpan _periodSpan; private readonly object _sync = new object(); private readonly RollingWindow<double> _window; /// <summary> /// Gets the volatility of the security as a percentage /// </summary> public decimal Volatility { get { lock (_sync) { if (_window.Count < 2) { return 0m; } if (_needsUpdate) { _needsUpdate = false; // volatility here is supposed to be a percentage var std = _window.StandardDeviation().SafeDecimalCast(); _volatility = std * 3; } } return _volatility; } } /// <summary> /// Initializes a new instance of the <see cref="QuantConnect.Securities.RelativeStandardDeviationVolatilityModel"/> class /// </summary> /// <param name="periodSpan">The time span representing one 'period' length</param> /// <param name="periods">The nuber of 'period' lengths to wait until updating the value</param> public ThreeSigmaVolatilityModel(TimeSpan periodSpan, int periods) { if (periods < 2) throw new ArgumentOutOfRangeException("periods", "'periods' must be greater than or equal to 2."); _periodSpan = periodSpan; _window = new RollingWindow<double>(periods); _lastUpdate = DateTime.MinValue + TimeSpan.FromMilliseconds(periodSpan.TotalMilliseconds * periods); } /// <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) { var timeSinceLastUpdate = data.EndTime - _lastUpdate; if (timeSinceLastUpdate >= _periodSpan) { lock (_sync) { _needsUpdate = true; // we purposefully use security.Price for consistency in our reporting // some streams of data will have trade/quote data, so if we just use // data.Value we could be mixing and matching data streams _window.Add((double)security.Price); } _lastUpdate = data.EndTime; } } } }