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
Probabilistic 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
-11.297
Tracking Error
0.242
Treynor Ratio
0
Total Fees
$0.00
Estimated Strategy Capacity
$0
Lowest Capacity Asset
#region imports
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using Newtonsoft.Json;
    using QuantConnect.Util;
    using QuantConnect.Data;
    using QuantConnect.Data.UniverseSelection;
    using QuantConnect.Securities;
#endregion

namespace QuantConnect.DataSource
{
    public class FundingRate : BaseData
    {
        [JsonProperty("time")]
        [JsonConverter(typeof(DateTimeJsonConverter), "yyyy-MM-ddTHH:mm:ssK")]
        public override DateTime EndTime { get; set; }
        
        [JsonProperty("future")]
        public string FTXsymbol { get; set; }

        [JsonProperty("rate")]
    	[JsonConverter(typeof(JsonScientificConverter))]
        public decimal Rate { get; set; }
        
        public override SubscriptionDataSource GetSource(SubscriptionDataConfig config, DateTime date, bool isLive)
	    {
            //NEED A WAY TO PASS 'symbolData.BaseSymbol' HERE SO 'source' CAN BE DYNAICALLY UPDATED FOR EACH SYMBOL 
	        var source = "https://ftx.com/api/funding_rates?future=BTC-PERP";
	
	        return new SubscriptionDataSource(source, SubscriptionTransportMedium.RemoteFile, FileFormat.UnfoldingCollection);
	    }

        public override BaseData Reader(SubscriptionDataConfig config, string line, DateTime date, bool isLive)
    	{
            var response = JsonConvert.DeserializeObject<RawFundingRate>(line, _jsonSerializerSettings);

            if (!response.Success) return null;

            var data = response.Result.Select(json =>
            {
                json.Symbol = config.Symbol;
                json.Time = json.EndTime.AddHours(-1);
                json.Value = json.Rate;
                return json;
            })
            .OrderBy(f => f.Time).ToList();

            return new BaseDataCollection(date, config.Symbol, data);
        }

        public override bool RequiresMapping()
        {
            return false;
        }

        public override bool IsSparseData()
        {
            return true;
        }

        public override Resolution DefaultResolution()
        {
            return Resolution.Hour;
        }

        public override List<Resolution> SupportedResolutions()
        {
            return new List<Resolution>{Resolution.Hour};
        }

        private readonly JsonSerializerSettings _jsonSerializerSettings = new()
        {
            DateTimeZoneHandling = DateTimeZoneHandling.Utc
        };

        private class JsonScientificConverter : JsonConverter
        {
            public override bool CanRead => true;
            public override bool CanConvert(Type objectType) => true;

            public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
            {
                serializer.Serialize(writer, value);
            }

            public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
            {
                return (decimal)(serializer.Deserialize<decimal>(reader));
            }       
        }
    }

    public class RawFundingRate
    {
        [JsonProperty("success")]
        public bool Success { get; set; }

        [JsonProperty("result")]
        public List<FundingRate> Result { get; set; }
    }
}
#region imports
    using System;
    using System.Collections.Generic;   
    using QuantConnect.Brokerages;
    using QuantConnect.Data;
    using QuantConnect.DataSource;
#endregion

namespace QuantConnect.Algorithm.CSharp
{
    public partial class CryptoAlgo : QCAlgorithm
    {
        Dictionary<Symbol, SymbolData> DataDico = new Dictionary<Symbol, SymbolData>();
        Dictionary<Symbol, FundingRate> FundingRateDico = new Dictionary<Symbol, FundingRate>();
        private Symbol FR_Symbol;

