From bd0dfda7e9dc2916eff0da9883df70f946dca5b3 Mon Sep 17 00:00:00 2001 From: Josue Nina Date: Tue, 23 Jun 2026 16:41:27 -0500 Subject: [PATCH 1/2] Use local data source in CustomDataPropertiesRegressionAlgorithm --- ...CustomDataPropertiesRegressionAlgorithm.cs | 70 +++++++++---------- ...CustomDataPropertiesRegressionAlgorithm.py | 34 ++++----- 2 files changed, 47 insertions(+), 57 deletions(-) diff --git a/Algorithm.CSharp/CustomDataPropertiesRegressionAlgorithm.cs b/Algorithm.CSharp/CustomDataPropertiesRegressionAlgorithm.cs index fba19955843a..a5624a522434 100644 --- a/Algorithm.CSharp/CustomDataPropertiesRegressionAlgorithm.cs +++ b/Algorithm.CSharp/CustomDataPropertiesRegressionAlgorithm.cs @@ -16,6 +16,7 @@ using System; using System.Collections.Generic; using System.Globalization; +using System.IO; using Newtonsoft.Json; using QuantConnect.Data; using QuantConnect.Interfaces; @@ -109,7 +110,7 @@ public override void OnEndOfAlgorithm() /// /// Data Points count of all timeslices of algorithm /// - public long DataPoints => 57; + public long DataPoints => 53; /// /// Data Points count of the algorithm history @@ -129,31 +130,31 @@ public override void OnEndOfAlgorithm() {"Total Orders", "1"}, {"Average Win", "0%"}, {"Average Loss", "0%"}, - {"Compounding Annual Return", "34781.071%"}, - {"Drawdown", "4.300%"}, + {"Compounding Annual Return", "47.205%"}, + {"Drawdown", "0.300%"}, {"Expectancy", "0"}, {"Start Equity", "100000"}, - {"End Equity", "110102.2"}, - {"Net Profit", "10.102%"}, - {"Sharpe Ratio", "283.719"}, - {"Sortino Ratio", "1123.876"}, - {"Probabilistic Sharpe Ratio", "81.716%"}, + {"End Equity", "100637.62"}, + {"Net Profit", "0.638%"}, + {"Sharpe Ratio", "4.986"}, + {"Sortino Ratio", "484.533"}, + {"Probabilistic Sharpe Ratio", "68.746%"}, {"Loss Rate", "0%"}, {"Win Rate", "0%"}, {"Profit-Loss Ratio", "0"}, - {"Alpha", "184.11"}, - {"Beta", "-6.241"}, - {"Annual Standard Deviation", "0.635"}, - {"Annual Variance", "0.403"}, - {"Information Ratio", "260.511"}, - {"Tracking Error", "0.689"}, - {"Treynor Ratio", "-28.849"}, + {"Alpha", "-0.24"}, + {"Beta", "0.917"}, + {"Annual Standard Deviation", "0.072"}, + {"Annual Variance", "0.005"}, + {"Information Ratio", "-10.861"}, + {"Tracking Error", "0.027"}, + {"Treynor Ratio", "0.39"}, {"Total Fees", "$0.00"}, {"Estimated Strategy Capacity", "$0"}, {"Lowest Capacity Asset", "BTC.Bitcoin 2S"}, - {"Portfolio Turnover", "16.73%"}, - {"Drawdown Recovery", "2"}, - {"OrderListHash", "b890a8e73bf118e943ad2f2e712f12d0"} + {"Portfolio Turnover", "16.66%"}, + {"Drawdown Recovery", "1"}, + {"OrderListHash", "596837f3f0cb7b46650912203c2b7d61"} }; /// @@ -216,12 +217,9 @@ public override SubscriptionDataSource GetSource(SubscriptionDataConfig config, return new SubscriptionDataSource("https://www.bitstamp.net/api/ticker/", SubscriptionTransportMedium.Rest); } - //return "http://my-ftp-server.com/futures-data-" + date.ToString("Ymd") + ".zip"; - // OR simply return a fixed small data file. Large files will slow down your backtest - return new SubscriptionDataSource("https://www.quantconnect.com/api/v2/proxy/nasdaq/api/v3/datatables/QDL/BITFINEX.csv?code=BTCUSD&api_key=WyAazVXnq7ATy_fefTqm") - { - Sort = true - }; + // Read from a local data file so the test is deterministic instead of depending on a remote source + var source = Path.Combine(Globals.DataFolder, "equity", "usa", "daily", "spy.zip"); + return new SubscriptionDataSource(source, SubscriptionTransportMedium.LocalFile, FileFormat.Csv); } /// @@ -251,24 +249,22 @@ public override BaseData Reader(SubscriptionDataConfig config, string line, Date return coin; } - //Example Line Format: - // code date high low mid last bid ask volume - // BTCUSD 2024-10-08 63248.0 61940.0 62246.5 62245.0 62246.0 62247.0 5.929230648356 + // Example Line Format (prices scaled by 10000): + // date open high low close volume + // 20200106 00:00 3204400 3237300 3203600 3236400 43759922 try { - string[] data = line.Split(','); - coin.Time = DateTime.Parse(data[1], CultureInfo.InvariantCulture); + var data = line.Split(','); + coin.Time = DateTime.ParseExact(data[0], "yyyyMMdd HH:mm", CultureInfo.InvariantCulture); coin.EndTime = coin.Time.AddDays(1); - coin.High = Convert.ToDecimal(data[2], CultureInfo.InvariantCulture); - coin.Low = Convert.ToDecimal(data[3], CultureInfo.InvariantCulture); - coin.Mid = Convert.ToDecimal(data[4], CultureInfo.InvariantCulture); - coin.Close = Convert.ToDecimal(data[5], CultureInfo.InvariantCulture); - coin.Bid = Convert.ToDecimal(data[6], CultureInfo.InvariantCulture); - coin.Ask = Convert.ToDecimal(data[7], CultureInfo.InvariantCulture); - coin.VolumeBTC = Convert.ToDecimal(data[8], CultureInfo.InvariantCulture); + coin.Open = Convert.ToDecimal(data[1], CultureInfo.InvariantCulture) / 10000m; + coin.High = Convert.ToDecimal(data[2], CultureInfo.InvariantCulture) / 10000m; + coin.Low = Convert.ToDecimal(data[3], CultureInfo.InvariantCulture) / 10000m; + coin.Close = Convert.ToDecimal(data[4], CultureInfo.InvariantCulture) / 10000m; + coin.VolumeBTC = Convert.ToDecimal(data[5], CultureInfo.InvariantCulture); coin.Value = coin.Close; } - catch { /* Do nothing, skip first title row */ } + catch { /* Do nothing, skip malformed rows */ } return coin; } diff --git a/Algorithm.Python/CustomDataPropertiesRegressionAlgorithm.py b/Algorithm.Python/CustomDataPropertiesRegressionAlgorithm.py index 4f373c3c5f38..8b4dbb79788c 100644 --- a/Algorithm.Python/CustomDataPropertiesRegressionAlgorithm.py +++ b/Algorithm.Python/CustomDataPropertiesRegressionAlgorithm.py @@ -67,11 +67,9 @@ def get_source(self, config: SubscriptionDataConfig, date: datetime, is_live_mod if is_live_mode: return SubscriptionDataSource("https://www.bitstamp.net/api/ticker/", SubscriptionTransportMedium.REST) - #return "http://my-ftp-server.com/futures-data-" + date.to_string("Ymd") + ".zip" - # OR simply return a fixed small data file. Large files will slow down your backtest - subscription = SubscriptionDataSource("https://www.quantconnect.com/api/v2/proxy/nasdaq/api/v3/datatables/QDL/BITFINEX.csv?code=BTCUSD&api_key=WyAazVXnq7ATy_fefTqm") - subscription.sort = True - return subscription + # Read from a local data file so the test is deterministic instead of depending on a remote source + source = f"{Globals.data_folder}/equity/usa/daily/spy.zip" + return SubscriptionDataSource(source, SubscriptionTransportMedium.LOCAL_FILE, FileFormat.CSV) def reader(self, config: SubscriptionDataConfig, line: str, date: datetime, is_live_mode: bool) -> DynamicData: coin = Bitcoin() @@ -102,25 +100,21 @@ def reader(self, config: SubscriptionDataConfig, line: str, date: datetime, is_l # Do nothing, possible error in json decoding return coin - # Example Line Format: - #code date high low mid last bid ask volume - #BTCUSD 2024-10-08 63248.0 61940.0 62246.5 62245.0 62246.0 62247.0 5.929230648356 - if not (line.strip() and line[7].isdigit()): return coin - + # Example Line Format (prices scaled by 10000): + # date open high low close volume + # 20200106 00:00 3204400 3237300 3203600 3236400 43759922 try: data = line.split(',') - coin.time = datetime.strptime(data[1], "%Y-%m-%d") + coin.time = datetime.strptime(data[0], "%Y%m%d %H:%M") coin.end_time = coin.time + timedelta(1) - coin.value = float(data[5]) - coin["High"] = float(data[2]) - coin["Low"] = float(data[3]) - coin["Mid"] = float(data[4]) - coin["Close"] = float(data[5]) - coin["Bid"] = float(data[6]) - coin["Ask"] = float(data[7]) - coin["VolumeBTC"] = float(data[8]) + coin.value = float(data[4]) / 10000 + coin["Open"] = float(data[1]) / 10000 + coin["High"] = float(data[2]) / 10000 + coin["Low"] = float(data[3]) / 10000 + coin["Close"] = float(data[4]) / 10000 + coin["VolumeBTC"] = float(data[5]) return coin except ValueError: - # Do nothing, possible error in json decoding + # Do nothing, skip malformed rows return coin From 499aa24634e5b962dc57a60ffc92a97f0c049199 Mon Sep 17 00:00:00 2001 From: Josue Nina Date: Tue, 23 Jun 2026 17:34:18 -0500 Subject: [PATCH 2/2] Use crypto data source instead of equity --- ...CustomDataPropertiesRegressionAlgorithm.cs | 54 +++++++++---------- ...CustomDataPropertiesRegressionAlgorithm.py | 20 +++---- 2 files changed, 37 insertions(+), 37 deletions(-) diff --git a/Algorithm.CSharp/CustomDataPropertiesRegressionAlgorithm.cs b/Algorithm.CSharp/CustomDataPropertiesRegressionAlgorithm.cs index a5624a522434..cdc54b1de847 100644 --- a/Algorithm.CSharp/CustomDataPropertiesRegressionAlgorithm.cs +++ b/Algorithm.CSharp/CustomDataPropertiesRegressionAlgorithm.cs @@ -41,8 +41,8 @@ public class CustomDataPropertiesRegressionAlgorithm : QCAlgorithm, IRegressionA /// public override void Initialize() { - SetStartDate(2020, 01, 05); - SetEndDate(2020, 01, 10); + SetStartDate(2018, 04, 05); + SetEndDate(2018, 04, 10); //Set the cash for the strategy: SetCash(100000); @@ -110,7 +110,7 @@ public override void OnEndOfAlgorithm() /// /// Data Points count of all timeslices of algorithm /// - public long DataPoints => 53; + public long DataPoints => 50; /// /// Data Points count of the algorithm history @@ -130,31 +130,31 @@ public override void OnEndOfAlgorithm() {"Total Orders", "1"}, {"Average Win", "0%"}, {"Average Loss", "0%"}, - {"Compounding Annual Return", "47.205%"}, - {"Drawdown", "0.300%"}, + {"Compounding Annual Return", "-45.767%"}, + {"Drawdown", "4.000%"}, {"Expectancy", "0"}, {"Start Equity", "100000"}, - {"End Equity", "100637.62"}, - {"Net Profit", "0.638%"}, - {"Sharpe Ratio", "4.986"}, - {"Sortino Ratio", "484.533"}, - {"Probabilistic Sharpe Ratio", "68.746%"}, + {"End Equity", "98999.21"}, + {"Net Profit", "-1.001%"}, + {"Sharpe Ratio", "0.907"}, + {"Sortino Ratio", "3.722"}, + {"Probabilistic Sharpe Ratio", "48.891%"}, {"Loss Rate", "0%"}, {"Win Rate", "0%"}, {"Profit-Loss Ratio", "0"}, - {"Alpha", "-0.24"}, - {"Beta", "0.917"}, - {"Annual Standard Deviation", "0.072"}, - {"Annual Variance", "0.005"}, - {"Information Ratio", "-10.861"}, - {"Tracking Error", "0.027"}, - {"Treynor Ratio", "0.39"}, + {"Alpha", "0.514"}, + {"Beta", "0.649"}, + {"Annual Standard Deviation", "0.5"}, + {"Annual Variance", "0.25"}, + {"Information Ratio", "1.127"}, + {"Tracking Error", "0.485"}, + {"Treynor Ratio", "0.699"}, {"Total Fees", "$0.00"}, {"Estimated Strategy Capacity", "$0"}, {"Lowest Capacity Asset", "BTC.Bitcoin 2S"}, - {"Portfolio Turnover", "16.66%"}, - {"Drawdown Recovery", "1"}, - {"OrderListHash", "596837f3f0cb7b46650912203c2b7d61"} + {"Portfolio Turnover", "16.93%"}, + {"Drawdown Recovery", "2"}, + {"OrderListHash", "b9aecea6ebe672324d20a389ac004b1e"} }; /// @@ -218,7 +218,7 @@ public override SubscriptionDataSource GetSource(SubscriptionDataConfig config, } // Read from a local data file so the test is deterministic instead of depending on a remote source - var source = Path.Combine(Globals.DataFolder, "equity", "usa", "daily", "spy.zip"); + var source = Path.Combine(Globals.DataFolder, "crypto", "coinbase", "daily", "btcusd_trade.zip"); return new SubscriptionDataSource(source, SubscriptionTransportMedium.LocalFile, FileFormat.Csv); } @@ -249,18 +249,18 @@ public override BaseData Reader(SubscriptionDataConfig config, string line, Date return coin; } - // Example Line Format (prices scaled by 10000): + // Example Line Format: // date open high low close volume - // 20200106 00:00 3204400 3237300 3203600 3236400 43759922 + // 20180405 00:00 6791.68 6933.11 6568.64 6785.85 13832.668772 try { var data = line.Split(','); coin.Time = DateTime.ParseExact(data[0], "yyyyMMdd HH:mm", CultureInfo.InvariantCulture); coin.EndTime = coin.Time.AddDays(1); - coin.Open = Convert.ToDecimal(data[1], CultureInfo.InvariantCulture) / 10000m; - coin.High = Convert.ToDecimal(data[2], CultureInfo.InvariantCulture) / 10000m; - coin.Low = Convert.ToDecimal(data[3], CultureInfo.InvariantCulture) / 10000m; - coin.Close = Convert.ToDecimal(data[4], CultureInfo.InvariantCulture) / 10000m; + coin.Open = Convert.ToDecimal(data[1], CultureInfo.InvariantCulture); + coin.High = Convert.ToDecimal(data[2], CultureInfo.InvariantCulture); + coin.Low = Convert.ToDecimal(data[3], CultureInfo.InvariantCulture); + coin.Close = Convert.ToDecimal(data[4], CultureInfo.InvariantCulture); coin.VolumeBTC = Convert.ToDecimal(data[5], CultureInfo.InvariantCulture); coin.Value = coin.Close; } diff --git a/Algorithm.Python/CustomDataPropertiesRegressionAlgorithm.py b/Algorithm.Python/CustomDataPropertiesRegressionAlgorithm.py index 8b4dbb79788c..359789ddd4dd 100644 --- a/Algorithm.Python/CustomDataPropertiesRegressionAlgorithm.py +++ b/Algorithm.Python/CustomDataPropertiesRegressionAlgorithm.py @@ -25,8 +25,8 @@ class CustomDataPropertiesRegressionAlgorithm(QCAlgorithm): def initialize(self) -> None: - self.set_start_date(2020, 1, 5) # Set Start Date - self.set_end_date(2020, 1, 10) # Set End Date + self.set_start_date(2018, 4, 5) # Set Start Date + self.set_end_date(2018, 4, 10) # Set End Date self.set_cash(100000) # Set Strategy Cash # Define our custom data properties and exchange hours @@ -68,7 +68,7 @@ def get_source(self, config: SubscriptionDataConfig, date: datetime, is_live_mod return SubscriptionDataSource("https://www.bitstamp.net/api/ticker/", SubscriptionTransportMedium.REST) # Read from a local data file so the test is deterministic instead of depending on a remote source - source = f"{Globals.data_folder}/equity/usa/daily/spy.zip" + source = f"{Globals.data_folder}/crypto/coinbase/daily/btcusd_trade.zip" return SubscriptionDataSource(source, SubscriptionTransportMedium.LOCAL_FILE, FileFormat.CSV) def reader(self, config: SubscriptionDataConfig, line: str, date: datetime, is_live_mode: bool) -> DynamicData: @@ -100,18 +100,18 @@ def reader(self, config: SubscriptionDataConfig, line: str, date: datetime, is_l # Do nothing, possible error in json decoding return coin - # Example Line Format (prices scaled by 10000): + # Example Line Format: # date open high low close volume - # 20200106 00:00 3204400 3237300 3203600 3236400 43759922 + # 20180405 00:00 6791.68 6933.11 6568.64 6785.85 13832.668772 try: data = line.split(',') coin.time = datetime.strptime(data[0], "%Y%m%d %H:%M") coin.end_time = coin.time + timedelta(1) - coin.value = float(data[4]) / 10000 - coin["Open"] = float(data[1]) / 10000 - coin["High"] = float(data[2]) / 10000 - coin["Low"] = float(data[3]) / 10000 - coin["Close"] = float(data[4]) / 10000 + coin.value = float(data[4]) + coin["Open"] = float(data[1]) + coin["High"] = float(data[2]) + coin["Low"] = float(data[3]) + coin["Close"] = float(data[4]) coin["VolumeBTC"] = float(data[5]) return coin