Overall Statistics
Total Trades
0
Average Win
0%
Average Loss
0%
Compounding Annual Return
0%
Drawdown
0%
Expectancy
0
Net Profit
0%
Sharpe Ratio
0
Loss Rate
0%
Win Rate
0%
Profit-Loss Ratio
0
Alpha
0
Beta
0
Annual Standard Deviation
0
Annual Variance
0
Information Ratio
0
Tracking Error
0
Treynor Ratio
0
Total Fees
$0.00
using System;
using System.Linq;
using System.Collections;
using System.Collections.Generic; 
using QuantConnect.Securities;  
using QuantConnect.Models; 

namespace QuantConnect { 
    public partial class OandaAutochartist : QCAlgorithm
    {
    	// https://www.quantconnect.com/data#forex/oanda/currency-pairs
    	public 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 string[] OandaFXMajors = { 
    		"AUDJPY","AUDUSD","EURAUD","EURCHF","EURGBP","EURJPY","EURUSD","GBPCHF","GBPJPY","GBPUSD",
			"NZDUSD","USDCAD","USDCHF","USDJPY" };
			
		[Parameter]
		public string accessToken;
		
		[Parameter]
		public string timeZone = "America/New_York";
		
		[Parameter]
	   	public int lotSize = 10;
	   	
       	[Parameter]
       	public bool isLive = false;
       	
       	public string[] Symbols;
    	public bool test = true;
    	
    	public override void Initialize()
        {
        	SetTimeZone(timeZone);
           	SetStartDate(DateTime.Now.Date.AddDays(-1));
            SetCash(100000);
            SetBrokerageModel(BrokerageName.OandaBrokerage);
            Symbols = OandaFXSymbols;
            
            foreach (var symbol in Symbols)
            {
                AddForex(symbol, Resolution.Hour, Market.Oanda);
            }
            
   			Schedule.On(DateRules.EveryDay(), TimeRules.Every(TimeSpan.FromMinutes(15)), () =>
			{
				if ((isLive || test) && accessToken != "<enter>")
				{
					ProcessAutochartistSignals(QueryAutochartist());
					test = false;
				}
			});
        }
        
        public void OnData(TradeBars data)
        {
        	ExpireSignals();
        }
        
        public override void OnOrderEvent(OrderEvent orderEvent)
		{
			BracketEvent(orderEvent);
		}
    }
}
namespace QuantConnect {
	public partial class OandaAutochartist : QCAlgorithm
    {
    	// http://developer.oanda.com/rest-live/forex-labs/#autochartist
		public class Signal
		{
		    public Meta meta { get; set; }
		    public int id { get; set; }
		    public string instrument { get; set; }
		    public string type { get; set; }
		    public Data data { get; set; }
		}
		
		public class Meta
		{
		    public int completed { get; set; }
		    public Scores scores { get; set; }
		    public double probability { get; set; }
		    public int interval { get; set; }
		    public int direction { get; set; }
		    public string pattern { get; set; }
		    public int length { get; set; }
		    public Historicalstats historicalstats { get; set; }
		    public string trendtype { get; set; }
		}
		public class Scores
		{
		    public int uniformity { get; set; }
		    public int quality { get; set; }
		    public int breakout { get; set; }
		    public int initialtrend { get; set; }
		    public int clarity { get; set; }
		}
		public class Historicalstats
		{
		    public Hourofday hourofday { get; set; }
		    public Pattern pattern { get; set; }
		    public Symbol_ symbol { get; set; }	// Symbol is predefined
		}
		public class Hourofday
		{
		    public int total { get; set; }
		    public double percent { get; set; }
		    public int correct { get; set; }
		}
		public class Pattern
		{
		    public int total { get; set; }
		    public double percent { get; set; }
		    public int correct { get; set; }
		}
		public class Symbol_
		{
		    public int total { get; set; }
		    public double percent { get; set; }
		    public int correct { get; set; }
		}
		