		public override void Initialize()
        {
        	SetStartDate(2022, 8, 1);
            SetEndDate(2022, 8, 10);
            SetCash(10000);

            foreach (var symbol in CryptoSymbolsList)
            {
                var crypto = AddCrypto(symbol, Resolution.Hour, Market.FTX);
                DataDico.Add(symbol, new SymbolData(this, crypto.Symbol, crypto.BaseCurrencySymbol));
            }

            foreach (var kvp in DataDico)
            {
                var symbolData = kvp.Value;
                var fundingRate = AddData<FundingRate>(symbolData.BaseSymbol+"-PERP", Resolution.Hour);
                // MAYBE NEED TO STORE THE FundingRate OBJECTS INTO A DICTIONARY, BUT NOT SURE IF NECESSARY
                // SOMETHING ALONG THOSE LINE? FundingRateDico.Add(symbolData.Symbol, new FundingRate(symbolData.BaseSymbol+"-PERP"));
            }

            SetWarmUp(TimeSpan.FromDays(5));
            SetBrokerageModel(BrokerageName.FTX, AccountType.Margin);
        }

        
        public override void OnData(Slice data)
        {
            foreach (var kvp in DataDico)
            {
                SymbolData symbolData = kvp.Value;

                //Check if algorithm is ready, if not break
                if (!data.ContainsKey(symbolData.Symbol)) { return; }
                if (IsWarmingUp) { return; }
                if (!symbolData.IsReady) { return; }
                if (!symbolData.H4_ConsolidatorFlag) { return; }
                symbolData.H4_ConsolidatorFlag = false;

                symbolData.Price = symbolData.H4_BarsWin[0].Close;
                //DO SOME MAGIC HERE SO EVERY 4H WHEN THE DATA IS CONSOLIDATED, THE FUNDING RATE IS UPDATED INSIDE EACH symbolData
                //symbolData.FundingRate = XXX;

                Plot($"Price {symbolData.Symbol}", $"Price(H4)", symbolData.Price);
                //Plot($"Funding Rate {fr.FTXsymbol}", $"Price(H4)", fr.Rate);

                // THE BELOW CODE SHOULD NO LONGER BE NECESSARY
                foreach (var fr in data.Get<FundingRate>().Values)
                {
                    Debug($"Acctual Time {Time} | FR EndTime {fr.EndTime} | FR Symbol {fr.FTXsymbol} | FR Value {fr.Rate}");
                    Plot($"Funding Rate {fr.FTXsymbol}", $"Price(H4)", fr.Rate);
                }
            }
    	}
    }
}
#region imports
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Linq;
    using System.Globalization;
    using System.Drawing;
    using QuantConnect;
    using QuantConnect.Algorithm.Framework;
    using QuantConnect.Algorithm.Framework.Selection;
    using QuantConnect.Algorithm.Framework.Alphas;
    using QuantConnect.Algorithm.Framework.Portfolio;
    using QuantConnect.Algorithm.Framework.Execution;
    using QuantConnect.Algorithm.Framework.Risk;
    using QuantConnect.Parameters;
    using QuantConnect.Benchmarks;
    using QuantConnect.Brokerages;
    using QuantConnect.Util;
    using QuantConnect.Interfaces;
    using QuantConnect.Algorithm;
    using QuantConnect.Indicators;
    using QuantConnect.Data;
    using QuantConnect.Data.Consolidators;
    using QuantConnect.Data.Custom;
    using QuantConnect.DataSource;
    using QuantConnect.Data.Fundamental;
    using QuantConnect.Data.Market;
    using QuantConnect.Data.UniverseSelection;
    using QuantConnect.Notifications;
    using QuantConnect.Orders;
    using QuantConnect.Orders.Fees;
    using QuantConnect.Orders.Fills;
    using QuantConnect.Orders.Slippage;
    using QuantConnect.Scheduling;
    using QuantConnect.Securities;
    using QuantConnect.Securities.Equity;
    using QuantConnect.Securities.Future;
    using QuantConnect.Securities.Option;
    using QuantConnect.Securities.Forex;
    using QuantConnect.Securities.Crypto;
    using QuantConnect.Securities.Interfaces;
    using QuantConnect.Storage;
    using QuantConnect.Data.Custom.AlphaStreams;
    using QCAlgorithmFramework = QuantConnect.Algorithm.QCAlgorithm;
    using QCAlgorithmFrameworkBridge = QuantConnect.Algorithm.QCAlgorithm;
	using QuantConnect.Indicators.CandlestickPatterns;
#endregion

