| 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
{
}
}