Overall Statistics
Total Trades
895
Average Win
0.11%
Average Loss
-0.01%
Compounding Annual Return
-0.562%
Drawdown
2.900%
Expectancy
-0.360
Net Profit
-1.121%
Sharpe Ratio
-0.341
Probabilistic Sharpe Ratio
2.117%
Loss Rate
94%
Win Rate
6%
Profit-Loss Ratio
9.55
Alpha
-0.005
Beta
0.001
Annual Standard Deviation
0.013
Annual Variance
0
Information Ratio
-1.006
Tracking Error
0.227
Treynor Ratio
-5.724
Total Fees
$0.00
using System;
using System.Collections.Generic;
using IntrinsicTime;

namespace QuantConnect.Algorithm.CSharp
{
    public class AlphaEngine : QCAlgorithm
    {
    	public Dictionary<Symbol, IntrinsicTimeChart> Charts;
    	private Dictionary<Symbol, decimal?> StopLoss;
    	private List<Symbol> _symbols;
    	private int _lookback;
    	private int _size;

        public override void Initialize()
        {
            SetStartDate(2019, 1, 1);
            SetCash(100000);
            
            List<string> pairs = new List<string> {
            	"AUDJPY", "AUDNZD", "AUDUSD", "CADJPY", "CHFJPY",
            	"EURAUD", "EURCAD", "EURCHF", "EURGBP",
            	"EURJPY", "EURNZD", "EURUSD", "GBPAUD", "GBPCAD",
            	"GBPCHF", "GBPJPY", "GBPUSD", "NZDCAD",
            	"NZDJPY", "NZDUSD", "USDCAD", "USDCHF", "USDJPY",
            };
            
            _symbols = new List<Symbol> {};
            _lookback = int.Parse(GetParameter("lookback"));
            _size = int.Parse(GetParameter("size"));
            decimal precision = Decimal.Parse(GetParameter("change_percentage"));
            
            Charts = new Dictionary<Symbol, IntrinsicTimeChart>();
            StopLoss = new Dictionary<Symbol, decimal?>();
            
            for (int i = 0; i < pairs.Count; i++)
            {
            	Forex fx = AddForex(pairs[i], Resolution.Minute);
            	_symbols.Add(fx.Symbol);
            	var chart = new IntrinsicTimeChart(5, fx.Symbol, precision, _lookback);
            	chart.OnChartUpdate += OnChartUpdate;
            	Charts.Add(fx.Symbol, chart);
            	StopLoss.Add(fx.Symbol, null);
            }
        }

        public override void OnData(Slice data)
        {
        	for (int i = 0; i < _symbols.Count; i++)
        	{
        		Symbol s = _symbols[i];
        		if (data.QuoteBars.ContainsKey(s))
        		{
        			Charts[s].Update(Time, data.QuoteBars[s].Ask);
        		}
        		if (Portfolio[s].Invested && data.QuoteBars[s].Ask.Low < StopLoss[s].Value)
        		{
        			Liquidate(s);
        			StopLoss[s] = null;
        		}
        	}
        }
        
        public void OnChartUpdate(object sender, Symbol symbol)
        {
        	IntrinsicTimeChart chart = Charts[symbol];
        	
        	if (chart.Window.Count < 2 || chart.Window[0].Reversal)
        	{
        		return;
        	}
        	
        	IntrinsicTimeBar new_bar = chart.Window[0];
        	IntrinsicTimeBar last_bar = chart.Window[1];
        	
        	if (new_bar.High > last_bar.High)
        	{
        		MarketOrder(symbol, _size);
        		StopLoss[symbol] = new_bar.Low;
        	}
        }
    }
}
namespace IntrinsicTime
{
	public class IntrinsicTimeChart
	{
		public int Precision;
		public decimal? High;
		public decimal? Low;
		public int WindowLength;
		public Symbol SecuritySymbol;
		public RollingWindow<IntrinsicTimeBar> Window;
		public event EventHandler<Symbol> OnChartUpdate;
		private decimal _maxPercentageChange;
		
		public IntrinsicTimeChart(int precision, Symbol s, decimal maxPercentageChange)
		{
			Precision = precision;
			WindowLength = 3;
			SecuritySymbol = s;
			_maxPercentageChange = maxPercentageChange;
			Window = new RollingWindow<IntrinsicTimeBar>(3);
		}
		
		public IntrinsicTimeChart(int precision, Symbol symbol, decimal maxPercentageChange, int length)
		{
			if (length < 3)
			{
				throw new ArgumentException("length must be 3 or more");
			}
			Precision = precision;
			WindowLength = length;
			SecuritySymbol = symbol;
			_maxPercentageChange = maxPercentageChange;
			Window = new RollingWindow<IntrinsicTimeBar>(length);
		}
		
		public void Update(DateTime time, Bar bar)
		{
			Update(time, bar.Open);
			
			var distanceToLow = Math.Abs(Math.Round(bar.Open - bar.Low, Precision));
			var distanceToHigh = Math.Abs(Math.Round(bar.Open - bar.High, Precision));
			
			if (distanceToLow < distanceToHigh)
			{
				Update(time, bar.Low);
				Update(time, bar.High);
			}
			else
			{
				Update(time, bar.High);
				Update(time, bar.Low);
			}
			
			Update(time, bar.Close);
		}
		
		public void Update(DateTime time, decimal price)
		{
			High = High == null ? price : Math.Max(price, High.Value);
			Low = Low == null ? price : Math.Min(price, Low.Value);
			
			var delta = Math.Round(High.Value - Low.Value, Precision);
			var mid = Math.Round((High.Value + Low.Value) * new Decimal(0.5), Precision);
			var barHeight = Math.Round(mid * _maxPercentageChange, Precision);
			var possibleNewUpper = Math.Round(Low.Value + barHeight, Precision);
			var possibleNewLower = Math.Round(High.Value - barHeight, Precision);
			
			if (delta < barHeight)
			{
				return;
			}
			if (price >= possibleNewUpper)
			{
				var isReversal = false;
				if (Window.Count > 1)
				{
					isReversal = Window[1].Low > Window[0].Low;
				}
				Window.Add(new IntrinsicTimeBar(time, possibleNewUpper, Low.Value, isReversal));
				High = possibleNewUpper;
				Low = possibleNewUpper;
			}
			else if (price <= possibleNewLower)
			{
				var isReversal = false;
				if (Window.Count > 1)
				{
					isReversal = Window[1].High < Window[0].High;
				}
				Window.Add(new IntrinsicTimeBar(time, High.Value, possibleNewLower, isReversal));
				High = possibleNewLower;
				Low = possibleNewLower;
			}
			else
			{
				throw new Exception("The impossible has happened");
			}
			
			if (Window.Count > 0)
			{
				OnChartUpdate?.Invoke(this, SecuritySymbol);
			}
			Update(time, price);
		}
	}
	
	public class IntrinsicTimeBar
	{
		public bool Reversal;
		public decimal High;
		public decimal Low;
		public DateTime Time;
		
		public IntrinsicTimeBar(DateTime time, decimal high, decimal low, bool reversal)
		{
			Time = time;
			Reversal = reversal;
			High = high;
			Low = low;
		}
	}
}