Overall Statistics |
Total Trades 6666 Average Win 0.02% Average Loss -0.02% Compounding Annual Return -99.980% Drawdown 40.700% Expectancy -0.627 Net Profit -40.660% Sharpe Ratio -25.099 Loss Rate 81% Win Rate 19% Profit-Loss Ratio 0.97 Alpha -5.611 Beta -0.498 Annual Standard Deviation 0.224 Annual Variance 0.05 Information Ratio -24.094 Tracking Error 0.235 Treynor Ratio 11.312 Total Fees $0.00 |
namespace QuantConnect { public class TradingSymbols { public static string[] OandaFXSymbols = { "AUDCAD","AUDCHF","AUDHKD","AUDJPY","AUDNZD","AUDSGD","AUDUSD","CADCHF","CADHKD","CADJPY", "CADSGD","CHFHKD","CHFJPY","CHFZAR","EURAUD","EURCAD","EURCHF","EURCZK","EURDKK","EURGBP", "EURHKD","EURHUF","EURJPY","EURNOK","EURNZD","EURPLN","EURSEK","EURSGD","EURTRY","EURUSD", "EURZAR","GBPAUD","GBPCAD","GBPCHF","GBPHKD","GBPJPY","GBPNZD","GBPPLN","GBPSGD","GBPUSD", "GBPZAR","HKDJPY","NZDCAD","NZDCHF","NZDHKD","NZDJPY","NZDSGD","NZDUSD","SGDCHF","SGDHKD", "SGDJPY","TRYJPY","USDCAD","USDCHF","USDCNH","USDCZK","USDDKK","USDHKD","USDHUF","USDINR", "USDJPY","USDMXN","USDNOK","USDPLN","USDSAR","USDSEK","USDSGD","USDTHB","USDTRY","USDZAR", "ZARJPY" }; public static string[] OandaFXMajors2 = { "AUDJPY","AUDUSD","EURAUD","EURCHF","EURGBP","EURJPY","EURUSD","GBPCHF","GBPJPY","GBPUSD", "NZDUSD","USDCAD","USDCHF","USDJPY" }; public static string[] OandaFXMajors1 = { "EURCHF","EURGBP","EURJPY","EURUSD","GBPCHF","GBPJPY","GBPUSD","USDCHF","USDJPY" }; public static string[] OandaFXMajors = { "EURCHF","EURGBP","EURJPY","EURUSD" }; public static string[] OandaCFD = { "EU50EUR", "FR40EUR", "DE30EUR" }; public static string[] OandaFXMajors0 = { "EURUSD" }; } }
using System; using System.Collections.Generic; namespace QuantConnect { public class SignalFactory : AbstractSignalFactory { //todo: derive maximum signals from config keys private readonly int _maximumSignals = 5; int _period; int _slowPeriod; int _fastPeriod; int _signalPeriod; QCAlgorithm _algorithm; Resolution _resolution; private bool _enableParameterLog = false; public enum TechnicalIndicator { None = -1, SimpleMovingAverage = 0, MovingAverageConvergenceDivergence = 1, Stochastic = 2, RelativeStrengthIndex = 3, CommodityChannelIndex = 4, MomentumPercent = 5, WilliamsPercentR = 6, PercentagePriceOscillator = 7, AverageDirectionalIndex = 8, AverageTrueRange = 9, BollingerBands = 10, ExponentialMovingAverage = 11 } public override Rule Create(QCAlgorithm algorithm, Symbol symbol, bool isEntryRule, Resolution resolution = Resolution.Hour) { _algorithm = algorithm; _resolution = resolution; var entryOrExit = isEntryRule ? "Entry" : "Exit"; _period = GetConfigValue("period"); _slowPeriod = GetConfigValue("slowPeriod"); _fastPeriod = GetConfigValue("fastPeriod"); _signalPeriod = GetConfigValue("signalPeriod"); ISignal parent = null; List<ISignal> list = new List<ISignal>(); for (var i = 1; i <= _maximumSignals; i++) { var item = CreateIndicator(symbol, i, entryOrExit); if (parent != null) { parent.Child = item; } //last item won't have operator if (i < _maximumSignals) { var key = entryOrExit + "Operator" + i; Operator op = (Operator)GetConfigValue(key); item.Operator = op; } item.Parent = parent; parent = item; list.Add(item); } return new Rule(symbol, list); } protected override ISignal CreateIndicator(Symbol pair, int i, string entryOrExit) { var key = entryOrExit + "Indicator" + i + "Direction"; var intDirection = GetConfigValue(key); var direction = intDirection == 0 ? Direction.LongOnly : Direction.ShortOnly; key = entryOrExit + "Indicator" + i; var indicator = (TechnicalIndicator)GetConfigValue(key); ISignal signal = null; switch (indicator) { case TechnicalIndicator.SimpleMovingAverage: var fast = _algorithm.SMA(pair, _fastPeriod, _resolution); var slow = _algorithm.SMA(pair, _slowPeriod, _resolution); signal = new CrossingMovingAverageSignal(fast, slow, direction); break; case TechnicalIndicator.ExponentialMovingAverage: // Canonical cross moving average parameters. var fastema = _algorithm.EMA(pair, period: 50); var slowema = _algorithm.EMA(pair, period: 200); signal = new CrossingMovingAverageSignal(fastema, slowema, direction); break; case TechnicalIndicator.MovingAverageConvergenceDivergence: var macd = _algorithm.MACD(pair, fastPeriod: 12, slowPeriod: 26, signalPeriod: 9, type:MovingAverageType.Simple, resolution:_resolution); signal = new CrossingMovingAverageSignal(macd, macd.Signal, direction); break; case TechnicalIndicator.Stochastic: var sto = _algorithm.STO(pair, period: 14, resolution:_resolution); signal = new OscillatorSignal(sto, new[] { 20, 80 }, direction); break; case TechnicalIndicator.RelativeStrengthIndex: var rsi = _algorithm.RSI(pair, period: 14); signal = new OscillatorSignal(rsi, new[] { 30, 70 }, direction); break; case TechnicalIndicator.CommodityChannelIndex: var cci = _algorithm.CCI(pair, period: 20, movingAverageType:MovingAverageType.Simple, resolution:_resolution); signal = new OscillatorSignal(cci, new[] { -100, 100 }, direction); break; case TechnicalIndicator.MomentumPercent: var pm = _algorithm.MOMP(pair, period: 60, resolution:_resolution); signal = new OscillatorSignal(pm, new[] { -5, 5 }, direction); break; case TechnicalIndicator.WilliamsPercentR: var wr = _algorithm.WILR(pair, period: 14, resolution:_resolution); signal = new OscillatorSignal(wr, new[] { -20, -80 }, direction); break; case TechnicalIndicator.PercentagePriceOscillator: var ppo = _algorithm.MACD(pair, fastPeriod: 12, slowPeriod: 26, signalPeriod: 9, type: MovingAverageType.Simple, resolution: _resolution) .Over(_algorithm.EMA(pair, _period, resolution: _resolution)).Plus(constant: 100m); var compound = new SimpleMovingAverage(_period).Of(ppo); signal = new CrossingMovingAverageSignal(ppo, compound, direction); break; case TechnicalIndicator.None: signal = new EmptySignal(); break; case TechnicalIndicator.AverageDirectionalIndex: var adx = _algorithm.ADX(pair, _period, _resolution); signal = new OscillatorSignal(adx, new[] { 25, 25 }, direction); break; //todo: //case TechnicalIndicator.AverageTrueRange: // var atr = _algorithm.ATR(pair, _period, MovingAverageType.Simple, _resolution); // signal = new OscillatorSignal(atr, oscillatorThresholds, direction); // break; case TechnicalIndicator.BollingerBands: var bb = _algorithm.BB(pair, period: 20, k: 2); signal = new BBOscillatorSignal(bb, direction); break; } return signal; } protected override int GetConfigValue(string key) { int value; try { int.TryParse(_algorithm.GetParameter(key), out value); //value = Config.GetInt(key, value); if (_enableParameterLog) { _algorithm.Log(string.Format("Parameter {0} set to {1}", key, value)); } } catch (ArgumentNullException e) { throw new ArgumentNullException(key, "The gene " + key + " is not present either as Config or as Parameter"); } return value; } } public abstract class AbstractSignalFactory { public abstract Rule Create(QCAlgorithm algorithm, Symbol symbol, bool isEntryRule, Resolution resolution = Resolution.Hour); protected abstract ISignal CreateIndicator(Symbol pair, int i, string entryOrExit); protected abstract int GetConfigValue(string key); } }
namespace QuantConnect { public class Rule { public IEnumerable<ISignal> List { get; } public Symbol Symbol { get; } public Rule(Symbol symbol, IEnumerable<ISignal> signal) { List = signal; Symbol = symbol; } public bool IsReady() { return List.All(s => s.IsReady); } public bool IsTrue() { string expression = ""; foreach (var item in List) { string isTrue = item.IsTrue().ToString().ToLower(); if (new[] { Operator.NorInclusive, Operator.OrInclusive }.Contains(item.Operator)) { isTrue = "(" + isTrue; } if (item.Parent != null && new[] { Operator.NorInclusive, Operator.OrInclusive }.Contains(item.Parent.Operator)) { isTrue += ")"; } expression = expression+(isTrue); if (item.Child != null) { if (item.Operator == Operator.And) { expression = expression +(" and "); } else if (new[] { Operator.Or, Operator.OrInclusive }.Contains(item.Operator)) { expression = expression +(" or "); } else if (item.Operator == Operator.Not) { expression = expression +(" and !"); } else if (new[] { Operator.Nor, Operator.NorInclusive }.Contains(item.Operator)) { expression = expression +(" or !"); } } } var tokens = new Tokenizer(expression.ToString()).Tokenize(); var parser = new Parser(tokens); return parser.Parse(); } public void Update(BaseData data) { List.First().Update(data); } } }
namespace QuantConnect { public partial class GeneticTreeAlgorithmExample : QCAlgorithm { private readonly bool IsOutOfSampleRun = true; private readonly int oosPeriod = 3; public bool verbose = false; private List<Rule> _entry; private List<Rule> _exit; public List<Symbol> _symbols; FxRiskManagment RiskManager; public override void Initialize() { SetCash(10000); SetStartDate(Configuration.GetConfigDateTime("startDate", new DateTime(2017, 1, 12), this)); //SetEndDate(Config.GetValue<DateTime>("endDate", new DateTime(2017, 7, 22))); if (IsOutOfSampleRun) { //var startDate = new DateTime(year: 2016, month: 1, day: 1); //SetStartDate(startDate); //SetEndDate(startDate.AddMonths(oosPeriod)); RuntimeStatistics["ID"] = GetParameter("ID"); SetParameters(config.ToDictionary(k => k.Key, v => v.Value.ToString())); } SetBrokerageModel(QuantConnect.Brokerages.BrokerageName.OandaBrokerage); var con = new TickConsolidator(new TimeSpan(1, 0, 0)); // SetBenchmark(_symbol); _symbols = new List<Symbol>(); _entry = new List<Rule>(); _exit = new List<Rule>(); foreach (var symbol in TradingSymbols.OandaFXMajors) { var security= AddSecurity(SecurityType.Forex, symbol, Configuration._resolution, Market.Oanda, true, Configuration._leverage, false); _symbols.Add(security.Symbol); } foreach (var symbol in TradingSymbols.OandaCFD) { // AddSecurity(SecurityType.Cfd, symbol, _resolution, Market.Oanda, true, _leverage, false); } var factory = new SignalFactory(); foreach (var symbol in _symbols) { Securities[symbol].VolatilityModel = new ThreeSigmaVolatilityModel(STD(symbol: symbol, period: 12 * 60, resolution: Configuration._resolution), 20.0m); _entry.Add(factory.Create(this, symbol, true, Configuration._resolution)); _exit.Add(factory.Create(this, symbol, false, Configuration._resolution)); } RiskManager = new FxRiskManagment(Portfolio, Configuration._riskPerTrade, Configuration._maxExposurePerTrade, Configuration._maxExposure, Configuration._lotSize); } public void OnData(QuoteBars data) { foreach (var entry in _entry) { if (entry.IsReady()) { EntrySignal(data, entry); } } foreach (var entry in _exit) { if (entry.IsReady()) { ExitSignal(entry); } } } public void ExitSignal(Rule signal) { if (verbose && signal.IsTrue()) { Log(string.Format("signal symbol:: {0}", signal.Symbol)); } if (Portfolio[signal.Symbol].Invested && signal.IsTrue()) { Liquidate(signal.Symbol); } else if (Portfolio[signal.Symbol].Invested && Portfolio[signal.Symbol].UnrealizedProfitPercent > Configuration.takeProfit) { //safeguard profits, //liquidate half MarketOrder(signal.Symbol, -(Portfolio[signal.Symbol].Quantity / 2)); } } public void EntrySignal(QuoteBars data, Rule signal) { if (verbose && signal.IsTrue()) { Log(string.Format("signal symbol:: {0}", signal.Symbol)); } if (!Portfolio[signal.Symbol].Invested) { if (signal.IsTrue()) { var openPrice = Securities[signal.Symbol].Price; var entryValues = RiskManager.CalculateEntryOrders(data, signal.Symbol, AgentAction.GoLong); if (entryValues.Item1 != 0) { var ticket = MarketOrder(signal.Symbol, entryValues.Item1); StopMarketOrder(signal.Symbol, -entryValues.Item1, entryValues.Item2, tag: entryValues.Item3.ToString("0.000000")); if (verbose) { Log(string.Format("MarketOrder:: {0} {1}", signal.Symbol, entryValues.Item1)); } } //MarketOrder(signal.Symbol, size, false, ""); } } } private static Dictionary<string, int> config = new Dictionary<string, int> { {"EntryIndicator1", 0}, {"EntryIndicator2", 10}, {"EntryIndicator3", 0}, {"EntryIndicator4", 2}, {"EntryIndicator5", 3}, {"EntryIndicator1Direction", 1}, {"EntryIndicator2Direction", 1}, {"EntryIndicator3Direction", 1}, {"EntryIndicator4Direction", 1}, {"EntryIndicator5Direction", 1}, {"EntryOperator1", 1}, {"EntryOperator2", 1}, {"EntryOperator3", 1}, {"EntryOperator4", 1}, {"EntryRelationship1", 0}, {"EntryRelationship2", 1}, {"EntryRelationship3", 1}, {"EntryRelationship4", 0}, {"ExitIndicator1", 6}, {"ExitIndicator2", 5}, {"ExitIndicator3", 4}, {"ExitIndicator4", 0}, {"ExitIndicator5", 2}, {"ExitIndicator1Direction", 0}, {"ExitIndicator2Direction", 0}, {"ExitIndicator3Direction", 0}, {"ExitIndicator4Direction", 0}, {"ExitIndicator5Direction", 0}, {"ExitOperator1", 1}, {"ExitOperator2", 1}, {"ExitOperator3", 1}, {"ExitOperator4", 1}, {"ExitRelationship1", 0}, {"ExitRelationship2", 1}, {"ExitRelationship3", 0}, {"ExitRelationship4", 1}, {"period", 1}, {"slowPeriod", 200}, {"fastPeriod", 20}, {"signalPeriod", 4 } }; } }
namespace QuantConnect { public class Configuration { public static decimal _leverage = 50m; // How much of the total strategy equity can be at risk as maximum in all trades. public static decimal _maxExposure = 0.8m; // How much of the total strategy equity can be at risk in a single trade. public static decimal _maxExposurePerTrade = 0.25m; // The max strategy equity proportion to put at risk in a single operation. public static decimal _riskPerTrade = 0.01m; public static decimal takeProfit = 0.05m; public static Resolution _resolution = Resolution.Minute; public static double accountsize = 10000; // Smallest lot public static LotSize _lotSize = LotSize.Nano; /// <summary> /// Gets the gene int from key. /// </summary> /// <param name="key">The key.</param> /// <returns></returns> /// <exception cref="System.ArgumentNullException">The gene " + key + " is not present either as Config or as Parameter</exception> /// <remarks> /// This method makes the algorithm working with the genes defined from the Config (as in the Lean Optimization) and /// from the Parameters (as the Lean Caller). /// </remarks> public static decimal GetConfigDecimal(string key, decimal def, QCAlgorithm algo) { // I'll keep this line as in the original code. //var gene = Config.GetValue<decimal>(key); var gene = decimal.MinValue; if (gene == decimal.MinValue)//not found in config, then get from parameter { try { gene = decimal.Parse(algo.GetParameter(key)); } #pragma warning disable CS0168 // Variable is declared but never used catch (ArgumentNullException e) #pragma warning restore CS0168 // Variable is declared but never used { return def; } } return gene; } /// <summary> /// Gets the gene int from key. /// </summary> /// <param name="key">The key.</param> /// <returns></returns> /// <exception cref="System.ArgumentNullException">The gene " + key + " is not present either as Config or as Parameter</exception> /// <remarks> /// This method makes the algorithm working with the genes defined from the Config (as in the Lean Optimization) and /// from the Parameters (as the Lean Caller). /// </remarks> public static DateTime GetConfigDateTime(string key, DateTime def, QCAlgorithm algo) { // I'll keep this line as in the original code. //var gene = Config.GetValue<DateTime>(key, null); var gene = DateTime.MinValue; if (gene == DateTime.MinValue)//not found in config, then get from parameter { try { gene = DateTime.Parse(algo.GetParameter(key)); } #pragma warning disable CS0168 // Variable is declared but never used catch (ArgumentNullException e) #pragma warning restore CS0168 // Variable is declared but never used { return def; } } return gene; } } }
namespace QuantConnect { public abstract class SignalBase : ISignal { public ISignal Child { get; set; } public ISignal Parent { get; set; } public Operator Operator { get; set; } public abstract bool IsReady { get; } public abstract string Name { get; } public abstract bool IsTrue(); public virtual void Update(BaseData data) { if (Child != null) { Child.Update(data); } } } }
namespace QuantConnect { /// <summary> /// This class keeps track of an oscillator respect to its thresholds and updates an <see cref="OscillatorSignal" /> /// for each given state. /// </summary> /// <seealso cref="QuantConnect.Algorithm.CSharp.ITechnicalIndicatorSignal" /> public class OscillatorSignal : SignalBase { private decimal _previousIndicatorValue; private ThresholdState _previousSignal; private int[] _thresholds; private Direction _direction; static int[] defaultThresholds = new int[2] { 20, 80 }; /// <summary> /// Possibles states of an oscillator respect to its thresholds. /// </summary> public enum ThresholdState { CrossLowerFromAbove = -3, BelowLower = -2, CrossLowerFromBelow = -1, InBetween = 0, CrossUpperFromBelow = 3, AboveUpper = 2, CrossUpperFromAbove = 1 } /// <summary> /// Initializes a new instance of the <see cref="OscillatorSignal" /> class. /// </summary> /// <param name="indicator">The indicator.</param> /// <param name="thresholds">The thresholds.</param> /// <param name="direction"> /// The trade rule direction. Only used if the instance will be part of a /// <see cref="Rule" /> class /// </param> /// <remarks>The oscillator must be registered BEFORE being used by this constructor.</remarks> public OscillatorSignal(dynamic indicator, int[] thresholds, Direction direction) { Initialize(indicator, thresholds, direction); } /// <summary> /// Initializes a new instance of the <see cref="OscillatorSignal" /> class. /// </summary> /// <param name="indicator">The indicator.</param> /// <param name="thresholds">The thresholds.</param> /// <remarks>The oscillator must be registered BEFORE being used by this constructor.</remarks> public OscillatorSignal(dynamic indicator, int[] thresholds) { Initialize(indicator, thresholds, Direction.LongOnly); } public OscillatorSignal(dynamic indicator, Direction direction) { Initialize(indicator, defaultThresholds, direction); } /// <summary> /// Initializes a new instance of the <see cref="OscillatorSignal" /> class. /// </summary> /// <param name="indicator">The indicator.</param> /// <remarks>The oscillator must be registered BEFORE being used by this constructor.</remarks> public OscillatorSignal(dynamic indicator) { Initialize(indicator, defaultThresholds, Direction.LongOnly); } /// <summary> /// The underlying indicator, must be an oscillator. /// </summary> public dynamic Indicator { get; private set; } /// <summary> /// Gets the actual state of the oscillator. /// </summary> public ThresholdState Signal { get; private set; } /// <summary> /// Gets a value indicating whether this instance is ready. /// </summary> /// <value> /// <c>true</c> if this instance is ready; otherwise, <c>false</c>. /// </value> public override bool IsReady { get { return Indicator.IsReady; } } public override string Name { get { return ((string)Indicator.GetType().ToString()).Split('.').Last(); } } /// <summary> /// Gets the signal. Only used if the instance will be part of a <see cref="Rule" /> class. /// </summary> /// <returns> /// <c>true</c> if the actual <see cref="Signal" /> correspond with the instance <see cref="Direction" />. /// <c>false</c> /// otherwise. /// </returns> public override bool IsTrue() { var signal = false; if (IsReady) { switch (_direction) { case Direction.LongOnly: signal = Signal == ThresholdState.CrossLowerFromBelow; break; case Direction.ShortOnly: signal = Signal == ThresholdState.CrossUpperFromAbove; break; } } return signal; } /// <summary> /// Updates the <see cref="Signal" /> status. /// </summary> private void Indicator_Updated(object sender, IndicatorDataPoint updated) { var actualPositionSignal = GetThresholdState(updated); if (!Indicator.IsReady) { _previousIndicatorValue = updated.Value; _previousSignal = actualPositionSignal; Signal = _previousSignal; return; } var actualSignal = GetActualSignal(_previousSignal, actualPositionSignal); Signal = actualSignal; _previousIndicatorValue = updated.Value; _previousSignal = actualSignal; } /// <summary> /// Gets the actual position respect to the thresholds. /// </summary> /// <param name="indicatorCurrentValue">The indicator current value.</param> /// <returns></returns> protected virtual ThresholdState GetThresholdState(decimal indicatorCurrentValue) { var positionSignal = ThresholdState.InBetween; if (indicatorCurrentValue > _thresholds[1]) { positionSignal = ThresholdState.AboveUpper; } else if (indicatorCurrentValue < _thresholds[0]) { positionSignal = ThresholdState.BelowLower; } return positionSignal; } /// <summary> /// Gets the actual signal from the actual position respect to the thresholds and the last signal. /// </summary> /// <param name="previousSignal">The previous signal.</param> /// <param name="actualPositionSignal">The actual position signal.</param> /// <returns></returns> private ThresholdState GetActualSignal(ThresholdState previousSignal, ThresholdState actualPositionSignal) { ThresholdState actualSignal; var previous = (int)previousSignal; var current = (int)actualPositionSignal; if (current == 0) { if (Math.Abs(previous) > 1) { actualSignal = (ThresholdState)Math.Sign(previous); } else { actualSignal = ThresholdState.InBetween; } } else { if (previous * current <= 0 || Math.Abs(previous + current) == 3) { actualSignal = (ThresholdState)(Math.Sign(current) * 3); } else { actualSignal = (ThresholdState)(Math.Sign(current) * 2); } } return actualSignal; } /// <summary> /// Sets up class. /// </summary> /// <param name="indicator">The indicator.</param> /// <param name="thresholds">The thresholds.</param> /// <param name="direction">The trade rule direction.</param> private void Initialize(dynamic indicator, int[] thresholds, Direction direction) { _thresholds = thresholds; Indicator = indicator; indicator.Updated += new IndicatorUpdatedHandler(Indicator_Updated); _direction = direction; } /// <summary> /// Exposes a means to update underlying indicator /// </summary> /// <param name="data"></param> public override void Update(BaseData data) { if (Indicator.GetType().IsSubclassOf(typeof(IndicatorBase<IBaseDataBar>))) { if (data.GetType().GetInterfaces().Contains(typeof(IBaseDataBar))) { Indicator.Update((IBaseDataBar)data); } } else if (Indicator.GetType().IsSubclassOf(typeof(IndicatorBase<IndicatorDataPoint>))) { Indicator.Update(new IndicatorDataPoint(data.Time, data.Value)); } else { Indicator.Update(data); } base.Update(data); } } }
namespace QuantConnect { public interface ISignal { /// <summary> /// Gets a value indicating whether this instance is ready. /// </summary> /// <value> /// <c>true</c> if this instance is ready; otherwise, <c>false</c>. /// </value> bool IsReady { get; } bool IsTrue(); ISignal Child { get; set; } ISignal Parent { get; set; } Operator Operator { get; set; } void Update(BaseData data); string Name { get; } } public enum Direction { LongOnly = 1, ShortOnly = -1 } public enum Operator { And = 0, Or = 1, OrInclusive = 2, Not = 3, Nor = 4, NorInclusive = 5 } }
namespace QuantConnect { public class EmptySignal : ISignal { public bool _isTrue = true; public EmptySignal(bool isTrue = true) { _isTrue = isTrue; } public bool IsReady { get { return true; } } public Operator Operator { get; set; } public ISignal Child { get; set; } public ISignal Parent { get; set; } public string Name { get { return "Empty"; } } public bool IsTrue() { return _isTrue; } public void Update(BaseData data) { } } }
namespace QuantConnect { /// <summary> /// Possibles states of two moving averages. /// </summary> public enum CrossingMovingAveragesSignals { Bullish = 1, FastCrossSlowFromAbove = -2, Bearish = -1, FastCrossSlowFromBelow = 2 } /// <summary> /// This class keeps track of two crossing moving averages and updates a <see cref="CrossingMovingAveragesSignals" /> /// for each given state. /// </summary> public class CrossingMovingAverageSignal : SignalBase { private readonly CompositeIndicator<IndicatorDataPoint> _moving_average_difference; private readonly Direction _direction; private int _lastSignal; IndicatorBase<IndicatorDataPoint> _fast { get; set; } IndicatorBase<IndicatorDataPoint> _slow { get; set; } //todo: name public override string Name { get { return "CrossingMovingAverageSignal"; } } /// <summary> /// Initializes a new instance of the <see cref="CrossingMovingAverageSignal" /> class. /// </summary> /// <param name="fast">The fast moving average.</param> /// <param name="slow">The slow moving average.</param> /// <param name="direction"> /// The trade rule direction. Only used if the instance will be part of a /// <see cref="Rule" /> class /// </param> /// <remarks> /// Both Moving Averages must be registered BEFORE being used by this constructor. /// </remarks> public CrossingMovingAverageSignal(IndicatorBase<IndicatorDataPoint> fast, IndicatorBase<IndicatorDataPoint> slow, Direction direction) { _fast = fast; _slow = slow; _moving_average_difference = fast.Minus(slow); _moving_average_difference.Updated += ma_Updated; _direction = direction; } /// <summary> /// Gets the actual state of both moving averages. /// </summary> public CrossingMovingAveragesSignals Signal { get; private set; } /// <summary> /// Gets a value indicating whether this instance is ready. /// </summary> /// <value> /// <c>true</c> if this instance is ready; otherwise, <c>false</c>. /// </value> public override bool IsReady { get { return _moving_average_difference.IsReady; } } /// <summary> /// Gets the signal. Only used if the instance will be part of a <see cref="Rule" /> class. /// </summary> /// <returns> /// <c>true</c> if the actual <see cref="Signal" /> correspond with the instance <see cref="Direction" />. /// <c>false</c> /// otherwise. /// </returns> public override bool IsTrue() { var signal = false; if (IsReady) { switch (_direction) { case Direction.LongOnly: signal = Signal == CrossingMovingAveragesSignals.FastCrossSlowFromBelow; break; case Direction.ShortOnly: signal = Signal == CrossingMovingAveragesSignals.FastCrossSlowFromAbove; break; } } return signal; } private void ma_Updated(object sender, IndicatorDataPoint updated) { if (!IsReady) { return; } var actualSignal = Math.Sign(_moving_average_difference); if (actualSignal == _lastSignal || _lastSignal == 0) { Signal = (CrossingMovingAveragesSignals)actualSignal; } else if (_lastSignal == -1 && actualSignal == 1) { Signal = CrossingMovingAveragesSignals.FastCrossSlowFromBelow; } else if (_lastSignal == 1 && actualSignal == -1) { Signal = CrossingMovingAveragesSignals.FastCrossSlowFromAbove; } _lastSignal = actualSignal; } public override void Update(BaseData data) { var point = new IndicatorDataPoint(data.Time, data.Price); AttemptCompositeUpdate(_fast, point); AttemptCompositeUpdate(_slow, point); _fast.Update(point); _slow.Update(point); base.Update(data); } private void AttemptCompositeUpdate(IndicatorBase<IndicatorDataPoint> indicator, IndicatorDataPoint point) { if (indicator.GetType() == typeof(CompositeIndicator<IndicatorDataPoint>)) { var composite = ((CompositeIndicator<IndicatorDataPoint>)indicator); composite.Left.Update(point); composite.Right.Update(point); AttemptCompositeUpdate(composite.Left, point); AttemptCompositeUpdate(composite.Right, point); } } } }
namespace QuantConnect { /// <summary> /// This class keeps track of an oscillator respect to its thresholds and updates an <see cref="BBOscillatorSignal" /> /// for each given state. /// </summary> /// <seealso cref="QuantConnect.Algorithm.CSharp.ITechnicalIndicatorSignal" /> public class BBOscillatorSignal : OscillatorSignal { private BollingerBands _bb; /// <summary> /// Initializes a new instance of the <see cref="BBOscillatorSignal" /> class. /// </summary> /// <param name="indicator">The indicator.</param> /// <remarks>The oscillator must be registered BEFORE being used by this constructor.</remarks> public BBOscillatorSignal(BollingerBands indicator, Direction direction) : base(indicator, direction) { _bb = indicator; } /// <summary> /// Gets the actual position respect to the thresholds. /// </summary> /// <param name="indicatorCurrentValue">The indicator current value.</param> /// <returns></returns> protected override ThresholdState GetThresholdState(decimal indicatorCurrentValue) { var positionSignal = ThresholdState.InBetween; if (indicatorCurrentValue > _bb.UpperBand) { positionSignal = ThresholdState.AboveUpper; } else if (indicatorCurrentValue < _bb.LowerBand) { positionSignal = ThresholdState.BelowLower; } return positionSignal; } } }
namespace QuantConnect { /// <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 TimeSpan _periodSpan; private StandardDeviation _standardDeviation; private decimal _percentage; /// <summary> /// Gets the volatility of the security as a percentage /// </summary> public decimal Volatility { get { return _standardDeviation * _percentage; } } /// <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(StandardDeviation standardDeviation, decimal percentage = 2.5m) { _standardDeviation = standardDeviation; _percentage = percentage; _periodSpan = TimeSpan.FromMinutes(standardDeviation.Period); } /// <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) { } public IEnumerable<HistoryRequest> GetHistoryRequirements(Security security, DateTime utcTime) { return Enumerable.Empty<HistoryRequest>(); } } }
namespace QuantConnect { public enum LotSize { Standard = 100000, Mini = 10000, Micro = 1000, Nano = 100, } public enum AgentAction { GoShort = -1, DoNothing = 0, GoLong = 1 } public class FxRiskManagment { // Maximum equity proportion to put at risk in a single operation. private decimal _riskPerTrade; // Maximum equity proportion at risk in open positions in a given time. private decimal _maxExposure; // Maximum equity proportion at risk in a single trade. private decimal _maxExposurePerTrade; private int _lotSize; private int _minQuantity; private SecurityPortfolioManager _portfolio; /// <summary> /// Initializes a new instance of the <see cref="FxRiskManagment"/> class. /// </summary> /// <param name="portfolio">The QCAlgorithm Portfolio.</param> /// <param name="riskPerTrade">The max risk per trade.</param> /// <param name="maxExposurePerTrade">The maximum exposure per trade.</param> /// <param name="maxExposure">The maximum exposure in all trades.</param> /// <param name="lotsize">The minimum quantity to trade.</param> /// <exception cref="System.NotImplementedException">The pairs should be added to the algorithm before initialize the risk manager.</exception> public FxRiskManagment(SecurityPortfolioManager portfolio, decimal riskPerTrade, decimal maxExposurePerTrade, decimal maxExposure, LotSize lotsize = LotSize.Micro, int minQuantity = 5) { _portfolio = portfolio; if (_portfolio.Securities.Count == 0) { throw new NotImplementedException("The pairs should be added to the algorithm before initialize the risk manager."); } this._riskPerTrade = riskPerTrade; _maxExposurePerTrade = maxExposurePerTrade; this._maxExposure = maxExposure; _lotSize = (int)lotsize; _minQuantity = minQuantity; } /// <summary> /// Calculates the entry orders and stop-loss price. /// </summary> /// <param name="pair">The Forex pair Symbol.</param> /// <param name="action">The order direction.</param> /// <returns>a Tuple with the quantity as Item1 and the stop-loss price as Item2. If quantity is zero, then means that no trade must be done.</returns> public Tuple<int, decimal, decimal> CalculateEntryOrders(QuoteBars data, Symbol pair, AgentAction action) { // If exposure is greater than the max exposure, then return zero. if (_portfolio.TotalMarginUsed > _portfolio.TotalPortfolioValue * _maxExposure) { return Tuple.Create(0, 0m, 0m); } var closePrice = _portfolio.Securities[pair].Price; var leverage = _portfolio.Securities[pair].Leverage; var exchangeRate = _portfolio.Securities[pair].QuoteCurrency.ConversionRate; var volatility = _portfolio.Securities[pair].VolatilityModel.Volatility; // Estimate the maximum entry order quantity given the risk per trade. var moneyAtRisk = _portfolio.TotalPortfolioValue * _riskPerTrade; var quantity = action == AgentAction.GoLong ? _lotSize : -_lotSize; if((volatility * exchangeRate)>0) { var maxQuantitybyRisk = moneyAtRisk / (volatility * exchangeRate); // Estimate the maximum entry order quantity given the exposure per trade. var maxBuySize = Math.Min(_portfolio.MarginRemaining, _portfolio.TotalPortfolioValue * _maxExposurePerTrade) * leverage; var maxQuantitybyExposure = maxBuySize / (closePrice * exchangeRate); // The final quantity is the lowest of both. quantity = (int)(Math.Round(Math.Min(maxQuantitybyRisk, maxQuantitybyExposure) / _lotSize, 0) * _lotSize); // If the final quantity is lower than the minimum quantity of the given lot size, then return zero. if (quantity < _lotSize * _minQuantity) return Tuple.Create(0, 0m, 0m); quantity = action == AgentAction.GoLong ? quantity : -quantity; } var stopLossPrice = closePrice + (action == AgentAction.GoLong ? -volatility : volatility); return Tuple.Create(quantity, stopLossPrice, action == AgentAction.GoLong ? data[pair].Ask.Close : data[pair].Bid.Close); } /// <summary> /// Updates the stop-loss price of all open StopMarketOrders. /// </summary> public void UpdateTrailingStopOrders(QuoteBars data) { // Get all the spot-loss orders. var openStopLossOrders = _portfolio.Transactions.GetOrderTickets(o => o.OrderType == OrderType.StopMarket && o.Status == OrderStatus.Submitted); foreach (var ticket in openStopLossOrders) { var stopLossPrice = ticket.SubmitRequest.StopPrice; var volatility = _portfolio.Securities[ticket.Symbol].VolatilityModel.Volatility; var actualPrice = _portfolio.Securities[ticket.Symbol].Price; // The StopLossOrder has the opposite direction of the original order. var originalOrderDirection = ticket.Quantity > 0 ? OrderDirection.Sell : OrderDirection.Buy; if (originalOrderDirection == OrderDirection.Sell) { actualPrice = data[ticket.Symbol].Ask.Close; } if (originalOrderDirection == OrderDirection.Buy) { actualPrice = data[ticket.Symbol].Bid.Close; } var newStopLossPrice = actualPrice + (volatility * (originalOrderDirection == OrderDirection.Buy ? -1 : 1)); if ((originalOrderDirection == OrderDirection.Buy && newStopLossPrice > stopLossPrice) || (originalOrderDirection == OrderDirection.Sell && newStopLossPrice < stopLossPrice)) { /* if (originalOrderDirection == OrderDirection.Sell && data[ticket.Symbol].Ask.Close < System.Convert.ToDecimal(ticket.SubmitRequest.Tag)) { if(newStopLossPrice>System.Convert.ToDecimal(ticket.SubmitRequest.Tag)) { newStopLossPrice = System.Convert.ToDecimal(ticket.SubmitRequest.Tag); } } if (originalOrderDirection == OrderDirection.Buy && data[ticket.Symbol].Bid.Close > System.Convert.ToDecimal(ticket.SubmitRequest.Tag)) { //price is on right direction if(newStopLossPrice<System.Convert.ToDecimal(ticket.SubmitRequest.Tag)) { newStopLossPrice = System.Convert.ToDecimal(ticket.SubmitRequest.Tag); } } */ ticket.Update(new UpdateOrderFields { Quantity = -(_portfolio[ticket.Symbol].Quantity), StopPrice = newStopLossPrice }); } else if (!_portfolio[ticket.Symbol].Invested) { ticket.Cancel(); } else if(_portfolio[ticket.Symbol].Quantity!=ticket.Quantity) { ticket.Update(new UpdateOrderFields { Quantity = -(_portfolio[ticket.Symbol].Quantity) }); } } } } }
namespace QuantConnect { // Expression := [ "!" ] <Boolean> { <BooleanOperator> <Boolean> } ... // Boolean := <BooleanConstant> | <Expression> | "(" <Expression> ")" // BooleanOperator := "And" | "Or" // BooleanConstant := "True" | "False" public class Parser { private readonly IEnumerator<Token> _tokens; public Parser(IEnumerable<Token> tokens) { _tokens = tokens.GetEnumerator(); _tokens.MoveNext(); } public bool Parse() { while (_tokens.Current != null) { var isNegated = _tokens.Current is NegationToken; if (isNegated) _tokens.MoveNext(); var boolean = ParseBoolean(); if (isNegated) boolean = !boolean; while (_tokens.Current is OperandToken) { var operand = _tokens.Current; if (!_tokens.MoveNext()) { throw new Exception("Missing expression after operand"); } var nextBoolean = ParseBoolean(); if (operand is AndToken) boolean = boolean && nextBoolean; else boolean = boolean || nextBoolean; } return boolean; } throw new Exception("Empty expression"); } private bool ParseBoolean() { if (_tokens.Current is BooleanValueToken) { var current = _tokens.Current; _tokens.MoveNext(); if (current is TrueToken) return true; return false; } if (_tokens.Current is OpenParenthesisToken) { _tokens.MoveNext(); var expInPars = Parse(); if (!(_tokens.Current is ClosedParenthesisToken)) throw new Exception("Expecting Closing Parenthesis"); _tokens.MoveNext(); return expInPars; } if (_tokens.Current is ClosedParenthesisToken) throw new Exception("Unexpected Closed Parenthesis"); // since its not a BooleanConstant or Expression in parenthesis, it must be a expression again var val = Parse(); return val; } } }
namespace QuantConnect { public class Tokenizer { private string _text; private int i = 0; public Tokenizer(string text) { _text = text; } public IEnumerable<Token> Tokenize() { var tokens = new List<Token>(); while (_text.Length > i) { while (Char.IsWhiteSpace((char) _text[i])) { i++; } if (_text.Length <= i) break; var c = (char) _text[i]; switch (c) { case '!': tokens.Add(new NegationToken()); i++; break; case '(': tokens.Add(new OpenParenthesisToken()); i++; break; case ')': tokens.Add(new ClosedParenthesisToken()); i++; break; default: if (Char.IsLetter(c)) { var token = ParseKeyword(); tokens.Add(token); } else { var remainingText = _text.Substring(i) ?? string.Empty; throw new Exception(string.Format("Unknown grammar found at position {0} : '{1}'", _text.Length - remainingText.Length, remainingText)); } break; } } return tokens; } private Token ParseKeyword() { var text = ""; while (_text.Length > i && Char.IsLetter((char) _text[i])) { text = text + ((char) _text[i]); i++; } var potentialKeyword = text.ToString().ToLower(); switch (potentialKeyword) { case "true": return new TrueToken(); case "false": return new FalseToken(); case "and": return new AndToken(); case "or": return new OrToken(); default: throw new Exception("Expected keyword (True, False, And, Or) but found "+ potentialKeyword); } } } }
//https://github.com/spavkov/BooleanLogicExpressionParser namespace QuantConnect { public class OperandToken : Token { } public class OrToken : OperandToken { } public class AndToken : OperandToken { } public class BooleanValueToken : Token { } public class FalseToken : BooleanValueToken { } public class TrueToken : BooleanValueToken { } public class ParenthesisToken : Token { } public class ClosedParenthesisToken : ParenthesisToken { } public class OpenParenthesisToken : ParenthesisToken { } public class NegationToken : Token { } public abstract class Token { } }