From cda769df7442e8610848360d303657178135c472 Mon Sep 17 00:00:00 2001
From: Martin-Molinero <martin@quantconnect.com>
Date: Tue, 14 Jan 2025 17:08:36 -0300
Subject: [PATCH] Add Nikkei 225 index support (#8529)

- Add Osaka exchange for nikkei index. Adding regression test
- Improve default market resolution
---
 .../HSIFutureHourRegressionAlgorithm.cs       |   2 +-
 .../NikkeiIndexRegressionAlgorithm.cs         | 122 ++++++++++++++++
 Algorithm/QCAlgorithm.cs                      |  84 +++++------
 Common/Currencies.cs                          |   7 +-
 Common/Market.cs                              |   8 +-
 Common/Securities/Index/IndexSymbol.cs        |  27 +++-
 Data/index/ose/minute/n225/20210114_trade.zip | Bin 0 -> 4775 bytes
 Data/market-hours/market-hours-database.json  | 138 ++++++++++++++++++
 .../symbol-properties-database.csv            |   2 +
 run_benchmarks.py                             |   5 +-
 10 files changed, 338 insertions(+), 57 deletions(-)
 create mode 100644 Algorithm.CSharp/NikkeiIndexRegressionAlgorithm.cs
 create mode 100644 Data/index/ose/minute/n225/20210114_trade.zip

diff --git a/Algorithm.CSharp/HSIFutureHourRegressionAlgorithm.cs b/Algorithm.CSharp/HSIFutureHourRegressionAlgorithm.cs
index b7daa659a3e1..657ced59c790 100644
--- a/Algorithm.CSharp/HSIFutureHourRegressionAlgorithm.cs
+++ b/Algorithm.CSharp/HSIFutureHourRegressionAlgorithm.cs
@@ -52,7 +52,7 @@ public override void Initialize()
             SetTimeZone(TimeZones.HongKong);
 
             UniverseSettings.Resolution = Resolution;
-            _index = AddIndex("HSI", Resolution, market: Market.HKFE).Symbol;
+            _index = AddIndex("HSI", Resolution).Symbol;
             var future = AddFuture(Futures.Indices.HangSeng, Resolution);
             future.SetFilter(TimeSpan.Zero, TimeSpan.FromDays(182));
             _futureSymbol = future.Symbol;
diff --git a/Algorithm.CSharp/NikkeiIndexRegressionAlgorithm.cs b/Algorithm.CSharp/NikkeiIndexRegressionAlgorithm.cs
new file mode 100644
index 000000000000..633b38934160
--- /dev/null
+++ b/Algorithm.CSharp/NikkeiIndexRegressionAlgorithm.cs
@@ -0,0 +1,122 @@
+/*
+ * QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
+ * Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+*/
+
+using QuantConnect.Indicators;
+using QuantConnect.Interfaces;
+using QuantConnect.Securities;
+using System.Collections.Generic;
+
+namespace QuantConnect.Algorithm.CSharp
+{
+    /// <summary>
+    /// Example algorithm using nikkei index
+    /// </summary>
+    public class NikkeiIndexRegressionAlgorithm : QCAlgorithm, IRegressionAlgorithmDefinition
+    {
+        private Security _security;
+        private ExponentialMovingAverage _emaSlow;
+        private ExponentialMovingAverage _emaFast;
+
+        /// <summary>
+        /// Initialize your algorithm and add desired assets.
+        /// </summary>
+        public override void Initialize()
+        {
+            SetStartDate(2021, 1, 14);
+            SetEndDate(2021, 1, 15);
+            SetCash(1000000);
+
+            _security = AddIndex("N225");
+
+            var symbol = _security.Symbol;
+            _emaSlow = EMA(symbol, 80);
+            _emaFast = EMA(symbol, 200);
+
+            Settings.DailyPreciseEndTime = true;
+        }
+
+        public override void OnEndOfAlgorithm()
+        {
+            if (!_emaSlow.IsReady || !_emaFast.IsReady)
+            {
+                throw new RegressionTestException("Indicators are not ready!");
+            }
+            if (!_security.HasData)
+            {
+                throw new RegressionTestException("Security does not have data!");
+            }
+        }
+
+        /// <summary>
+        /// This is used by the regression test system to indicate if the open source Lean repository has the required data to run this algorithm.
+        /// </summary>
+        public virtual bool CanRunLocally { get; } = true;
+
+        /// <summary>
+        /// This is used by the regression test system to indicate which languages this algorithm is written in.
+        /// </summary>
+        public virtual List<Language> Languages { get; } = new() { Language.CSharp };
+
+        /// <summary>
+        /// Data Points count of all timeslices of algorithm
+        /// </summary>
+        public virtual long DataPoints => 443;
+
+        /// <summary>
+        /// Data Points count of the algorithm history
+        /// </summary>
+        public virtual int AlgorithmHistoryDataPoints => 0;
+
+        /// <summary>
+        /// Final status of the algorithm
+        /// </summary>
+        public AlgorithmStatus AlgorithmStatus => AlgorithmStatus.Completed;
+
+        /// <summary>
+        /// This is used by the regression test system to indicate what the expected statistics are from running the algorithm
+        /// </summary>
+        public virtual Dictionary<string, string> ExpectedStatistics => new Dictionary<string, string>
+        {
+            {"Total Orders", "0"},
+            {"Average Win", "0%"},
+            {"Average Loss", "0%"},
+            {"Compounding Annual Return", "0%"},
+            {"Drawdown", "0%"},
+            {"Expectancy", "0"},
+            {"Start Equity", "1000000"},
+            {"End Equity", "1000000"},
+            {"Net Profit", "0%"},
+            {"Sharpe Ratio", "0"},
+            {"Sortino 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", "0"},
+            {"Tracking Error", "0"},
+            {"Treynor Ratio", "0"},
+            {"Total Fees", "$0.00"},
+            {"Estimated Strategy Capacity", "$0"},
+            {"Lowest Capacity Asset", ""},
+            {"Portfolio Turnover", "0%"},
+            {"OrderListHash", "d41d8cd98f00b204e9800998ecf8427e"}
+        };
+    }
+}
diff --git a/Algorithm/QCAlgorithm.cs b/Algorithm/QCAlgorithm.cs
index 280eb60d2ae8..0224eb60d098 100644
--- a/Algorithm/QCAlgorithm.cs
+++ b/Algorithm/QCAlgorithm.cs
@@ -56,6 +56,7 @@
 using Python.Runtime;
 using QuantConnect.Commands;
 using Newtonsoft.Json;
+using QuantConnect.Securities.Index;
 
 namespace QuantConnect.Algorithm
 {
@@ -1378,11 +1379,7 @@ public void SetBenchmark(SecurityType securityType, string symbol)
                 throw new InvalidOperationException("Algorithm.SetBenchmark(): Cannot change Benchmark after algorithm initialized.");
             }
 
-            string market;
-            if (!BrokerageModel.DefaultMarkets.TryGetValue(securityType, out market))
-            {
-                market = Market.USA;
-            }
+            var market = GetMarket(null, symbol, securityType, defaultMarket: Market.USA);
 
             var benchmarkSymbol = QuantConnect.Symbol.Create(symbol, securityType, market);
             SetBenchmark(benchmarkSymbol);
@@ -1886,13 +1883,7 @@ public Security AddSecurity(SecurityType securityType, string ticker, Resolution
 
             try
             {
-                if (market == null)
-                {
-                    if (!BrokerageModel.DefaultMarkets.TryGetValue(securityType, out market))
-                    {
-                        throw new KeyNotFoundException($"No default market set for security type: {securityType}");
-                    }
-                }
+                market = GetMarket(market, ticker, securityType);
 
                 Symbol symbol;
                 if (!SymbolCache.TryGetSymbol(ticker, out symbol) ||
@@ -2068,13 +2059,7 @@ public Equity AddEquity(string ticker, Resolution? resolution = null, string mar
         [DocumentationAttribute(AddingData)]
         public Option AddOption(string underlying, Resolution? resolution = null, string market = null, bool fillForward = true, decimal leverage = Security.NullLeverage)
         {
-            if (market == null)
-            {
-                if (!BrokerageModel.DefaultMarkets.TryGetValue(SecurityType.Option, out market))
-                {
-                    throw new KeyNotFoundException($"No default market set for security type: {SecurityType.Option}");
-                }
-            }
+            market = GetMarket(market, underlying, SecurityType.Option);
 
             var underlyingSymbol = QuantConnect.Symbol.Create(underlying, SecurityType.Equity, market);
             return AddOption(underlyingSymbol, resolution, market, fillForward, leverage);
@@ -2117,13 +2102,7 @@ public Option AddOption(Symbol underlying, string targetOption, Resolution? reso
         {
             var optionType = QuantConnect.Symbol.GetOptionTypeFromUnderlying(underlying);
 
-            if (market == null)
-            {
-                if (!BrokerageModel.DefaultMarkets.TryGetValue(optionType, out market))
-                {
-                    throw new KeyNotFoundException($"No default market set for security type: {optionType}");
-                }
-            }
+            market = GetMarket(market, targetOption, optionType);
 
             Symbol canonicalSymbol;
 
@@ -2165,14 +2144,7 @@ public Future AddFuture(string ticker, Resolution? resolution = null, string mar
             bool fillForward = true, decimal leverage = Security.NullLeverage, bool extendedMarketHours = false,
             DataMappingMode? dataMappingMode = null, DataNormalizationMode? dataNormalizationMode = null, int contractDepthOffset = 0)
         {
-            if (market == null)
-            {
-                if (!SymbolPropertiesDatabase.TryGetMarket(ticker, SecurityType.Future, out market)
-                    && !BrokerageModel.DefaultMarkets.TryGetValue(SecurityType.Future, out market))
-                {
-                    throw new KeyNotFoundException($"No default market set for security type: {SecurityType.Future}");
-                }
-            }
+            market = GetMarket(market, ticker, SecurityType.Future);
 
             Symbol canonicalSymbol;
             var alias = "/" + ticker;
@@ -2301,13 +2273,8 @@ public IndexOption AddIndexOption(Symbol symbol, string targetOption, Resolution
         [DocumentationAttribute(AddingData)]
         public IndexOption AddIndexOption(string underlying, string targetOption, Resolution? resolution = null, string market = null, bool fillForward = true)
         {
-            if (market == null && !BrokerageModel.DefaultMarkets.TryGetValue(SecurityType.Index, out market))
-            {
-                throw new KeyNotFoundException($"No default market set for underlying security type: {SecurityType.Index}");
-            }
-
             return AddIndexOption(
-                QuantConnect.Symbol.Create(underlying, SecurityType.Index, market),
+                QuantConnect.Symbol.Create(underlying, SecurityType.Index, GetMarket(market, underlying, SecurityType.Index)),
                 targetOption, resolution, fillForward);
         }
 
@@ -2946,13 +2913,7 @@ private T AddSecurity<T>(SecurityType securityType, string ticker, Resolution? r
             DataMappingMode? mappingMode = null, DataNormalizationMode? normalizationMode = null)
             where T : Security
         {
-            if (market == null)
-            {
-                if (!BrokerageModel.DefaultMarkets.TryGetValue(securityType, out market))
-                {
-                    throw new Exception("No default market set for security type: " + securityType);
-                }
-            }
+            market = GetMarket(market, ticker, securityType);
 
             Symbol symbol;
             if (!SymbolCache.TryGetSymbol(ticker, out symbol) ||
@@ -3489,6 +3450,35 @@ public CommandResultPacket RunCommand(CallbackCommand command)
             return true;
         }
 
+        /// <summary>
+        /// Helper method to get a market for a given security type and ticker
+        /// </summary>
+        private string GetMarket(string market, string ticker, SecurityType securityType, string defaultMarket = null)
+        {
+            if (string.IsNullOrEmpty(market))
+            {
+                if (securityType == SecurityType.Index && IndexSymbol.TryGetIndexMarket(ticker, out market))
+                {
+                    return market;
+                }
+
+                if (securityType == SecurityType.Future && SymbolPropertiesDatabase.TryGetMarket(ticker, securityType, out market))
+                {
+                    return market;
+                }
+
+                if (!BrokerageModel.DefaultMarkets.TryGetValue(securityType, out market))
+                {
+                    if (string.IsNullOrEmpty(defaultMarket))
+                    {
+                        throw new KeyNotFoundException($"No default market set for security type: {securityType}");
+                    }
+                    return defaultMarket;
+                }
+            }
+            return market;
+        }
+
         private string CommandLink(string typeName, object command)
         {
             var payload = new Dictionary<string, dynamic> { { "projectId", ProjectId }, { "command", command } };
diff --git a/Common/Currencies.cs b/Common/Currencies.cs
index eab212a6ea8c..fcbc1efd6702 100644
--- a/Common/Currencies.cs
+++ b/Common/Currencies.cs
@@ -66,6 +66,11 @@ public static class Currencies
         /// </summary>
         public const string HKD = "HKD";
 
+        /// <summary>
+        /// JPY (Japanese yen) currency string
+        /// </summary>
+        public const string JPY = "JPY";
+
         /// <summary>
         /// Null currency used when a real one is not required
         /// </summary>
@@ -81,7 +86,7 @@ public static class Currencies
         {
             {USD, "$"},
             {GBP, "₤"},
-            {"JPY", "¥"},
+            {JPY, "¥"},
             {EUR, "€"},
             {"NZD", "$"},
             {"AUD", "$"},
diff --git a/Common/Market.cs b/Common/Market.cs
index 82670df584c0..b2a1692cbd68 100644
--- a/Common/Market.cs
+++ b/Common/Market.cs
@@ -69,7 +69,8 @@ public static class Market
             Tuple.Create(Bybit, 37),
             Tuple.Create(Coinbase, 38),
             Tuple.Create(InteractiveBrokers, 39),
-            Tuple.Create(EUREX, 40)
+            Tuple.Create(EUREX, 40),
+            Tuple.Create(OSE, 41)
         };
 
         static Market()
@@ -169,6 +170,11 @@ static Market()
         /// </summary>
         public const string HKFE = "hkfe";
 
+        /// <summary>
+        /// Osaka Stock Exchange
+        /// </summary>
+        public const string OSE = "ose";
+
         /// <summary>
         /// London International Financial Futures and Options Exchange
         /// </summary>
diff --git a/Common/Securities/Index/IndexSymbol.cs b/Common/Securities/Index/IndexSymbol.cs
index 132e4f1ec506..a55e77e536a2 100644
--- a/Common/Securities/Index/IndexSymbol.cs
+++ b/Common/Securities/Index/IndexSymbol.cs
@@ -13,6 +13,7 @@
  * limitations under the License.
 */
 
+using System;
 using System.Collections.Generic;
 
 namespace QuantConnect.Securities.Index
@@ -22,27 +23,41 @@ namespace QuantConnect.Securities.Index
     /// </summary>
     public static class IndexSymbol
     {
-        private static readonly Dictionary<string, string> _indexMarket = new Dictionary<string, string>
+        private static readonly Dictionary<string, string> _indexExchange = new(StringComparer.InvariantCultureIgnoreCase)
         {
             { "SPX", Market.CBOE },
             { "NDX", "NASDAQ" },
             { "VIX", Market.CBOE },
             { "SPXW", Market.CBOE },
             { "NQX", "NASDAQ" },
-            { "VIXW", Market.CBOE },
-            { "HSI", Market.HKFE }
+            { "VIXW", Market.CBOE }
+        };
+
+        private static readonly Dictionary<string, string> _indexMarket = new(StringComparer.InvariantCultureIgnoreCase)
+        {
+            { "HSI", Market.HKFE },
+            { "N225", Market.OSE }
         };
 
         /// <summary>
         /// Gets the actual exchange the index lives on
         /// </summary>
-        /// <returns>The market of the index</returns>
+        /// <remarks>Useful for live trading</remarks>
+        /// <returns>The exchange of the index</returns>
         public static string GetIndexExchange(Symbol symbol)
         {
-            string market;
-            return _indexMarket.TryGetValue(symbol.Value, out market)
+            return _indexExchange.TryGetValue(symbol.Value, out var market)
                 ? market
                 : symbol.ID.Market;
         }
+
+        /// <summary>
+        /// Gets the lean market for this index ticker
+        /// </summary>
+        /// <returns>The market of the index</returns>
+        public static bool TryGetIndexMarket(string ticker, out string market)
+        {
+            return _indexMarket.TryGetValue(ticker, out market);
+        }
     }
 }
diff --git a/Data/index/ose/minute/n225/20210114_trade.zip b/Data/index/ose/minute/n225/20210114_trade.zip
new file mode 100644
index 0000000000000000000000000000000000000000..8edad96366ac527c24cfee809309a6ef51b7633f
GIT binary patch
literal 4775
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

literal 0
HcmV?d00001

diff --git a/Data/market-hours/market-hours-database.json b/Data/market-hours/market-hours-database.json
index a18855d3acd5..ca0956353325 100644
--- a/Data/market-hours/market-hours-database.json
+++ b/Data/market-hours/market-hours-database.json
@@ -123903,6 +123903,144 @@
         "12/31/2025": "12:00:00"
       },
       "lateOpens": {}
+    },
+    "Index-ose-[*]": {
+      "dataTimeZone": "Asia/Tokyo",
+      "exchangeTimeZone": "Asia/Tokyo",
+      "sunday": [],
+      "monday": [
+        {
+          "start": "09:00:00",
+          "end": "11:30:00",
+          "state": "market"
+        },
+        {
+          "start": "12:30:00",
+          "end": "15:30:00",
+          "state": "market"
+        }
+      ],
+      "tuesday": [
+        {
+          "start": "09:00:00",
+          "end": "11:30:00",
+          "state": "market"
+        },
+        {
+          "start": "12:30:00",
+          "end": "15:30:00",
+          "state": "market"
+        }
+      ],
+      "wednesday": [
+        {
+          "start": "09:00:00",
+          "end": "11:30:00",
+          "state": "market"
+        },
+        {
+          "start": "12:30:00",
+          "end": "15:30:00",
+          "state": "market"
+        }
+      ],
+      "thursday": [
+        {
+          "start": "09:00:00",
+          "end": "11:30:00",
+          "state": "market"
+        },
+        {
+          "start": "12:30:00",
+          "end": "15:30:00",
+          "state": "market"
+        }
+      ],
+      "friday": [
+        {
+          "start": "09:00:00",
+          "end": "11:30:00",
+          "state": "market"
+        },
+        {
+          "start": "12:30:00",
+          "end": "15:30:00",
+          "state": "market"
+        }
+      ],
+      "saturday": [],
+      "holidays": [],
+      "earlyCloses": {},
+      "lateOpens": {}
+    },
+    "Index-ose-N225": {
+      "dataTimeZone": "Asia/Tokyo",
+      "exchangeTimeZone": "Asia/Tokyo",
+      "sunday": [],
+      "monday": [
+        {
+          "start": "09:00:00",
+          "end": "11:30:00",
+          "state": "market"
+        },
+        {
+          "start": "12:30:00",
+          "end": "15:30:00",
+          "state": "market"
+        }
+      ],
+      "tuesday": [
+        {
+          "start": "09:00:00",
+          "end": "11:30:00",
+          "state": "market"
+        },
+        {
+          "start": "12:30:00",
+          "end": "15:30:00",
+          "state": "market"
+        }
+      ],
+      "wednesday": [
+        {
+          "start": "09:00:00",
+          "end": "11:30:00",
+          "state": "market"
+        },
+        {
+          "start": "12:30:00",
+          "end": "15:30:00",
+          "state": "market"
+        }
+      ],
+      "thursday": [
+        {
+          "start": "09:00:00",
+          "end": "11:30:00",
+          "state": "market"
+        },
+        {
+          "start": "12:30:00",
+          "end": "15:30:00",
+          "state": "market"
+        }
+      ],
+      "friday": [
+        {
+          "start": "09:00:00",
+          "end": "11:30:00",
+          "state": "market"
+        },
+        {
+          "start": "12:30:00",
+          "end": "15:30:00",
+          "state": "market"
+        }
+      ],
+      "saturday": [],
+      "holidays": [],
+      "earlyCloses": {},
+      "lateOpens": {}
     }
   }
 }
\ No newline at end of file
diff --git a/Data/symbol-properties/symbol-properties-database.csv b/Data/symbol-properties/symbol-properties-database.csv
index b8be25c4f13c..947fb46b2dd6 100644
--- a/Data/symbol-properties/symbol-properties-database.csv
+++ b/Data/symbol-properties/symbol-properties-database.csv
@@ -407,6 +407,8 @@ india,SENSEX,future,BSE S&P Sensex Index,INR,0.05,25,1.0
 hkfe,HSI,future,Hang Seng Index,HKD,50,1,1.0
 hkfe,[*],index,,HKD,1,0.01,1
 
+ose,[*],index,,JPY,1,0.01,1
+
 # Futures options -- will default to Futures contract specs in case no entry exists
 cbot,OZB,futureoption,U.S. Treasury Bond American Futures Options,USD,1000.0,0.015625,1.0
 cbot,OZC,futureoption,Corn American Futures Options,USD,5000.0,0.00125,1.0,,,100
diff --git a/run_benchmarks.py b/run_benchmarks.py
index 7c48fb6bb62c..a029d0e7f363 100644
--- a/run_benchmarks.py
+++ b/run_benchmarks.py
@@ -30,7 +30,7 @@
 
 			dataPointsPerSecond = []
 			benchmarkLengths = []
-			for x in range(1, 2):
+			for x in range(1, 3):
 
 				subprocess.run(["dotnet", "./QuantConnect.Lean.Launcher.dll",
 					"--data-folder " + dataPath,
@@ -42,6 +42,9 @@
 					cwd="./Launcher/bin/Release",
 					stdout=subprocess.DEVNULL,
 					stderr=subprocess.DEVNULL)
+				if x == 1:
+					# skip first run
+					continue
 
 				algorithmLogs = os.path.join("./Launcher/bin/Release", algorithmName + "-log.txt")
 				file = open(algorithmLogs, 'r')