		public class Data
		{
		    public int patternendtime { get; set; }
		    public Points points { get; set; }
		    public Prediction prediction { get; set; }
		}
		public class Points
		{
		    public Resistance resistance { get; set; }
		    public Support support { get; set; }
		}
		public class Resistance
		{
		    public int x0 { get; set; }
		    public int x1 { get; set; }
		    public double y0 { get; set; }
		    public double y1 { get; set; }
		}
		public class Support
		{
		    public int x0 { get; set; }
		    public int x1 { get; set; }
		    public double y0 { get; set; }
		    public double y1 { get; set; }
		}
		public class Prediction // only present if pattern is complete
		{
		    public int timeto { get; set; }
		    public int timefrom { get; set; }
		    public double pricehigh { get; set; }
		    public double pricelow { get; set; }
		}
    }
}
using RestSharp; // http://restsharp.org/
using Newtonsoft.Json; 
using Newtonsoft.Json.Linq; 

namespace QuantConnect {
	public partial class OandaAutochartist : QCAlgorithm
    {
        public string QueryAutochartist(string type = "chartpattern")
    	{
    		var url = "https://api-fxtrade.oanda.com/labs/v1/signal/autochartist?type=";
			var auth = "Bearer " + accessToken; 
			var client = new RestClient();
			client.BaseUrl = new Uri(url + type);
			var request = new RestRequest();
			request.AddHeader("Authorization", auth);
			IRestResponse response = client.Execute(request);
            return response.Content;
        }

        public void ProcessAutochartistSignals(String json)
        {
            JObject jobj = JObject.Parse(json);
			IList<JToken> jtoks = jobj?["signals"].Children().ToList();
			foreach (JToken jtok in jtoks)
			{
			    Signal signal = jtok.ToObject<Signal>();
			    ExecuteSignal(signal);			  
			}
        }

        public void ExecuteSignal(Signal signal)
        {
            var activeSignal = GenActiveSignal(signal);
            if (!ValidateSignal(activeSignal))
            {
                return;
            }
            MarketOrder(activeSignal.Symbol, signal.meta.direction * lotSize, false, GenSignalTag(activeSignal));
        }	    

    	public bool ValidateSignal(ActiveSignal activeSignal)
	    {  
            var symbol = activeSignal.Symbol;
    		return (Symbols.Contains(symbol)
    			&& activeSignal.IsCompleted
    			&& !Portfolio[symbol].Invested
      			&& (IsMarketOpen(symbol) || !isLive)
	    		&& !IsExpired(activeSignal.Expiration)
	    		&& IsApproachingTarget(activeSignal))
	    		? true : false; 
	    }

        public bool IsApproachingTarget(ActiveSignal activeSignal) 
        {
            var currentPrice = Securities[activeSignal.Symbol].Price;
            return ((activeSignal.IsLong && currentPrice < activeSignal.Forecast) 
                || (activeSignal.IsShort && currentPrice > activeSignal.Forecast)) ? true : false;
        }

        public bool IsExpired(DateTime expiration) 
        {
            return Time >= expiration ? true : false;
        }

        public bool IsHedgingPortfolio(ActiveSignal activeSignal)
        {
            return ((Portfolio[activeSignal.Symbol].IsLong && activeSignal.IsShort) 
                || (Portfolio[activeSignal.Symbol].IsShort && activeSignal.IsLong)) 
                ? true : false;
        }

        public ActiveSignal GenActiveSignal(Signal signal)
        {
            var activeSignal = new ActiveSignal();
            activeSignal.Id = signal.id;
            activeSignal.IsCompleted = signal.meta.completed == 1 ? true : false;
            activeSignal.IsLong = signal.meta.direction == 1 ? true : false;
            activeSignal.IsShort = signal.meta.direction == -1 ? true : false;
            activeSignal.Symbol = signal.instrument.Replace("_","");
            activeSignal.Expiration = DateTimeOffset.FromUnixTimeSeconds(signal.data.prediction.timeto).DateTime;
            activeSignal.Forecast = (decimal)(signal.meta.direction == 1 ? signal.data.prediction.pricelow : signal.data.prediction.pricehigh);           
            return activeSignal;
        }