namespace QuantConnect.Algorithm.CSharp
{
	public partial class CryptoAlgo : QCAlgorithm
    {
        public class SymbolData
        {
        	//***General***
        	public readonly QCAlgorithm algorithm;
        	public readonly Symbol Symbol;
        	public readonly string BaseSymbol;
        	public readonly string QuoteSymbol;
            public TradeBarConsolidator H4_Bar;
    		public bool H4_ConsolidatorFlag = false;
    		public readonly RollingWindow<IBaseDataBar> H4_BarsWin;
     		public decimal Price;
            public decimal FundingRate;

    		//***SymbolData class constructor which initializes a new instance of SymbolData***
    		public SymbolData(QCAlgorithm algorithm, Symbol symbol, string baseSymbol)
    		{
    			this.algorithm = algorithm;
    			Symbol = symbol;
    			BaseSymbol = baseSymbol;
    			int _QSNumChr = Symbol.ToString().Length - BaseSymbol.Length;
    			QuoteSymbol = Symbol.ToString().Substring(Symbol.ToString().Length - _QSNumChr);
    			H4_BarsWin = new RollingWindow<IBaseDataBar>(30);
	            H4_Bar = new TradeBarConsolidator(TimeSpan.FromHours(4));

	    		H4_Bar.DataConsolidated += (sender, baseData) =>
				{
        			var _bar = (IBaseDataBar)baseData;
        			H4_ConsolidatorFlag = true;
					H4_BarsWin.Add(_bar);
				};
				
				algorithm.SubscriptionManager.AddConsolidator(symbol, H4_Bar);
				
    		}
    		
    		//***Returns true if all the data in this instance is ready (indicators, rolling windows, ect...)***
    		public bool IsReady
    		{
    			get {return H4_BarsWin.IsReady ;}
    		}

        }
    }
}
#region imports
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Linq;
    using System.Globalization;
    using System.Drawing;
    using QuantConnect;
    using QuantConnect.Algorithm.Framework;
    using QuantConnect.Algorithm.Framework.Selection;
    using QuantConnect.Algorithm.Framework.Alphas;
    using QuantConnect.Algorithm.Framework.Portfolio;
    using QuantConnect.Algorithm.Framework.Execution;
    using QuantConnect.Algorithm.Framework.Risk;
    using QuantConnect.Parameters;
    using QuantConnect.Benchmarks;
    using QuantConnect.Brokerages;
    using QuantConnect.Util;
    using QuantConnect.Interfaces;
    using QuantConnect.Algorithm;
    using QuantConnect.Indicators;
    using QuantConnect.Data;
    using QuantConnect.Data.Consolidators;
    using QuantConnect.Data.Custom;
    using QuantConnect.DataSource;
    using QuantConnect.Data.Fundamental;
    using QuantConnect.Data.Market;
    using QuantConnect.Data.UniverseSelection;
    using QuantConnect.Notifications;
    using QuantConnect.Orders;
    using QuantConnect.Orders.Fees;
    using QuantConnect.Orders.Fills;
    using QuantConnect.Orders.Slippage;
    using QuantConnect.Scheduling;
    using QuantConnect.Securities;
    using QuantConnect.Securities.Equity;
    using QuantConnect.Securities.Future;
    using QuantConnect.Securities.Option;
    using QuantConnect.Securities.Forex;
    using QuantConnect.Securities.Crypto;
    using QuantConnect.Securities.Interfaces;
    using QuantConnect.Storage;
    using QuantConnect.Data.Custom.AlphaStreams;
    using QCAlgorithmFramework = QuantConnect.Algorithm.QCAlgorithm;
    using QCAlgorithmFrameworkBridge = QuantConnect.Algorithm.QCAlgorithm;
	using QuantConnect.Indicators.CandlestickPatterns;
#endregion

namespace QuantConnect.Algorithm.CSharp
{
	public partial class CryptoAlgo : QCAlgorithm
    {      
        //***Symbol List***
		List <string> CryptoSymbolsList = new List <string>
		{
			"BTCUSD",
			"ETHUSD",
			"MATICUSD",
			"BNBUSD",
			"FTMUSD",
			"SOLUSD",
			"XRPUSD",
			"AVAXUSD",
			"LINKUSD",
			"LTCUSD",
		};    	
    }
}