| 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);
}
}
}