        public class ActiveSignal
        {
            public int Id { get; set; }
            public bool IsCompleted { get; set; }
            public bool IsLong { get; set; }
            public bool IsShort { get; set; }
            public string Symbol { get; set; }
            public DateTime Expiration { get; set; }
            public decimal Forecast { get; set; }    		  
        }

	    public string GenSignalTag(ActiveSignal activeSignal)
	    {
	    	var orderTag = new OrderTag();
	    	orderTag.SignalId = activeSignal.Id;
	    	orderTag.Expiration = activeSignal.Expiration;
	    	orderTag.Target = activeSignal.Forecast;	    	
	    	return JsonConvert.SerializeObject(orderTag);
	    }

        public class OrderTag 
	    {
    	 	public int SignalId { get; set; } = 0;
    	 	public DateTime Expiration { get; set; } = DateTime.MaxValue;
		    public decimal Target { get; set; } = 0;		  
	    }	

        public void BracketEvent(OrderEvent orderEvent)
        {
            var orderTicket = Transactions.GetOrderTicket(orderEvent.OrderId);
			if (orderTicket.Status == OrderStatus.Submitted
                && orderTicket.OrderType == OrderType.Market)
			{
                AddBracket(orderTicket);
            }
            else if (orderTicket.Status.IsClosed()
            	&& (orderTicket.OrderType == OrderType.StopMarket
            	|| orderTicket.OrderType == OrderType.Limit))
            {
                CloseBracket(orderTicket.Symbol);
            }
        }

        public void AddBracket(OrderTicket submittedTicket)
        {
            if (!Transactions.GetOrderTickets(x => x.Status.IsOpen() 
                && x.Symbol == submittedTicket.Symbol 
                && x.OrderType == OrderType.StopMarket).Any())
            {
                SetStopLoss(submittedTicket);
            }
            if (!Transactions.GetOrderTickets(x => x.Status.IsOpen() 
                && x.Symbol == submittedTicket.Symbol 
                && x.OrderType == OrderType.Limit).Any())
            {
                SetTakeProfit(submittedTicket);
            }
        }
		
		public void SetStopLoss(OrderTicket submittedOpenTicket)
		{
			StopMarketOrder(submittedOpenTicket.Symbol, -submittedOpenTicket.Quantity, CalcStopLoss(submittedOpenTicket), submittedOpenTicket.Tag);
		}
		
		public decimal CalcStopLoss(OrderTicket openTicket)
	    {
            OrderTag orderTag = JsonConvert.DeserializeObject<OrderTag>(openTicket.Tag);
            var openPrice = Securities[openTicket.Symbol].Price;             
	    	var profitRange = Math.Abs(orderTag.Target - openPrice);
	    	var lossRange = profitRange / 2;
	    	return orderTag.Target > openPrice ? openPrice - lossRange : openPrice + lossRange;
	    }    
		
		public void SetTakeProfit(OrderTicket submittedOpenTicket)
		{
            OrderTag openTag = JsonConvert.DeserializeObject<OrderTag>(submittedOpenTicket.Tag);
			LimitOrder(submittedOpenTicket.Symbol, -submittedOpenTicket.Quantity, openTag.Target, submittedOpenTicket.Tag);
		}

        public void CloseBracket(string symbol)
        {
			Transactions.CancelOpenOrders(symbol);
        }

        public void ExpireSignals()
        {
	 		foreach (Order openOrder in Transactions.GetOpenOrders())
	 		{
	 			OrderTag orderTag = JsonConvert.DeserializeObject<OrderTag>(openOrder.Tag);
	 			if (IsExpired(orderTag.Expiration))
	 			{
                     Liquidate(openOrder.Symbol);
                     CloseBracket(openOrder.Symbol);
	 			}
	 		}
        }		
    }
}