Compare commits
10 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ca9e55fda6 | ||
|
|
b698641c90 | ||
|
|
e5c709ee29 | ||
|
|
ca787d0a25 | ||
|
|
b1a1277eca | ||
|
|
30d7fb042b | ||
|
|
d1bb70fbb7 | ||
|
|
0946bfc2fb | ||
|
|
f34be8e3ff | ||
|
|
e1d1e28bb8 |
@@ -18,6 +18,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using QuantConnect.Data;
|
||||
using QuantConnect.Data.UniverseSelection;
|
||||
using QuantConnect.Interfaces;
|
||||
using QuantConnect.Securities;
|
||||
using QuantConnect.Securities.Future;
|
||||
@@ -64,6 +65,9 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
|
||||
var benchmark = AddEquity("SPY");
|
||||
SetBenchmark(benchmark.Symbol);
|
||||
|
||||
var seeder = new FuncSecuritySeeder(GetLastKnownPrices);
|
||||
SetSecurityInitializer(security => seeder.SeedSecurity(security));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -112,6 +116,19 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
var maintenanceIntraday = futureMarginModel.MaintenanceIntradayMarginRequirement;
|
||||
}
|
||||
|
||||
public override void OnSecuritiesChanged(SecurityChanges changes)
|
||||
{
|
||||
foreach (var addedSecurity in changes.AddedSecurities)
|
||||
{
|
||||
if (addedSecurity.Symbol.SecurityType == SecurityType.Future
|
||||
&& !addedSecurity.Symbol.IsCanonical()
|
||||
&& !addedSecurity.HasData)
|
||||
{
|
||||
throw new Exception($"Future contracts did not work up as expected: {addedSecurity.Symbol}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <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>
|
||||
|
||||
@@ -14,8 +14,9 @@
|
||||
*/
|
||||
|
||||
using QuantConnect.Data;
|
||||
using QuantConnect.Orders;
|
||||
using System.Collections.Generic;
|
||||
using QuantConnect.Interfaces;
|
||||
using QuantConnect.Orders;
|
||||
|
||||
namespace QuantConnect.Algorithm.CSharp
|
||||
{
|
||||
@@ -26,16 +27,17 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
/// <meta name="tag" content="using data" />
|
||||
/// <meta name="tag" content="using quantconnect" />
|
||||
/// <meta name="tag" content="trading and orders" />
|
||||
public class BasicTemplateIndiaAlgorithm : QCAlgorithm
|
||||
public class BasicTemplateIndiaAlgorithm : QCAlgorithm, IRegressionAlgorithmDefinition
|
||||
{
|
||||
/// <summary>
|
||||
/// Initialise the data and resolution required, as well as the cash and start-end dates for your algorithm. All algorithms must initialized.
|
||||
/// </summary>
|
||||
public override void Initialize()
|
||||
{
|
||||
SetAccountCurrency("INR"); //Set Account Currency
|
||||
SetStartDate(2019, 1, 23); //Set Start Date
|
||||
SetEndDate(2019, 10, 31); //Set End Date
|
||||
SetCash(100000); //Set Strategy Cash
|
||||
SetEndDate(2019, 10, 31); //Set End Date
|
||||
SetCash(100000); //Set Strategy Cash
|
||||
|
||||
// Find more symbols here: http://quantconnect.com/data
|
||||
// Equities Resolutions: Tick, Second, Minute, Hour, Daily.
|
||||
@@ -85,48 +87,48 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
/// </summary>
|
||||
public Dictionary<string, string> ExpectedStatistics => new Dictionary<string, string>
|
||||
{
|
||||
{"Total Trades", "3"},
|
||||
{"Total Trades", "1"},
|
||||
{"Average Win", "0%"},
|
||||
{"Average Loss", "-1.01%"},
|
||||
{"Compounding Annual Return", "261.134%"},
|
||||
{"Drawdown", "2.200%"},
|
||||
{"Expectancy", "-1"},
|
||||
{"Net Profit", "1.655%"},
|
||||
{"Sharpe Ratio", "8.505"},
|
||||
{"Probabilistic Sharpe Ratio", "66.840%"},
|
||||
{"Loss Rate", "100%"},
|
||||
{"Average Loss", "0%"},
|
||||
{"Compounding Annual Return", "-0.010%"},
|
||||
{"Drawdown", "0.000%"},
|
||||
{"Expectancy", "0"},
|
||||
{"Net Profit", "-0.008%"},
|
||||
{"Sharpe Ratio", "-1.183"},
|
||||
{"Probabilistic Sharpe Ratio", "0.001%"},
|
||||
{"Loss Rate", "0%"},
|
||||
{"Win Rate", "0%"},
|
||||
{"Profit-Loss Ratio", "0"},
|
||||
{"Alpha", "-0.091"},
|
||||
{"Beta", "1.006"},
|
||||
{"Annual Standard Deviation", "0.224"},
|
||||
{"Annual Variance", "0.05"},
|
||||
{"Information Ratio", "-33.445"},
|
||||
{"Tracking Error", "0.002"},
|
||||
{"Treynor Ratio", "1.893"},
|
||||
{"Total Fees", "$10.32"},
|
||||
{"Estimated Strategy Capacity", "$27000000.00"},
|
||||
{"Lowest Capacity Asset", "SPY R735QTJ8XC9X"},
|
||||
{"Fitness Score", "0.747"},
|
||||
{"Kelly Criterion Estimate", "38.796"},
|
||||
{"Kelly Criterion Probability Value", "0.228"},
|
||||
{"Sortino Ratio", "79228162514264337593543950335"},
|
||||
{"Return Over Maximum Drawdown", "85.095"},
|
||||
{"Portfolio Turnover", "0.747"},
|
||||
{"Total Insights Generated", "100"},
|
||||
{"Total Insights Closed", "99"},
|
||||
{"Total Insights Analysis Completed", "99"},
|
||||
{"Long Insight Count", "100"},
|
||||
{"Alpha", "0"},
|
||||
{"Beta", "0"},
|
||||
{"Annual Standard Deviation", "0"},
|
||||
{"Annual Variance", "0"},
|
||||
{"Information Ratio", "-1.183"},
|
||||
{"Tracking Error", "0"},
|
||||
{"Treynor Ratio", "0"},
|
||||
{"Total Fees", "$6.00"},
|
||||
{"Estimated Strategy Capacity", "$61000000000.00"},
|
||||
{"Lowest Capacity Asset", "YESBANK UL"},
|
||||
{"Fitness Score", "0"},
|
||||
{"Kelly Criterion Estimate", "0"},
|
||||
{"Kelly Criterion Probability Value", "0"},
|
||||
{"Sortino Ratio", "-0.247"},
|
||||
{"Return Over Maximum Drawdown", "-1.104"},
|
||||
{"Portfolio Turnover", "0"},
|
||||
{"Total Insights Generated", "0"},
|
||||
{"Total Insights Closed", "0"},
|
||||
{"Total Insights Analysis Completed", "0"},
|
||||
{"Long Insight Count", "0"},
|
||||
{"Short Insight Count", "0"},
|
||||
{"Long/Short Ratio", "100%"},
|
||||
{"Estimated Monthly Alpha Value", "$135639.1761"},
|
||||
{"Total Accumulated Estimated Alpha Value", "$21852.9784"},
|
||||
{"Mean Population Estimated Insight Value", "$220.7372"},
|
||||
{"Mean Population Direction", "53.5354%"},
|
||||
{"Mean Population Magnitude", "53.5354%"},
|
||||
{"Rolling Averaged Population Direction", "58.2788%"},
|
||||
{"Rolling Averaged Population Magnitude", "58.2788%"},
|
||||
{"OrderListHash", "ad2216297c759d8e5aef48ff065f8919"}
|
||||
{"Estimated Monthly Alpha Value", "₹0"},
|
||||
{"Total Accumulated Estimated Alpha Value", "₹0"},
|
||||
{"Mean Population Estimated Insight Value", "₹0"},
|
||||
{"Mean Population Direction", "0%"},
|
||||
{"Mean Population Magnitude", "0%"},
|
||||
{"Rolling Averaged Population Direction", "0%"},
|
||||
{"Rolling Averaged Population Magnitude", "0%"},
|
||||
{"OrderListHash", "6cc69218edd7bd461678b9ee0c575db5"}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
158
Algorithm.CSharp/BasicTemplateIndiaIndexAlgorithm.cs
Normal file
158
Algorithm.CSharp/BasicTemplateIndiaIndexAlgorithm.cs
Normal file
@@ -0,0 +1,158 @@
|
||||
/*
|
||||
* 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 System;
|
||||
using QuantConnect.Data;
|
||||
using System.Collections.Generic;
|
||||
using QuantConnect.Indicators;
|
||||
using QuantConnect.Interfaces;
|
||||
using QuantConnect.Orders;
|
||||
|
||||
namespace QuantConnect.Algorithm.CSharp
|
||||
{
|
||||
/// <summary>
|
||||
/// This example demonstrates how to add index asset types.
|
||||
/// </summary>
|
||||
/// <meta name="tag" content="using data" />
|
||||
/// <meta name="tag" content="benchmarks" />
|
||||
/// <meta name="tag" content="indexes" />
|
||||
public class BasicTemplateIndiaIndexAlgorithm : QCAlgorithm, IRegressionAlgorithmDefinition
|
||||
{
|
||||
protected Symbol Nifty;
|
||||
protected Symbol NiftyETF;
|
||||
private ExponentialMovingAverage _emaSlow;
|
||||
private ExponentialMovingAverage _emaFast;
|
||||
|
||||
/// <summary>
|
||||
/// Initialize your algorithm and add desired assets.
|
||||
/// </summary>
|
||||
public override void Initialize()
|
||||
{
|
||||
SetAccountCurrency("INR"); //Set Account Currency
|
||||
SetStartDate(2019, 1, 1); //Set End Date
|
||||
SetEndDate(2019, 1, 5); //Set End Date
|
||||
SetCash(1000000); //Set Strategy Cash
|
||||
|
||||
// Use indicator for signal; but it cannot be traded
|
||||
Nifty = AddIndex("NIFTY50", Resolution.Minute, Market.India).Symbol;
|
||||
|
||||
//Trade Index based ETF
|
||||
NiftyETF = AddEquity("JUNIORBEES", Resolution.Minute, Market.India).Symbol;
|
||||
|
||||
//Set Order Prperties as per the requirements for order placement
|
||||
DefaultOrderProperties = new IndiaOrderProperties(exchange: Exchange.NSE);
|
||||
|
||||
_emaSlow = EMA(Nifty, 80);
|
||||
_emaFast = EMA(Nifty, 200);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Index EMA Cross trading underlying.
|
||||
/// </summary>
|
||||
public override void OnData(Slice slice)
|
||||
{
|
||||
if (!slice.Bars.ContainsKey(Nifty) || !slice.Bars.ContainsKey(NiftyETF))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Warm up indicators
|
||||
if (!_emaSlow.IsReady)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (_emaFast > _emaSlow)
|
||||
{
|
||||
if (!Portfolio.Invested)
|
||||
{
|
||||
var marketTicket = MarketOrder(NiftyETF, 1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Liquidate();
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnEndOfAlgorithm()
|
||||
{
|
||||
if (Portfolio[Nifty].TotalSaleVolume > 0)
|
||||
{
|
||||
throw new Exception("Index is not tradable.");
|
||||
}
|
||||
}
|
||||
|
||||
/// <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 Language[] Languages { get; } = { Language.CSharp, Language.Python };
|
||||
|
||||
/// <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 Trades", "6"},
|
||||
{"Average Win", "0%"},
|
||||
{"Average Loss", "0.00%"},
|
||||
{"Compounding Annual Return", "-0.395%"},
|
||||
{"Drawdown", "0.000%"},
|
||||
{"Expectancy", "-1"},
|
||||
{"Net Profit", "-0.004%"},
|
||||
{"Sharpe Ratio", "-23.595"},
|
||||
{"Probabilistic Sharpe Ratio", "0%"},
|
||||
{"Loss Rate", "100%"},
|
||||
{"Win Rate", "0%"},
|
||||
{"Profit-Loss Ratio", "0"},
|
||||
{"Alpha", "0"},
|
||||
{"Beta", "0"},
|
||||
{"Annual Standard Deviation", "0"},
|
||||
{"Annual Variance", "0"},
|
||||
{"Information Ratio", "-23.595"},
|
||||
{"Tracking Error", "0"},
|
||||
{"Treynor Ratio", "0"},
|
||||
{"Total Fees", "$36.00"},
|
||||
{"Estimated Strategy Capacity", "$74000.00"},
|
||||
{"Lowest Capacity Asset", "JUNIORBEES UL"},
|
||||
{"Fitness Score", "0"},
|
||||
{"Kelly Criterion Estimate", "0"},
|
||||
{"Kelly Criterion Probability Value", "0"},
|
||||
{"Sortino Ratio", "-29.6"},
|
||||
{"Return Over Maximum Drawdown", "-123.624"},
|
||||
{"Portfolio Turnover", "0"},
|
||||
{"Total Insights Generated", "0"},
|
||||
{"Total Insights Closed", "0"},
|
||||
{"Total Insights Analysis Completed", "0"},
|
||||
{"Long Insight Count", "0"},
|
||||
{"Short Insight Count", "0"},
|
||||
{"Long/Short Ratio", "100%"},
|
||||
{"Estimated Monthly Alpha Value", "₹0"},
|
||||
{"Total Accumulated Estimated Alpha Value", "₹0"},
|
||||
{"Mean Population Estimated Insight Value", "₹0"},
|
||||
{"Mean Population Direction", "0%"},
|
||||
{"Mean Population Magnitude", "0%"},
|
||||
{"Rolling Averaged Population Direction", "0%"},
|
||||
{"Rolling Averaged Population Magnitude", "0%"},
|
||||
{"OrderListHash", "4637f26543287548b28a3c296db055d3"}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -45,6 +45,7 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
/// </summary>
|
||||
public override void Initialize()
|
||||
{
|
||||
SetAccountCurrency("INR"); //Set Account Currency
|
||||
SetStartDate(2004, 5, 20); //Set Start Date
|
||||
SetEndDate(2016, 7, 26); //Set End Date
|
||||
_mappingSymbol = AddEquity("3MINDIA", Resolution.Daily, Market.India).Symbol;
|
||||
@@ -170,8 +171,8 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
{"Beta", "0"},
|
||||
{"Annual Standard Deviation", "0"},
|
||||
{"Annual Variance", "0"},
|
||||
{"Information Ratio", "-0.427"},
|
||||
{"Tracking Error", "0.158"},
|
||||
{"Information Ratio", "0"},
|
||||
{"Tracking Error", "0"},
|
||||
{"Treynor Ratio", "0"},
|
||||
{"Total Fees", "$0.00"},
|
||||
{"Estimated Strategy Capacity", "$0"},
|
||||
@@ -188,9 +189,9 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
{"Long Insight Count", "0"},
|
||||
{"Short Insight Count", "0"},
|
||||
{"Long/Short Ratio", "100%"},
|
||||
{"Estimated Monthly Alpha Value", "$0"},
|
||||
{"Total Accumulated Estimated Alpha Value", "$0"},
|
||||
{"Mean Population Estimated Insight Value", "$0"},
|
||||
{"Estimated Monthly Alpha Value", "₹0"},
|
||||
{"Total Accumulated Estimated Alpha Value", "₹0"},
|
||||
{"Mean Population Estimated Insight Value", "₹0"},
|
||||
{"Mean Population Direction", "0%"},
|
||||
{"Mean Population Magnitude", "0%"},
|
||||
{"Rolling Averaged Population Direction", "0%"},
|
||||
|
||||
@@ -43,6 +43,8 @@ class BasicTemplateFuturesAlgorithm(QCAlgorithm):
|
||||
benchmark = self.AddEquity("SPY")
|
||||
self.SetBenchmark(benchmark.Symbol)
|
||||
|
||||
seeder = FuncSecuritySeeder(self.GetLastKnownPrices)
|
||||
self.SetSecurityInitializer(lambda security: seeder.SeedSecurity(security))
|
||||
|
||||
def OnData(self,slice):
|
||||
if not self.Portfolio.Invested:
|
||||
@@ -70,3 +72,8 @@ class BasicTemplateFuturesAlgorithm(QCAlgorithm):
|
||||
maintenanceOvernight = buyingPowerModel.MaintenanceOvernightMarginRequirement
|
||||
initialIntraday = buyingPowerModel.InitialIntradayMarginRequirement
|
||||
maintenanceIntraday = buyingPowerModel.MaintenanceIntradayMarginRequirement
|
||||
|
||||
def OnSecuritiesChanged(self, changes):
|
||||
for addedSecurity in changes.AddedSecurities:
|
||||
if addedSecurity.Symbol.SecurityType == SecurityType.Future and not addedSecurity.Symbol.IsCanonical() and not addedSecurity.HasData:
|
||||
raise Exception(f"Future contracts did not work up as expected: {addedSecurity.Symbol}")
|
||||
|
||||
@@ -25,9 +25,10 @@ class BasicTemplateIndiaAlgorithm(QCAlgorithm):
|
||||
def Initialize(self):
|
||||
'''Initialise the data and resolution required, as well as the cash and start-end dates for your algorithm. All algorithms must initialized.'''
|
||||
|
||||
self.SetAccountCurrency("INR") #Set Account Currency
|
||||
self.SetStartDate(2019, 1, 23) #Set Start Date
|
||||
self.SetEndDate(2019, 10, 31) #Set End Date
|
||||
self.SetCash(100000) #Set Strategy Cash
|
||||
self.SetEndDate(2019, 10, 31) #Set End Date
|
||||
self.SetCash(100000) #Set Strategy Cash
|
||||
# Find more symbols here: http://quantconnect.com/data
|
||||
self.AddEquity("YESBANK", Resolution.Minute, Market.India)
|
||||
self.Debug("numpy test >>> print numpy.pi: " + str(np.pi))
|
||||
@@ -42,7 +43,7 @@ class BasicTemplateIndiaAlgorithm(QCAlgorithm):
|
||||
data: Slice object keyed by symbol containing the stock data
|
||||
'''
|
||||
if not self.Portfolio.Invested:
|
||||
self.SetHoldings("YESBANK", 1)
|
||||
self.MarketOrder("YESBANK", 1)
|
||||
|
||||
def OnOrderEvent(self, orderEvent):
|
||||
if orderEvent.Status == OrderStatus.Filled:
|
||||
|
||||
71
Algorithm.Python/BasicTemplateIndiaIndexAlgorithm.py
Normal file
71
Algorithm.Python/BasicTemplateIndiaIndexAlgorithm.py
Normal file
@@ -0,0 +1,71 @@
|
||||
# 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.
|
||||
|
||||
from AlgorithmImports import *
|
||||
|
||||
### <summary>
|
||||
### Basic Template India Index Algorithm uses framework components to define the algorithm.
|
||||
### </summary>
|
||||
### <meta name="tag" content="using data" />
|
||||
### <meta name="tag" content="using quantconnect" />
|
||||
### <meta name="tag" content="trading and orders" />
|
||||
class BasicTemplateIndiaIndexAlgorithm(QCAlgorithm):
|
||||
'''Basic template framework algorithm uses framework components to define the algorithm.'''
|
||||
|
||||
def Initialize(self):
|
||||
'''Initialise the data and resolution required, as well as the cash and start-end dates for your algorithm. All algorithms must initialized.'''
|
||||
|
||||
self.SetAccountCurrency("INR") #Set Account Currency
|
||||
self.SetStartDate(2019, 1, 1) #Set Start Date
|
||||
self.SetEndDate(2019, 1, 5) #Set End Date
|
||||
self.SetCash(1000000) #Set Strategy Cash
|
||||
|
||||
# Use indicator for signal; but it cannot be traded
|
||||
self.Nifty = self.AddIndex("NIFTY50", Resolution.Minute, Market.India).Symbol
|
||||
# Trade Index based ETF
|
||||
self.NiftyETF = self.AddEquity("JUNIORBEES", Resolution.Minute, Market.India).Symbol
|
||||
|
||||
# Set Order Prperties as per the requirements for order placement
|
||||
self.DefaultOrderProperties = IndiaOrderProperties(Exchange.NSE)
|
||||
|
||||
# Define indicator
|
||||
self._emaSlow = self.EMA(self.Nifty, 80);
|
||||
self._emaFast = self.EMA(self.Nifty, 200);
|
||||
|
||||
self.Debug("numpy test >>> print numpy.pi: " + str(np.pi))
|
||||
|
||||
|
||||
def OnData(self, data):
|
||||
'''OnData event is the primary entry point for your algorithm. Each new data point will be pumped in here.
|
||||
|
||||
Arguments:
|
||||
data: Slice object keyed by symbol containing the stock data
|
||||
'''
|
||||
|
||||
if not data.Bars.ContainsKey(self.Nifty) or not data.Bars.ContainsKey(self.NiftyETF):
|
||||
return
|
||||
|
||||
if not self._emaSlow.IsReady:
|
||||
return
|
||||
|
||||
if self._emaFast > self._emaSlow:
|
||||
if not self.Portfolio.Invested:
|
||||
self.marketTicket = self.MarketOrder(self.NiftyETF, 1)
|
||||
else:
|
||||
self.Liquidate()
|
||||
|
||||
|
||||
def OnEndOfAlgorithm(self):
|
||||
if self.Portfolio[self.Nifty].TotalSaleVolume > 0:
|
||||
raise Exception("Index is not tradable.")
|
||||
|
||||
@@ -24,6 +24,8 @@ class IndiaDataRegressionAlgorithm(QCAlgorithm):
|
||||
|
||||
def Initialize(self):
|
||||
'''Initialise the data and resolution required, as well as the cash and start-end dates for your algorithm. All algorithms must initialized.'''
|
||||
|
||||
self.SetAccountCurrency("INR")
|
||||
self.SetStartDate(2004, 5, 20)
|
||||
self.SetEndDate(2016, 7, 26)
|
||||
self._mappingSymbol = self.AddEquity("3MINDIA", Resolution.Daily, Market.India).Symbol
|
||||
|
||||
@@ -513,16 +513,18 @@ namespace QuantConnect.Algorithm
|
||||
}
|
||||
|
||||
var result = new Dictionary<TickType, BaseData>();
|
||||
// For speed and memory usage, use Resolution.Minute as the minimum resolution
|
||||
var resolution = (Resolution)Math.Max((int)Resolution.Minute,
|
||||
(int)SubscriptionManager.SubscriptionDataConfigService.GetSubscriptionDataConfigs(symbol).GetHighestResolution());
|
||||
Resolution? resolution = null;
|
||||
Func<int, bool> requestData = period =>
|
||||
{
|
||||
var historyRequests = CreateBarCountHistoryRequests(new[] { symbol }, period, resolution)
|
||||
var historyRequests = CreateBarCountHistoryRequests(new[] { symbol }, period)
|
||||
.Select(request =>
|
||||
{
|
||||
// For speed and memory usage, use Resolution.Minute as the minimum resolution
|
||||
request.Resolution = (Resolution)Math.Max((int)Resolution.Minute, (int)request.Resolution);
|
||||
// force no fill forward behavior
|
||||
request.FillForwardResolution = null;
|
||||
|
||||
resolution = request.Resolution;
|
||||
return request;
|
||||
})
|
||||
// request only those tick types we didn't get the data we wanted
|
||||
@@ -547,12 +549,21 @@ namespace QuantConnect.Algorithm
|
||||
|
||||
if (!requestData(5))
|
||||
{
|
||||
// If the first attempt to get the last know price returns null, it maybe the case of an illiquid security.
|
||||
// We increase the look-back period for this case accordingly to the resolution to cover 3 trading days
|
||||
var periods =
|
||||
resolution == Resolution.Daily ? 3 :
|
||||
resolution == Resolution.Hour ? 24 : 1440;
|
||||
requestData(periods);
|
||||
if (resolution.HasValue)
|
||||
{
|
||||
// If the first attempt to get the last know price returns null, it maybe the case of an illiquid security.
|
||||
// We increase the look-back period for this case accordingly to the resolution to cover 3 trading days
|
||||
var periods =
|
||||
resolution.Value == Resolution.Daily ? 3 :
|
||||
resolution.Value == Resolution.Hour ? 24 : 1440;
|
||||
requestData(periods);
|
||||
}
|
||||
else
|
||||
{
|
||||
// this shouldn't happen but just in case
|
||||
QuantConnect.Logging.Log.Error(
|
||||
$"QCAlgorithm.GetLastKnownPrices(): no history request was created for symbol {symbol} at {Time}");
|
||||
}
|
||||
}
|
||||
// return the data ordered by time ascending
|
||||
return result.Values.OrderBy(data => data.Time);
|
||||
|
||||
@@ -320,7 +320,7 @@ namespace QuantConnect.Brokerages.Binance
|
||||
var apiKey = job.BrokerageData["binance-api-key"];
|
||||
var apiSecret = job.BrokerageData["binance-api-secret"];
|
||||
var aggregator = Composer.Instance.GetExportedValueByTypeName<IDataAggregator>(
|
||||
Config.Get("data-aggregator", "QuantConnect.Lean.Engine.DataFeeds.AggregationManager"));
|
||||
Config.Get("data-aggregator", "QuantConnect.Lean.Engine.DataFeeds.AggregationManager"), forceTypeNameOnExisting: false);
|
||||
|
||||
Initialize(
|
||||
wssUrl: webSocketBaseUrl,
|
||||
|
||||
@@ -88,7 +88,7 @@ namespace QuantConnect.Brokerages.Binance
|
||||
job.BrokerageData["binance-api-url"],
|
||||
job.BrokerageData["binance-websocket-url"],
|
||||
algorithm,
|
||||
Composer.Instance.GetExportedValueByTypeName<IDataAggregator>(Config.Get("data-aggregator", "QuantConnect.Lean.Engine.DataFeeds.AggregationManager")),
|
||||
Composer.Instance.GetExportedValueByTypeName<IDataAggregator>(Config.Get("data-aggregator", "QuantConnect.Lean.Engine.DataFeeds.AggregationManager"), forceTypeNameOnExisting: false),
|
||||
job);
|
||||
Composer.Instance.AddPart<IDataQueueHandler>(brokerage);
|
||||
|
||||
|
||||
@@ -443,7 +443,7 @@ namespace QuantConnect.Brokerages.Bitfinex
|
||||
var apiKey = job.BrokerageData["bitfinex-api-key"];
|
||||
var apiSecret = job.BrokerageData["bitfinex-api-secret"];
|
||||
var aggregator = Composer.Instance.GetExportedValueByTypeName<IDataAggregator>(
|
||||
Config.Get("data-aggregator", "QuantConnect.Lean.Engine.DataFeeds.AggregationManager"));
|
||||
Config.Get("data-aggregator", "QuantConnect.Lean.Engine.DataFeeds.AggregationManager"), forceTypeNameOnExisting: false);
|
||||
|
||||
Initialize(
|
||||
wssUrl: WebSocketUrl,
|
||||
|
||||
@@ -84,7 +84,7 @@ namespace QuantConnect.Brokerages.Bitfinex
|
||||
job.BrokerageData["bitfinex-api-secret"],
|
||||
algorithm,
|
||||
priceProvider,
|
||||
Composer.Instance.GetExportedValueByTypeName<IDataAggregator>(Config.Get("data-aggregator", "QuantConnect.Lean.Engine.DataFeeds.AggregationManager")),
|
||||
Composer.Instance.GetExportedValueByTypeName<IDataAggregator>(Config.Get("data-aggregator", "QuantConnect.Lean.Engine.DataFeeds.AggregationManager"), forceTypeNameOnExisting: false),
|
||||
job);
|
||||
Composer.Instance.AddPart<IDataQueueHandler>(brokerage);
|
||||
|
||||
|
||||
@@ -91,7 +91,7 @@ namespace QuantConnect.Brokerages.GDAX
|
||||
var restClient = new RestClient(restApi);
|
||||
var webSocketClient = new WebSocketClientWrapper();
|
||||
var priceProvider = new ApiPriceProvider(job.UserId, job.UserToken);
|
||||
var aggregator = Composer.Instance.GetExportedValueByTypeName<IDataAggregator>(Config.Get("data-aggregator", "QuantConnect.Lean.Engine.DataFeeds.AggregationManager"));
|
||||
var aggregator = Composer.Instance.GetExportedValueByTypeName<IDataAggregator>(Config.Get("data-aggregator", "QuantConnect.Lean.Engine.DataFeeds.AggregationManager"), forceTypeNameOnExisting: false);
|
||||
|
||||
IBrokerage brokerage;
|
||||
if (job.DataQueueHandler.Contains("GDAXDataQueueHandler"))
|
||||
|
||||
@@ -97,7 +97,7 @@ namespace QuantConnect.Brokerages.GDAX
|
||||
var apiSecret = job.BrokerageData["gdax-api-secret"];
|
||||
var priceProvider = new ApiPriceProvider(job.UserId, job.UserToken);
|
||||
var aggregator = Composer.Instance.GetExportedValueByTypeName<IDataAggregator>(
|
||||
Config.Get("data-aggregator", "QuantConnect.Lean.Engine.DataFeeds.AggregationManager"));
|
||||
Config.Get("data-aggregator", "QuantConnect.Lean.Engine.DataFeeds.AggregationManager"), forceTypeNameOnExisting: false);
|
||||
|
||||
Initialize(
|
||||
wssUrl: wssUrl,
|
||||
|
||||
@@ -2614,7 +2614,7 @@ namespace QuantConnect.Brokerages.InteractiveBrokers
|
||||
Initialize(null,
|
||||
null,
|
||||
null,
|
||||
Composer.Instance.GetExportedValueByTypeName<IDataAggregator>(Config.Get("data-aggregator", "QuantConnect.Lean.Engine.DataFeeds.AggregationManager")),
|
||||
Composer.Instance.GetExportedValueByTypeName<IDataAggregator>(Config.Get("data-aggregator", "QuantConnect.Lean.Engine.DataFeeds.AggregationManager"), forceTypeNameOnExisting: false),
|
||||
Composer.Instance.GetExportedValueByTypeName<IMapFileProvider>(Config.Get("map-file-provider", "QuantConnect.Data.Auxiliary.LocalDiskMapFileProvider")),
|
||||
account,
|
||||
host,
|
||||
|
||||
@@ -102,7 +102,7 @@ namespace QuantConnect.Brokerages.InteractiveBrokers
|
||||
algorithm,
|
||||
algorithm.Transactions,
|
||||
algorithm.Portfolio,
|
||||
Composer.Instance.GetExportedValueByTypeName<IDataAggregator>(Config.Get("data-aggregator", "QuantConnect.Lean.Engine.DataFeeds.AggregationManager")),
|
||||
Composer.Instance.GetExportedValueByTypeName<IDataAggregator>(Config.Get("data-aggregator", "QuantConnect.Lean.Engine.DataFeeds.AggregationManager"), forceTypeNameOnExisting: false),
|
||||
Composer.Instance.GetExportedValueByTypeName<IMapFileProvider>(Config.Get("map-file-provider", "QuantConnect.Data.Auxiliary.LocalDiskMapFileProvider")),
|
||||
account,
|
||||
host,
|
||||
|
||||
@@ -261,7 +261,7 @@ namespace QuantConnect.Brokerages.Oanda
|
||||
Initialize(
|
||||
null,
|
||||
null,
|
||||
Composer.Instance.GetExportedValueByTypeName<IDataAggregator>(Config.Get("data-aggregator", "QuantConnect.Lean.Engine.DataFeeds.AggregationManager")),
|
||||
Composer.Instance.GetExportedValueByTypeName<IDataAggregator>(Config.Get("data-aggregator", "QuantConnect.Lean.Engine.DataFeeds.AggregationManager"), forceTypeNameOnExisting: false),
|
||||
environment,
|
||||
accessToken,
|
||||
accountId,
|
||||
|
||||
@@ -96,7 +96,7 @@ namespace QuantConnect.Brokerages.Oanda
|
||||
var brokerage = new OandaBrokerage(
|
||||
algorithm.Transactions,
|
||||
algorithm.Portfolio,
|
||||
Composer.Instance.GetExportedValueByTypeName<IDataAggregator>(Config.Get("data-aggregator", "QuantConnect.Lean.Engine.DataFeeds.AggregationManager")),
|
||||
Composer.Instance.GetExportedValueByTypeName<IDataAggregator>(Config.Get("data-aggregator", "QuantConnect.Lean.Engine.DataFeeds.AggregationManager"), forceTypeNameOnExisting: false),
|
||||
environment,
|
||||
accessToken,
|
||||
accountId,
|
||||
|
||||
@@ -37,7 +37,6 @@
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
|
||||
<PackageReference Include="NodaTime" Version="3.0.5" />
|
||||
<PackageReference Include="QuantConnect.IBAutomater" Version="2.0.64" />
|
||||
<PackageReference Include="RestSharp" Version="106.12.0" />
|
||||
</ItemGroup>
|
||||
|
||||
@@ -52,7 +52,7 @@ namespace QuantConnect.Brokerages.Tradier
|
||||
var useSandbox = bool.Parse(job.BrokerageData["tradier-use-sandbox"]);
|
||||
var accountId = job.BrokerageData["tradier-account-id"];
|
||||
var accessToken = job.BrokerageData["tradier-access-token"];
|
||||
var aggregator = Composer.Instance.GetExportedValueByTypeName<IDataAggregator>(Config.Get("data-aggregator", "QuantConnect.Lean.Engine.DataFeeds.AggregationManager"));
|
||||
var aggregator = Composer.Instance.GetExportedValueByTypeName<IDataAggregator>(Config.Get("data-aggregator", "QuantConnect.Lean.Engine.DataFeeds.AggregationManager"), forceTypeNameOnExisting: false);
|
||||
|
||||
Initialize(
|
||||
wssUrl: WebSocketUrl,
|
||||
|
||||
@@ -468,7 +468,8 @@ namespace QuantConnect.Brokerages.Tradier
|
||||
request.AddParameter("symbols", csvSymbols, ParameterType.QueryString);
|
||||
|
||||
var dataContainer = Execute<TradierQuoteContainer>(request, TradierApiRequestType.Data, "quotes");
|
||||
return dataContainer.Quotes;
|
||||
// can return null quotes and not really be failing for cases where the provided symbols do not match
|
||||
return dataContainer.Quotes ?? new List<TradierQuote>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -101,7 +101,7 @@ namespace QuantConnect.Brokerages.Tradier
|
||||
algorithm,
|
||||
algorithm.Transactions,
|
||||
algorithm.Portfolio,
|
||||
Composer.Instance.GetExportedValueByTypeName<IDataAggregator>(Config.Get("data-aggregator", "QuantConnect.Lean.Engine.DataFeeds.AggregationManager")),
|
||||
Composer.Instance.GetExportedValueByTypeName<IDataAggregator>(Config.Get("data-aggregator", "QuantConnect.Lean.Engine.DataFeeds.AggregationManager"), forceTypeNameOnExisting: false),
|
||||
useSandbox,
|
||||
accountId,
|
||||
accessToken);
|
||||
|
||||
@@ -1,120 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
|
||||
namespace QuantConnect.Brokerages.Zerodha
|
||||
{
|
||||
#pragma warning disable 1591
|
||||
/// <summary>
|
||||
/// Types of product supported by Kite
|
||||
/// </summary>
|
||||
public enum KiteProductType
|
||||
{
|
||||
MIS,
|
||||
CNC,
|
||||
NRML
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Types of order supported by Kite
|
||||
/// </summary>
|
||||
public enum KiteOrderType
|
||||
{
|
||||
MARKET,
|
||||
LIMIT,
|
||||
SLM,
|
||||
SL
|
||||
}
|
||||
|
||||
public class Constants
|
||||
{
|
||||
|
||||
// Products
|
||||
public const string PRODUCT_MIS = "MIS";
|
||||
public const string PRODUCT_CNC = "CNC";
|
||||
public const string PRODUCT_NRML = "NRML";
|
||||
|
||||
// Order types
|
||||
public const string ORDER_TYPE_MARKET = "MARKET";
|
||||
public const string ORDER_TYPE_LIMIT = "LIMIT";
|
||||
public const string ORDER_TYPE_SLM = "SL-M";
|
||||
public const string ORDER_TYPE_SL = "SL";
|
||||
|
||||
// Order status
|
||||
public const string ORDER_STATUS_COMPLETE = "COMPLETE";
|
||||
public const string ORDER_STATUS_CANCELLED = "CANCELLED";
|
||||
public const string ORDER_STATUS_REJECTED = "REJECTED";
|
||||
|
||||
// Varities
|
||||
public const string VARIETY_REGULAR = "regular";
|
||||
public const string VARIETY_BO = "bo";
|
||||
public const string VARIETY_CO = "co";
|
||||
public const string VARIETY_AMO = "amo";
|
||||
|
||||
// Transaction type
|
||||
public const string TRANSACTION_TYPE_BUY = "BUY";
|
||||
public const string TRANSACTION_TYPE_SELL = "SELL";
|
||||
|
||||
// Validity
|
||||
public const string VALIDITY_DAY = "DAY";
|
||||
public const string VALIDITY_IOC = "IOC";
|
||||
|
||||
// Exchanges
|
||||
public const string EXCHANGE_NSE = "NSE";
|
||||
public const string EXCHANGE_BSE = "BSE";
|
||||
public const string EXCHANGE_NFO = "NFO";
|
||||
public const string EXCHANGE_CDS = "CDS";
|
||||
public const string EXCHANGE_BFO = "BFO";
|
||||
public const string EXCHANGE_MCX = "MCX";
|
||||
|
||||
// Margins segments
|
||||
public const string MARGIN_EQUITY = "equity";
|
||||
public const string MARGIN_COMMODITY = "commodity";
|
||||
|
||||
// Ticker modes
|
||||
public const string MODE_FULL = "full";
|
||||
public const string MODE_QUOTE = "quote";
|
||||
public const string MODE_LTP = "ltp";
|
||||
|
||||
// Positions
|
||||
public const string POSITION_DAY = "day";
|
||||
public const string POSITION_OVERNIGHT = "overnight";
|
||||
|
||||
// Historical intervals
|
||||
public const string INTERVAL_MINUTE = "minute";
|
||||
public const string INTERVAL_3MINUTE = "3minute";
|
||||
public const string INTERVAL_5MINUTE = "5minute";
|
||||
public const string INTERVAL_10MINUTE = "10minute";
|
||||
public const string INTERVAL_15MINUTE = "15minute";
|
||||
public const string INTERVAL_30MINUTE = "30minute";
|
||||
public const string INTERVAL_60MINUTE = "60minute";
|
||||
public const string INTERVAL_DAY = "day";
|
||||
|
||||
// GTT status
|
||||
public const string GTT_ACTIVE = "active";
|
||||
public const string GTT_TRIGGERED = "triggered";
|
||||
public const string GTT_DISABLED = "disabled";
|
||||
public const string GTT_EXPIRED = "expired";
|
||||
public const string GTT_CANCELLED = "cancelled";
|
||||
public const string GTT_REJECTED = "rejected";
|
||||
public const string GTT_DELETED = "deleted";
|
||||
|
||||
|
||||
// GTT trigger type
|
||||
public const string GTT_TRIGGER_OCO = "two-leg";
|
||||
public const string GTT_TRIGGER_SINGLE = "single";
|
||||
}
|
||||
#pragma warning restore 1591
|
||||
}
|
||||
@@ -1,60 +0,0 @@
|
||||
/*
|
||||
* 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 System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace QuantConnect.Brokerages.Zerodha
|
||||
{
|
||||
internal static partial class ExceptionExtensions
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Returns a list of all the exception messages from the top-level
|
||||
/// exception down through all the inner exceptions. Useful for making
|
||||
/// logs and error pages easier to read when dealing with exceptions.
|
||||
/// Usage: Exception.Messages()
|
||||
/// </summary>
|
||||
public static IEnumerable<string> Messages(this Exception ex)
|
||||
{
|
||||
// return an empty sequence if the provided exception is null
|
||||
if (ex == null) { yield break; }
|
||||
// first return THIS exception's message at the beginning of the list
|
||||
yield return ex.Message;
|
||||
// then get all the lower-level exception messages recursively (if any)
|
||||
IEnumerable<Exception> innerExceptions = Enumerable.Empty<Exception>();
|
||||
|
||||
if (ex is AggregateException && (ex as AggregateException).InnerExceptions.Any())
|
||||
{
|
||||
innerExceptions = (ex as AggregateException).InnerExceptions;
|
||||
}
|
||||
else if (ex.InnerException != null)
|
||||
{
|
||||
innerExceptions = new Exception[] { ex.InnerException };
|
||||
}
|
||||
|
||||
foreach (var innerEx in innerExceptions)
|
||||
{
|
||||
foreach (string msg in innerEx.Messages())
|
||||
{
|
||||
yield return msg;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,87 +0,0 @@
|
||||
/*
|
||||
* 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 System;
|
||||
using System.Net;
|
||||
|
||||
namespace QuantConnect.Brokerages.Zerodha
|
||||
{
|
||||
#pragma warning disable 1591
|
||||
/// <summary>
|
||||
/// KiteAPI Exceptions
|
||||
/// </summary>
|
||||
public class KiteException : Exception
|
||||
{
|
||||
HttpStatusCode status;
|
||||
public KiteException(string message, HttpStatusCode httpStatus, Exception innerException = null) : base(message, innerException) { status = httpStatus; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// General Exceptions
|
||||
/// </summary>
|
||||
public class GeneralException : KiteException
|
||||
{
|
||||
public GeneralException(string message, HttpStatusCode httpStatus = HttpStatusCode.InternalServerError, Exception innerException = null) : base(message, httpStatus, innerException) { }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Token Exceptions
|
||||
/// </summary>
|
||||
public class TokenException : KiteException
|
||||
{
|
||||
public TokenException(string message, HttpStatusCode httpStatus = HttpStatusCode.Forbidden, Exception innerException = null) : base(message, httpStatus, innerException) { }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Permission Exceptions
|
||||
/// </summary>
|
||||
public class PermissionException : KiteException
|
||||
{
|
||||
public PermissionException(string message, HttpStatusCode httpStatus = HttpStatusCode.Forbidden, Exception innerException = null) : base(message, httpStatus, innerException) { }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Order Exceptions
|
||||
/// </summary>
|
||||
public class OrderException : KiteException
|
||||
{
|
||||
public OrderException(string message, HttpStatusCode httpStatus = HttpStatusCode.BadRequest, Exception innerException = null) : base(message, httpStatus, innerException) { }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// InputExceptions
|
||||
/// </summary>
|
||||
public class InputException : KiteException
|
||||
{
|
||||
public InputException(string message, HttpStatusCode httpStatus = HttpStatusCode.BadRequest, Exception innerException = null) : base(message, httpStatus, innerException) { }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// DataExceptions
|
||||
/// </summary>
|
||||
public class DataException : KiteException
|
||||
{
|
||||
public DataException(string message, HttpStatusCode httpStatus = HttpStatusCode.BadGateway, Exception innerException = null) : base(message, httpStatus, innerException) { }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Network Exceptions
|
||||
/// </summary>
|
||||
public class NetworkException : KiteException
|
||||
{
|
||||
public NetworkException(string message, HttpStatusCode httpStatus = HttpStatusCode.ServiceUnavailable, Exception innerException = null) : base(message, httpStatus, innerException) { }
|
||||
}
|
||||
#pragma warning restore 1591
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,189 +0,0 @@
|
||||
/*
|
||||
* 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 System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
using System.IO;
|
||||
using System.Web;
|
||||
using System.Text.RegularExpressions;
|
||||
using Newtonsoft.Json;
|
||||
using System.Globalization;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace QuantConnect.Brokerages.Zerodha
|
||||
{
|
||||
/// <summary>
|
||||
/// Zerodha utility class
|
||||
/// </summary>
|
||||
public class Utils
|
||||
{
|
||||
/// <summary>
|
||||
/// Convert string to Date object
|
||||
/// </summary>
|
||||
/// <param name="dateString">Date string.</param>
|
||||
/// <returns>Date object/</returns>
|
||||
public static DateTime? StringToDate(string dateString)
|
||||
{
|
||||
if (dateString == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
return DateTime.ParseExact(dateString, dateString.Length == 10 ? "yyyy-MM-dd" : "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Serialize C# object to JSON string.
|
||||
/// </summary>
|
||||
/// <param name="obj">C# object to serialize.</param>
|
||||
/// <returns>JSON string/</returns>
|
||||
public static string JsonSerialize(object obj)
|
||||
{
|
||||
string json = JsonConvert.SerializeObject(obj);
|
||||
MatchCollection mc = Regex.Matches(json, @"\\/Date\((\d*?)\)\\/");
|
||||
foreach (Match m in mc)
|
||||
{
|
||||
var unix = Convert.ToInt64(m.Groups[1].Value,CultureInfo.InvariantCulture) / 1000;
|
||||
json = json.Replace(m.Groups[0].Value, UnixToDateTime(unix).ToStringInvariant());
|
||||
}
|
||||
return json;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deserialize Json string to nested string dictionary.
|
||||
/// </summary>
|
||||
/// <param name="Json">Json string to deserialize.</param>
|
||||
/// <returns>Json in the form of nested string dictionary.</returns>
|
||||
public static JObject JsonDeserialize(string Json)
|
||||
{
|
||||
JObject jObject = JObject.Parse(Json);
|
||||
return jObject;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Recursively traverses an object and converts double fields to decimal.
|
||||
/// This is used in Json deserialization. JavaScriptSerializer converts floats
|
||||
/// in exponential notation to double and everthing else to double. This function
|
||||
/// makes everything decimal. Currently supports only Dictionary and Array as input.
|
||||
/// </summary>
|
||||
/// <param name="obj">Input object.</param>
|
||||
/// <returns>Object with decimals instead of doubles</returns>
|
||||
public static dynamic DoubleToDecimal(dynamic obj)
|
||||
{
|
||||
if (obj is double)
|
||||
{
|
||||
obj = Convert.ToDecimal(obj);
|
||||
}
|
||||
else if (obj is IDictionary)
|
||||
{
|
||||
var keys = new List<string>(obj.Keys);
|
||||
for (int i = 0; i < keys.Count; i++)
|
||||
{
|
||||
obj[keys[i]] = DoubleToDecimal(obj[keys[i]]);
|
||||
}
|
||||
}
|
||||
else if (obj is ICollection)
|
||||
{
|
||||
obj = new ArrayList(obj);
|
||||
for (int i = 0; i < obj.Count; i++)
|
||||
{
|
||||
obj[i] = DoubleToDecimal(obj[i]);
|
||||
}
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Wraps a string inside a stream
|
||||
/// </summary>
|
||||
/// <param name="value">string data</param>
|
||||
/// <returns>Stream that reads input string</returns>
|
||||
public static MemoryStream StreamFromString(string value)
|
||||
{
|
||||
return new MemoryStream(Encoding.UTF8.GetBytes(value ?? ""));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper function to add parameter to the request only if it is not null or empty
|
||||
/// </summary>
|
||||
/// <param name="Params">Dictionary to add the key-value pair</param>
|
||||
/// <param name="Key">Key of the parameter</param>
|
||||
/// <param name="Value">Value of the parameter</param>
|
||||
public static void AddIfNotNull(Dictionary<string, dynamic> Params, string Key, string Value)
|
||||
{
|
||||
if (!String.IsNullOrEmpty(Value))
|
||||
Params.Add(Key, Value);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Creates key=value with url encoded value
|
||||
/// </summary>
|
||||
/// <param name="Key">Key</param>
|
||||
/// <param name="Value">Value</param>
|
||||
/// <returns>Combined string</returns>
|
||||
public static string BuildParam(string Key, dynamic Value)
|
||||
{
|
||||
if (Value is string)
|
||||
{
|
||||
return HttpUtility.UrlEncode(Key) + "=" + HttpUtility.UrlEncode((string)Value);
|
||||
}
|
||||
else
|
||||
{
|
||||
string[] values = (string[])Value;
|
||||
return String.Join("&", values.Select(x => HttpUtility.UrlEncode(Key) + "=" + HttpUtility.UrlEncode(x)));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Convert Unix TimeStamp to DateTime
|
||||
/// </summary>
|
||||
/// <param name="unixTimeStamp">Timestamp to convert</param>
|
||||
/// <returns><see cref="DateTime"/> object representing the timestamp</returns>
|
||||
public static DateTime UnixToDateTime(long unixTimeStamp)
|
||||
{
|
||||
// Unix timestamp is seconds past epoch
|
||||
DateTime dateTime = new DateTime(1970, 1, 1, 5, 30, 0, 0, DateTimeKind.Unspecified);
|
||||
dateTime = dateTime.AddSeconds(unixTimeStamp);
|
||||
return dateTime;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Convert ArrayList to list of <see cref="decimal"/>
|
||||
/// </summary>
|
||||
/// <param name="arrayList"><see cref="ArrayList"/> to convert</param>
|
||||
/// <returns>List of <see cref="decimal"/>s</returns>
|
||||
public static List<decimal> ToDecimalList(ArrayList arrayList)
|
||||
{
|
||||
var res = new List<decimal>();
|
||||
foreach(var i in arrayList)
|
||||
{
|
||||
res.Add(Convert.ToDecimal(i,CultureInfo.InvariantCulture));
|
||||
}
|
||||
return res;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,102 +0,0 @@
|
||||
/*
|
||||
* 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.Configuration;
|
||||
using QuantConnect.Data;
|
||||
using QuantConnect.Packets;
|
||||
using QuantConnect.Util;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace QuantConnect.Brokerages.Zerodha
|
||||
{
|
||||
/// <summary>
|
||||
/// ZerodhaBrokerage: IDataQueueHandler implementation
|
||||
/// </summary>
|
||||
public partial class ZerodhaBrokerage
|
||||
{
|
||||
#region IDataQueueHandler implementation
|
||||
|
||||
/// <summary>
|
||||
/// Sets the job we're subscribing for
|
||||
/// </summary>
|
||||
/// <param name="job">Job we're subscribing for</param>
|
||||
public void SetJob(LiveNodePacket job)
|
||||
{
|
||||
Initialize(
|
||||
job.BrokerageData["zerodha-trading-segment"],
|
||||
job.BrokerageData["zerodha-product-type"],
|
||||
job.BrokerageData["zerodha-api-key"],
|
||||
job.BrokerageData["zerodha-access-token"],
|
||||
null,
|
||||
null,
|
||||
Composer.Instance.GetExportedValueByTypeName<IDataAggregator>(Config.Get("data-aggregator", "QuantConnect.Lean.Engine.DataFeeds.AggregationManager"))
|
||||
);
|
||||
|
||||
if (!IsConnected)
|
||||
{
|
||||
Connect();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Subscribe to the specified configuration
|
||||
/// </summary>
|
||||
/// <param name="dataConfig">defines the parameters to subscribe to a data feed</param>
|
||||
/// <param name="newDataAvailableHandler">handler to be fired on new data available</param>
|
||||
/// <returns>The new enumerator for this subscription request</returns>
|
||||
public IEnumerator<BaseData> Subscribe(SubscriptionDataConfig dataConfig, EventHandler newDataAvailableHandler)
|
||||
{
|
||||
var symbol = dataConfig.Symbol;
|
||||
if (!CanSubscribe(symbol))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var enumerator = _aggregator.Add(dataConfig, newDataAvailableHandler);
|
||||
SubscriptionManager.Subscribe(dataConfig);
|
||||
|
||||
return enumerator;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// UnSubscribe to the specified configuration
|
||||
/// </summary>
|
||||
/// <param name="dataConfig">defines the parameters to subscribe to a data feed</param>
|
||||
public void Unsubscribe(SubscriptionDataConfig dataConfig)
|
||||
{
|
||||
SubscriptionManager.Unsubscribe(dataConfig);
|
||||
_aggregator.Remove(dataConfig);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if this data provide can handle the specified symbol
|
||||
/// </summary>
|
||||
/// <param name="symbol">The symbol to be handled</param>
|
||||
/// <returns>True if this data provider can get data for the symbol, false otherwise</returns>
|
||||
private static bool CanSubscribe(Symbol symbol)
|
||||
{
|
||||
var market = symbol.ID.Market;
|
||||
var securityType = symbol.ID.SecurityType;
|
||||
if (symbol.Value.IndexOfInvariant("universe", true) != -1) return false;
|
||||
// Include future options as a special case with no matching market, otherwise
|
||||
// our subscriptions are removed without any sort of notice.
|
||||
return
|
||||
(securityType == SecurityType.Equity) && (market == Market.India);
|
||||
}
|
||||
|
||||
#endregion IDataQueueHandler implementation
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,92 +0,0 @@
|
||||
/*
|
||||
* 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 System;
|
||||
using System.Collections.Generic;
|
||||
using QuantConnect.Configuration;
|
||||
using QuantConnect.Data;
|
||||
using QuantConnect.Interfaces;
|
||||
using QuantConnect.Securities;
|
||||
using QuantConnect.Util;
|
||||
|
||||
namespace QuantConnect.Brokerages.Zerodha
|
||||
{
|
||||
/// <summary>
|
||||
/// Factory method to create Zerodha Websockets brokerage
|
||||
/// </summary>
|
||||
public class ZerodhaBrokerageFactory : BrokerageFactory
|
||||
{
|
||||
/// <summary>
|
||||
/// Factory constructor
|
||||
/// </summary>
|
||||
public ZerodhaBrokerageFactory() : base(typeof(ZerodhaBrokerage))
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Not required
|
||||
/// </summary>
|
||||
public override void Dispose()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// provides brokerage connection data
|
||||
/// </summary>
|
||||
public override Dictionary<string, string> BrokerageData => new Dictionary<string, string>
|
||||
{
|
||||
{ "zerodha-api-key", Config.Get("zerodha-api-key")},
|
||||
{ "zerodha-access-token", Config.Get("zerodha-access-token")},
|
||||
{ "zerodha-trading-segment", Config.Get("zerodha-trading-segment")},
|
||||
{ "zerodha-product-type", Config.Get("zerodha-product-type")},
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// The brokerage model
|
||||
/// </summary>
|
||||
/// <param name="orderProvider">The order provider</param>
|
||||
public override IBrokerageModel GetBrokerageModel(IOrderProvider orderProvider) => new ZerodhaBrokerageModel();
|
||||
|
||||
/// <summary>
|
||||
/// Create the Brokerage instance
|
||||
/// </summary>
|
||||
/// <param name="job"></param>
|
||||
/// <param name="algorithm"></param>
|
||||
/// <returns></returns>
|
||||
public override IBrokerage CreateBrokerage(Packets.LiveNodePacket job, IAlgorithm algorithm)
|
||||
{
|
||||
var required = new[] { "zerodha-api-key", "zerodha-access-token", "zerodha-trading-segment"};
|
||||
|
||||
foreach (var item in required)
|
||||
{
|
||||
if (string.IsNullOrEmpty(job.BrokerageData[item]))
|
||||
throw new Exception($"ZerodhaBrokerageFactory.CreateBrokerage: Missing {item} in config.json");
|
||||
}
|
||||
|
||||
var brokerage = new ZerodhaBrokerage(
|
||||
job.BrokerageData["zerodha-trading-segment"],
|
||||
job.BrokerageData["zerodha-product-type"],
|
||||
job.BrokerageData["zerodha-api-key"],
|
||||
job.BrokerageData["zerodha-access-token"],
|
||||
algorithm,
|
||||
algorithm.Portfolio,
|
||||
Composer.Instance.GetExportedValueByTypeName<IDataAggregator>(Config.Get("data-aggregator", "QuantConnect.Lean.Engine.DataFeeds.AggregationManager"))
|
||||
);
|
||||
//Add the brokerage to the composer to ensure its accessible to the live data feed.
|
||||
Composer.Instance.AddPart<IDataQueueHandler>(brokerage);
|
||||
return brokerage;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,393 +0,0 @@
|
||||
/*
|
||||
* 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 System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using QuantConnect.Brokerages.Zerodha.Messages;
|
||||
using QuantConnect.Util;
|
||||
|
||||
namespace QuantConnect.Brokerages.Zerodha
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides the mapping between Lean symbols and Zerodha symbols.
|
||||
/// </summary>
|
||||
public class ZerodhaSymbolMapper : ISymbolMapper
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Symbols that are Tradable
|
||||
/// </summary>
|
||||
public List<Symbol> KnownSymbols
|
||||
{
|
||||
get
|
||||
{
|
||||
return KnownSymbolsList;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Custom class to store information about symbols
|
||||
/// </summary>
|
||||
private class SymbolData
|
||||
{
|
||||
/// <summary>
|
||||
/// Stores exchange name for the tradingSymbol
|
||||
/// </summary>
|
||||
public string Exchange { get; set;}
|
||||
|
||||
/// <summary>
|
||||
/// Stores instrumentToken name for the tradingSymbol
|
||||
/// </summary>
|
||||
public uint InstrumentToken {get; set;}
|
||||
|
||||
/// <summary>
|
||||
/// Initalize values to the class attributes
|
||||
/// </summary>
|
||||
public SymbolData(uint token, string exchangeName)
|
||||
{
|
||||
Exchange = exchangeName;
|
||||
InstrumentToken = token;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The list of known Zerodha symbols.
|
||||
/// </summary>
|
||||
private List<Symbol> KnownSymbolsList = new List<Symbol>();
|
||||
|
||||
/// <summary>
|
||||
/// Mapping between brokerageSymbol and a list of all available SymbolData objects for the brokerageSymbol.
|
||||
/// </summary>
|
||||
private Dictionary<string, List<SymbolData>> ZerodhaInstrumentsList = new Dictionary<string, List<SymbolData>>();
|
||||
|
||||
/// <summary>
|
||||
/// Mapping between instrumentToken and it's market segment ( E.g: 408065-> nse)
|
||||
/// </summary>
|
||||
private Dictionary<uint,string> ZerodhaInstrumentsExchangeMapping = new Dictionary<uint,string>();
|
||||
|
||||
/// <summary>
|
||||
/// Constructs default instance of the Zerodha Sybol Mapper
|
||||
/// </summary>
|
||||
public ZerodhaSymbolMapper(Kite kite, string exchange = "")
|
||||
{
|
||||
KnownSymbolsList = GetTradableInstrumentsList(kite, exchange);
|
||||
}
|
||||
/// <summary>
|
||||
/// Get list of tradable symbol
|
||||
/// </summary>
|
||||
/// <param name="kite">Kite</param>
|
||||
/// <param name="exchange">Exchange</param>
|
||||
/// <returns></returns>
|
||||
private List<Symbol> GetTradableInstrumentsList(Kite kite, string exchange = "")
|
||||
{
|
||||
|
||||
var tradableInstruments = kite.GetInstruments(exchange);
|
||||
var symbols = new List<Symbol>();
|
||||
var zerodhaInstrumentsMapping = new Dictionary<string, List<SymbolData>>();
|
||||
var zerodhaTokenExchangeDict = new Dictionary<uint,string>();
|
||||
|
||||
foreach (var tp in tradableInstruments)
|
||||
{
|
||||
var securityType = SecurityType.Equity;
|
||||
var market = Market.India;
|
||||
zerodhaTokenExchangeDict[tp.InstrumentToken] = tp.Exchange.ToLowerInvariant();
|
||||
OptionRight optionRight = 0;
|
||||
|
||||
switch (tp.InstrumentType)
|
||||
{
|
||||
//Equities
|
||||
case "EQ":
|
||||
securityType = SecurityType.Equity;
|
||||
break;
|
||||
//Call Options
|
||||
case "CE":
|
||||
securityType = SecurityType.Option;
|
||||
optionRight = OptionRight.Call;
|
||||
break;
|
||||
//Put Options
|
||||
case "PE":
|
||||
securityType = SecurityType.Option;
|
||||
optionRight = OptionRight.Put;
|
||||
break;
|
||||
//Stock Futures
|
||||
case "FUT":
|
||||
securityType = SecurityType.Future;
|
||||
break;
|
||||
default:
|
||||
securityType = SecurityType.Base;
|
||||
break;
|
||||
}
|
||||
|
||||
if (securityType == SecurityType.Option)
|
||||
{
|
||||
var strikePrice = tp.Strike;
|
||||
var expiryDate = tp.Expiry;
|
||||
//TODO: Handle parsing of BCDOPT strike price
|
||||
if(tp.Segment!= "BCD-OPT")
|
||||
{
|
||||
var symbol = GetLeanSymbol(tp.Name.Trim().Replace(" ", ""), securityType, market, (DateTime)expiryDate, GetStrikePrice(tp), optionRight);
|
||||
symbols.Add(symbol);
|
||||
var cleanSymbol = tp.TradingSymbol.Trim().Replace(" ", "");
|
||||
if (!zerodhaInstrumentsMapping.ContainsKey(cleanSymbol))
|
||||
{
|
||||
zerodhaInstrumentsMapping[cleanSymbol] = new List<SymbolData>();
|
||||
}
|
||||
zerodhaInstrumentsMapping[cleanSymbol].Add(new SymbolData(tp.InstrumentToken,market));
|
||||
}
|
||||
}
|
||||
if (securityType == SecurityType.Future)
|
||||
{
|
||||
var expiryDate = tp.Expiry;
|
||||
var cleanSymbol = tp.TradingSymbol.Trim().Replace(" ", "");
|
||||
var symbol = GetLeanSymbol(cleanSymbol, securityType, market, (DateTime)expiryDate);
|
||||
symbols.Add(symbol);
|
||||
if (!zerodhaInstrumentsMapping.ContainsKey(cleanSymbol))
|
||||
{
|
||||
zerodhaInstrumentsMapping[cleanSymbol] = new List<SymbolData>();
|
||||
}
|
||||
zerodhaInstrumentsMapping[cleanSymbol].Add(new SymbolData(tp.InstrumentToken,market));
|
||||
}
|
||||
if (securityType == SecurityType.Equity)
|
||||
{
|
||||
var cleanSymbol = tp.TradingSymbol.Trim().Replace(" ", "");
|
||||
var symbol = GetLeanSymbol(cleanSymbol, securityType, market);
|
||||
symbols.Add(symbol);
|
||||
if (!zerodhaInstrumentsMapping.ContainsKey(cleanSymbol))
|
||||
{
|
||||
zerodhaInstrumentsMapping[cleanSymbol] = new List<SymbolData>();
|
||||
}
|
||||
zerodhaInstrumentsMapping[cleanSymbol].Add(new SymbolData(tp.InstrumentToken,market));
|
||||
}
|
||||
}
|
||||
ZerodhaInstrumentsList = zerodhaInstrumentsMapping;
|
||||
ZerodhaInstrumentsExchangeMapping = zerodhaTokenExchangeDict;
|
||||
return symbols;
|
||||
}
|
||||
|
||||
private decimal GetStrikePrice(CsvInstrument scrip)
|
||||
{
|
||||
var strikePrice = scrip.TradingSymbol.Trim().Replace(" ", "").Replace(scrip.Name, "");
|
||||
var strikePriceTemp = strikePrice.Substring(5, strikePrice.Length - 5);
|
||||
var strikePriceResult = strikePriceTemp.Substring(0, strikePriceTemp.Length - 2);
|
||||
|
||||
return Convert.ToDecimal(strikePriceResult, CultureInfo.InvariantCulture);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts a Lean symbol instance to an Zerodha symbol
|
||||
/// </summary>
|
||||
/// <param name="symbol">A Lean symbol instance</param>
|
||||
/// <returns>The Zerodha symbol</returns>
|
||||
public string GetBrokerageSymbol(Symbol symbol)
|
||||
{
|
||||
if (symbol == null || string.IsNullOrWhiteSpace(symbol.Value))
|
||||
{
|
||||
throw new ArgumentException("Invalid symbol: " + (symbol == null ? "null" : symbol.ToString()));
|
||||
}
|
||||
|
||||
if (symbol.ID.SecurityType != SecurityType.Equity && symbol.ID.SecurityType != SecurityType.Future && symbol.ID.SecurityType != SecurityType.Option)
|
||||
{
|
||||
throw new ArgumentException("Invalid security type: " + symbol.ID.SecurityType);
|
||||
}
|
||||
|
||||
var brokerageSymbol = ConvertLeanSymbolToZerodhaSymbol(symbol.Value);
|
||||
|
||||
return brokerageSymbol;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Converts an Zerodha symbol to a Lean symbol instance
|
||||
/// </summary>
|
||||
/// <param name="brokerageSymbol">The Zerodha symbol</param>
|
||||
/// <param name="securityType">The security type</param>
|
||||
/// <param name="market">The market</param>
|
||||
/// <param name="expirationDate">Expiration date of the security(if applicable)</param>
|
||||
/// <param name="strike">The strike of the security (if applicable)</param>
|
||||
/// <param name="optionRight">The option right of the security (if applicable)</param>
|
||||
/// <returns>A new Lean Symbol instance</returns>
|
||||
public Symbol GetLeanSymbol(string brokerageSymbol, SecurityType securityType, string market, DateTime expirationDate = default(DateTime), decimal strike = 0, OptionRight optionRight = OptionRight.Call)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(brokerageSymbol))
|
||||
{
|
||||
throw new ArgumentException($"Invalid Zerodha symbol: {brokerageSymbol}");
|
||||
}
|
||||
|
||||
if (securityType == SecurityType.Forex || securityType == SecurityType.Cfd || securityType == SecurityType.Commodity || securityType == SecurityType.Crypto)
|
||||
{
|
||||
throw new ArgumentException($"Invalid security type: {securityType}");
|
||||
}
|
||||
|
||||
if (!Market.Encode(market).HasValue)
|
||||
{
|
||||
throw new ArgumentException($"Invalid market: {market}");
|
||||
}
|
||||
var cleanSymbol = brokerageSymbol.Replace(" ", "").Trim();
|
||||
|
||||
switch (securityType)
|
||||
{
|
||||
case SecurityType.Option:
|
||||
OptionStyle optionStyle = OptionStyle.European;
|
||||
return Symbol.CreateOption(cleanSymbol, market, optionStyle, optionRight, strike, expirationDate);
|
||||
case SecurityType.Future:
|
||||
return Symbol.CreateFuture(cleanSymbol, market, expirationDate);
|
||||
default:
|
||||
return Symbol.Create(cleanSymbol, securityType, market);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Converts an Zerodha symbol to a Lean symbol instance
|
||||
/// </summary>
|
||||
/// <param name="brokerageSymbol">The Zerodha symbol</param>
|
||||
/// <returns>A new Lean Symbol instance</returns>
|
||||
public Symbol GetLeanSymbol(string brokerageSymbol)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(brokerageSymbol))
|
||||
{
|
||||
throw new ArgumentException($"Invalid Zerodha symbol: {brokerageSymbol}");
|
||||
}
|
||||
|
||||
var cleanSymbol = brokerageSymbol.Replace(" ", "").Trim();
|
||||
|
||||
if (IsKnownBrokerageSymbol(cleanSymbol))
|
||||
{
|
||||
throw new ArgumentException($"Symbol not present : {cleanSymbol}");
|
||||
}
|
||||
|
||||
var symbol = KnownSymbols.FirstOrDefault(s => s.Value == cleanSymbol);
|
||||
var exchange = GetZerodhaDefaultExchange(cleanSymbol);
|
||||
return GetLeanSymbol(cleanSymbol, symbol.SecurityType, exchange);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fetches the trading segment inside India Market, E.g: NSE, BSE for the given Instrument Token
|
||||
/// </summary>
|
||||
/// <param name="Token">The Zerodha Instrument Token</param>
|
||||
/// <returns>An exchange value for the given token</returns>
|
||||
public string GetZerodhaExchangeFromToken(uint Token)
|
||||
{
|
||||
string exchange = string.Empty;
|
||||
if (ZerodhaInstrumentsExchangeMapping.ContainsKey(Token))
|
||||
{
|
||||
ZerodhaInstrumentsExchangeMapping.TryGetValue(Token, out exchange);
|
||||
}
|
||||
return exchange;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Fetches the first available Exchage value for the given symbol from list of possible exchanges
|
||||
/// </summary>
|
||||
/// <param name="brokerageSymbol">The Zerodha symbol</param>
|
||||
/// <returns>A default exchange value for the given ticker</returns>
|
||||
private string GetZerodhaDefaultExchange(string brokerageSymbol)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(brokerageSymbol))
|
||||
{
|
||||
throw new ArgumentException($"Invalid Zerodha symbol: {brokerageSymbol}");
|
||||
}
|
||||
|
||||
var cleanSymbol = brokerageSymbol.Replace(" ", "").Trim();
|
||||
|
||||
List<SymbolData> tempSymbolDataList;
|
||||
if (ZerodhaInstrumentsList.TryGetValue(cleanSymbol, out tempSymbolDataList))
|
||||
{
|
||||
return tempSymbolDataList[0].Exchange;
|
||||
}
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts Lean symbol to a List of Zerodha Instrument Tokens available from various exchange
|
||||
/// </summary>
|
||||
/// <param name="brokerageSymbol">The Zerodha symbol</param>
|
||||
/// <returns>A list of Zerodha Instrument Tokens</returns>
|
||||
public List<uint> GetZerodhaInstrumentTokenList(string brokerageSymbol)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(brokerageSymbol))
|
||||
{
|
||||
throw new ArgumentException($"Invalid Zerodha symbol: {brokerageSymbol}");
|
||||
}
|
||||
|
||||
var cleanSymbol = brokerageSymbol.Replace(" ", "").Trim();
|
||||
|
||||
List<uint> tokenList = new List<uint>();
|
||||
List<SymbolData> tempSymbolDataList;
|
||||
if (ZerodhaInstrumentsList.TryGetValue(cleanSymbol, out tempSymbolDataList))
|
||||
{
|
||||
foreach (var sd in tempSymbolDataList)
|
||||
{
|
||||
tokenList.Add(sd.InstrumentToken);
|
||||
}
|
||||
}
|
||||
return tokenList;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the symbol is supported by Zerodha
|
||||
/// </summary>
|
||||
/// <param name="brokerageSymbol">The Zerodha symbol</param>
|
||||
/// <returns>True if Zerodha supports the symbol</returns>
|
||||
private bool IsKnownBrokerageSymbol(string brokerageSymbol)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(brokerageSymbol))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return KnownSymbolsList.Where(x => x.Value.Contains(brokerageSymbol)).IsNullOrEmpty();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts an Zerodha symbol to a Lean symbol string
|
||||
/// </summary>
|
||||
public Symbol ConvertZerodhaSymbolToLeanSymbol(uint ZerodhaSymbol)
|
||||
{
|
||||
var _symbol = string.Empty;
|
||||
foreach (var item in ZerodhaInstrumentsList)
|
||||
{
|
||||
foreach( var sd in item.Value)
|
||||
{
|
||||
if (sd.InstrumentToken == ZerodhaSymbol)
|
||||
{
|
||||
_symbol = item.Key;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// return as it is due to Zerodha has similar Symbol format
|
||||
return KnownSymbolsList.Where(s => s.Value == _symbol).FirstOrDefault();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts a Lean symbol string to an Zerodha symbol
|
||||
/// </summary>
|
||||
private static string ConvertLeanSymbolToZerodhaSymbol(string leanSymbol)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(leanSymbol))
|
||||
{
|
||||
throw new ArgumentException($"Invalid Lean symbol: {leanSymbol}");
|
||||
}
|
||||
|
||||
// return as it is due to Zerodha has similar Symbol format
|
||||
return leanSymbol.ToUpperInvariant();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -40,6 +40,7 @@ from QuantConnect.Python import *
|
||||
from QuantConnect.Storage import *
|
||||
from QuantConnect.Research import *
|
||||
from QuantConnect.Algorithm import *
|
||||
from QuantConnect.Statistics import *
|
||||
from QuantConnect.Parameters import *
|
||||
from QuantConnect.Benchmarks import *
|
||||
from QuantConnect.Brokerages import *
|
||||
|
||||
@@ -167,7 +167,7 @@ namespace QuantConnect.Brokerages
|
||||
return 1m;
|
||||
}
|
||||
|
||||
if (security.Type == SecurityType.Equity || security.Type == SecurityType.Future || security.Type == SecurityType.Option)
|
||||
if (security.Type == SecurityType.Equity || security.Type == SecurityType.Future || security.Type == SecurityType.Option || security.Type == SecurityType.Index)
|
||||
{
|
||||
return _maxLeverage;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/*
|
||||
/*
|
||||
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
|
||||
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
|
||||
*
|
||||
@@ -164,7 +164,7 @@ namespace QuantConnect.Brokerages
|
||||
return 1m;
|
||||
}
|
||||
|
||||
if (security.Type == SecurityType.Equity || security.Type == SecurityType.Future || security.Type == SecurityType.Option)
|
||||
if (security.Type == SecurityType.Equity || security.Type == SecurityType.Future || security.Type == SecurityType.Option || security.Type == SecurityType.Index)
|
||||
{
|
||||
return _maxLeverage;
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ using System;
|
||||
using NodaTime;
|
||||
using QuantConnect.Interfaces;
|
||||
using QuantConnect.Securities;
|
||||
using QuantConnect.Util;
|
||||
|
||||
namespace QuantConnect.Data
|
||||
{
|
||||
@@ -53,12 +54,21 @@ namespace QuantConnect.Data
|
||||
{
|
||||
resolution ??= subscription.Resolution;
|
||||
|
||||
var dataType = subscription.Type;
|
||||
|
||||
// if we change resolution the data type can change, for example subscription being Tick type and resolution daily
|
||||
// data type here won't be Tick anymore, but TradeBar/QuoteBar
|
||||
if (resolution.Value != subscription.Resolution && LeanData.IsCommonLeanDataType(dataType))
|
||||
{
|
||||
dataType = LeanData.GetDataType(resolution.Value, subscription.TickType);
|
||||
}
|
||||
|
||||
var request = new HistoryRequest(subscription,
|
||||
exchangeHours,
|
||||
startAlgoTz.ConvertToUtc(_algorithm.TimeZone),
|
||||
endAlgoTz.ConvertToUtc(_algorithm.TimeZone))
|
||||
{
|
||||
DataType = subscription.Type,
|
||||
DataType = dataType,
|
||||
Resolution = resolution.Value,
|
||||
FillForwardResolution = subscription.FillDataForward ? resolution : null,
|
||||
TickType = subscription.TickType
|
||||
|
||||
@@ -127,15 +127,16 @@ namespace QuantConnect.Data
|
||||
/// <param name="config">The subscription data configuration we are processing</param>
|
||||
/// <remarks>One of the objectives of this method is to normalize the 'use price scale'
|
||||
/// check and void code duplication and related issues</remarks>
|
||||
/// <param name="liveMode">True, is this is a live mode data stream</param>
|
||||
/// <returns>True if ticker prices should be scaled</returns>
|
||||
public static bool PricesShouldBeScaled(this SubscriptionDataConfig config)
|
||||
public static bool PricesShouldBeScaled(this SubscriptionDataConfig config, bool liveMode = false)
|
||||
{
|
||||
if (config.IsCustomData || config.Symbol.Value.Contains("UNIVERSE"))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if(config.SecurityType == SecurityType.Equity)
|
||||
if(config.SecurityType == SecurityType.Equity && !liveMode)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -139,6 +139,9 @@ namespace QuantConnect.Orders.Fees
|
||||
case Market.USA:
|
||||
equityFee = new EquityFee(Currencies.USD, feePerShare: 0.005m, minimumFee: 1, maximumFeeRate: 0.005m);
|
||||
break;
|
||||
case Market.India:
|
||||
equityFee = new EquityFee(Currencies.INR, feePerShare: 0.01m, minimumFee: 6, maximumFeeRate: 20);
|
||||
break;
|
||||
default:
|
||||
throw new KeyNotFoundException($"InteractiveBrokersFeeModel(): unexpected equity Market {market}");
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ using System.Reflection;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using QuantConnect.Configuration;
|
||||
using QuantConnect.Data;
|
||||
using QuantConnect.Logging;
|
||||
|
||||
namespace QuantConnect.Util
|
||||
@@ -241,8 +242,10 @@ namespace QuantConnect.Util
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the export</typeparam>
|
||||
/// <param name="typeName">The name of the type to find. This can be an assembly qualified name, a full name, or just the type's name</param>
|
||||
/// <param name="forceTypeNameOnExisting">When false, if any existing instance of type T is found, it will be returned even if type name doesn't match.
|
||||
/// This is useful in cases where a single global instance is desired, like for <see cref="IDataAggregator"/></param>
|
||||
/// <returns>The export instance</returns>
|
||||
public T GetExportedValueByTypeName<T>(string typeName)
|
||||
public T GetExportedValueByTypeName<T>(string typeName, bool forceTypeNameOnExisting = true)
|
||||
where T : class
|
||||
{
|
||||
try
|
||||
@@ -254,8 +257,8 @@ namespace QuantConnect.Util
|
||||
var type = typeof(T);
|
||||
if (_exportedValues.TryGetValue(type, out values))
|
||||
{
|
||||
// if we've alread loaded this part, then just return the same one
|
||||
instance = values.OfType<T>().FirstOrDefault(x => x.GetType().MatchesTypeName(typeName));
|
||||
// if we've already loaded this part, then just return the same one
|
||||
instance = values.OfType<T>().FirstOrDefault(x => !forceTypeNameOnExisting || x.GetType().MatchesTypeName(typeName));
|
||||
if (instance != null)
|
||||
{
|
||||
return instance;
|
||||
|
||||
@@ -38,8 +38,8 @@ namespace QuantConnect.Util
|
||||
/// The different <see cref="SecurityType"/> used for data paths
|
||||
/// </summary>
|
||||
/// <remarks>This includes 'alternative'</remarks>
|
||||
public static IReadOnlyList<string> SecurityTypeAsDataPath => Enum.GetNames(typeof(SecurityType))
|
||||
.Select(x => x.ToLowerInvariant()).Union(new[] { "alternative" }).ToList();
|
||||
public static HashSet<string> SecurityTypeAsDataPath => Enum.GetNames(typeof(SecurityType))
|
||||
.Select(x => x.ToLowerInvariant()).Union(new[] { "alternative" }).ToHashSet();
|
||||
|
||||
/// <summary>
|
||||
/// Converts the specified base data instance into a lean data file csv line.
|
||||
@@ -472,7 +472,8 @@ namespace QuantConnect.Util
|
||||
/// <see cref="QuoteBar"/> or <see cref="OpenInterest"/></returns>
|
||||
public static bool IsCommonLeanDataType(Type baseDataType)
|
||||
{
|
||||
if (baseDataType == typeof(TradeBar) ||
|
||||
if (baseDataType == typeof(Tick) ||
|
||||
baseDataType == typeof(TradeBar) ||
|
||||
baseDataType == typeof(QuoteBar) ||
|
||||
baseDataType == typeof(OpenInterest))
|
||||
{
|
||||
@@ -965,9 +966,11 @@ namespace QuantConnect.Util
|
||||
/// </summary>
|
||||
/// <param name="fileName">File name to be parsed</param>
|
||||
/// <param name="securityType">The securityType as parsed from the fileName</param>
|
||||
public static bool TryParseSecurityType(string fileName, out SecurityType securityType)
|
||||
/// <param name="market">The market as parsed from the fileName</param>
|
||||
public static bool TryParseSecurityType(string fileName, out SecurityType securityType, out string market)
|
||||
{
|
||||
securityType = SecurityType.Base;
|
||||
market = string.Empty;
|
||||
|
||||
try
|
||||
{
|
||||
@@ -976,6 +979,13 @@ namespace QuantConnect.Util
|
||||
// find the securityType and parse it
|
||||
var typeString = info.Find(x => SecurityTypeAsDataPath.Contains(x.ToLowerInvariant()));
|
||||
securityType = ParseDataSecurityType(typeString);
|
||||
|
||||
var existingMarkets = Market.SupportedMarkets();
|
||||
var foundMarket = info.Find(x => existingMarkets.Contains(x.ToLowerInvariant()));
|
||||
if (foundMarket != null)
|
||||
{
|
||||
market = foundMarket;
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
||||
BIN
Data/equity/india/minute/juniorbees/20190101_trade.zip
Normal file
BIN
Data/equity/india/minute/juniorbees/20190101_trade.zip
Normal file
Binary file not shown.
BIN
Data/equity/india/minute/juniorbees/20190102_trade.zip
Normal file
BIN
Data/equity/india/minute/juniorbees/20190102_trade.zip
Normal file
Binary file not shown.
BIN
Data/equity/india/minute/juniorbees/20190103_trade.zip
Normal file
BIN
Data/equity/india/minute/juniorbees/20190103_trade.zip
Normal file
Binary file not shown.
BIN
Data/equity/india/minute/juniorbees/20190104_trade.zip
Normal file
BIN
Data/equity/india/minute/juniorbees/20190104_trade.zip
Normal file
Binary file not shown.
BIN
Data/index/india/minute/nifty50/20190101_trade.zip
Normal file
BIN
Data/index/india/minute/nifty50/20190101_trade.zip
Normal file
Binary file not shown.
BIN
Data/index/india/minute/nifty50/20190102_trade.zip
Normal file
BIN
Data/index/india/minute/nifty50/20190102_trade.zip
Normal file
Binary file not shown.
BIN
Data/index/india/minute/nifty50/20190103_trade.zip
Normal file
BIN
Data/index/india/minute/nifty50/20190103_trade.zip
Normal file
Binary file not shown.
BIN
Data/index/india/minute/nifty50/20190104_trade.zip
Normal file
BIN
Data/index/india/minute/nifty50/20190104_trade.zip
Normal file
Binary file not shown.
@@ -36059,6 +36059,328 @@
|
||||
],
|
||||
"holidays": []
|
||||
},
|
||||
|
||||
"Index-india-[*]": {
|
||||
"dataTimeZone": "Asia/Kolkata",
|
||||
"exchangeTimeZone": "Asia/Kolkata",
|
||||
"sunday": [],
|
||||
"monday": [
|
||||
{
|
||||
"start": "09:00:00",
|
||||
"end": "09:15:00",
|
||||
"state": "premarket"
|
||||
},
|
||||
{
|
||||
"start": "09:15:00",
|
||||
"end": "15:30:00",
|
||||
"state": "market"
|
||||
},
|
||||
{
|
||||
"start": "15:40:00",
|
||||
"end": "16:00:00",
|
||||
"state": "postmarket"
|
||||
}
|
||||
],
|
||||
"tuesday": [
|
||||
{
|
||||
"start": "09:00:00",
|
||||
"end": "09:15:00",
|
||||
"state": "premarket"
|
||||
},
|
||||
{
|
||||
"start": "09:15:00",
|
||||
"end": "15:30:00",
|
||||
"state": "market"
|
||||
},
|
||||
{
|
||||
"start": "15:40:00",
|
||||
"end": "16:00:00",
|
||||
"state": "postmarket"
|
||||
}
|
||||
],
|
||||
"wednesday": [
|
||||
{
|
||||
"start": "09:00:00",
|
||||
"end": "09:15:00",
|
||||
"state": "premarket"
|
||||
},
|
||||
{
|
||||
"start": "09:15:00",
|
||||
"end": "15:30:00",
|
||||
"state": "market"
|
||||
},
|
||||
{
|
||||
"start": "15:40:00",
|
||||
"end": "16:00:00",
|
||||
"state": "postmarket"
|
||||
}
|
||||
],
|
||||
"thursday": [
|
||||
{
|
||||
"start": "09:00:00",
|
||||
"end": "09:15:00",
|
||||
"state": "premarket"
|
||||
},
|
||||
{
|
||||
"start": "09:15:00",
|
||||
"end": "15:30:00",
|
||||
"state": "market"
|
||||
},
|
||||
{
|
||||
"start": "15:40:00",
|
||||
"end": "16:00:00",
|
||||
"state": "postmarket"
|
||||
}
|
||||
],
|
||||
"friday": [
|
||||
{
|
||||
"start": "09:00:00",
|
||||
"end": "09:15:00",
|
||||
"state": "premarket"
|
||||
},
|
||||
{
|
||||
"start": "09:15:00",
|
||||
"end": "15:30:00",
|
||||
"state": "market"
|
||||
},
|
||||
{
|
||||
"start": "15:40:00",
|
||||
"end": "16:00:00",
|
||||
"state": "postmarket"
|
||||
}
|
||||
],
|
||||
"saturday": [],
|
||||
"holidays": [
|
||||
"1/26/2004",
|
||||
"4/14/2004",
|
||||
"1/26/2005",
|
||||
"4/14/2005",
|
||||
"8/15/2005",
|
||||
"1/26/2006",
|
||||
"4/14/2006",
|
||||
"5/1/2006",
|
||||
"8/15/2006",
|
||||
"10/2/2006",
|
||||
"12/25/2006",
|
||||
"1/26/2007",
|
||||
"5/1/2007",
|
||||
"8/15/2007",
|
||||
"10/2/2007",
|
||||
"12/25/2007",
|
||||
"4/14/2008",
|
||||
"5/1/2008",
|
||||
"8/15/2008",
|
||||
"10/2/2008",
|
||||
"12/25/2008",
|
||||
"1/26/2009",
|
||||
"4/14/2009",
|
||||
"5/1/2009",
|
||||
"10/2/2009",
|
||||
"12/25/2009",
|
||||
"1/26/2010",
|
||||
"4/14/2010",
|
||||
"1/26/2011",
|
||||
"3/2/2011",
|
||||
"4/12/2011",
|
||||
"4/14/2011",
|
||||
"4/22/2011",
|
||||
"8/15/2011",
|
||||
"8/31/2011",
|
||||
"9/1/2011",
|
||||
"10/6/2011",
|
||||
"10/26/2011",
|
||||
"10/27/2011",
|
||||
"11/7/2011",
|
||||
"11/10/2011",
|
||||
"12/6/2011",
|
||||
"1/26/2012",
|
||||
"2/20/2012",
|
||||
"3/8/2012",
|
||||
"4/5/2012",
|
||||
"4/6/2012",
|
||||
"5/1/2012",
|
||||
"8/15/2012",
|
||||
"8/20/2012",
|
||||
"9/19/2012",
|
||||
"10/2/2012",
|
||||
"10/24/2012",
|
||||
"11/14/2012",
|
||||
"11/28/2012",
|
||||
"12/25/2012",
|
||||
"3/27/2013",
|
||||
"3/29/2013",
|
||||
"4/19/2013",
|
||||
"4/24/2013",
|
||||
"5/1/2013",
|
||||
"8/9/2013",
|
||||
"8/15/2013",
|
||||
"9/9/2013",
|
||||
"10/2/2013",
|
||||
"10/16/2013",
|
||||
"11/4/2013",
|
||||
"11/15/2013",
|
||||
"12/25/2013",
|
||||
"2/27/2014",
|
||||
"3/17/2014",
|
||||
"4/8/2014",
|
||||
"4/14/2014",
|
||||
"4/18/2014",
|
||||
"4/24/2014",
|
||||
"5/1/2014",
|
||||
"7/29/2014",
|
||||
"8/15/2014",
|
||||
"8/29/2014",
|
||||
"10/2/2014",
|
||||
"10/3/2014",
|
||||
"10/6/2014",
|
||||
"10/15/2014",
|
||||
"10/24/2014",
|
||||
"11/4/2014",
|
||||
"11/6/2014",
|
||||
"12/25/2014",
|
||||
"1/26/2015",
|
||||
"2/17/2015",
|
||||
"3/6/2015",
|
||||
"4/2/2015",
|
||||
"4/3/2015",
|
||||
"4/14/2015",
|
||||
"5/1/2015",
|
||||
"9/17/2015",
|
||||
"9/25/2015",
|
||||
"10/2/2015",
|
||||
"10/22/2015",
|
||||
"11/12/2015",
|
||||
"11/25/2015",
|
||||
"12/25/2015",
|
||||
"1/26/2016",
|
||||
"3/7/2016",
|
||||
"3/24/2016",
|
||||
"3/25/2016",
|
||||
"4/14/2016",
|
||||
"4/15/2016",
|
||||
"4/19/2016",
|
||||
"7/6/2016",
|
||||
"8/15/2016",
|
||||
"9/5/2016",
|
||||
"9/13/2016",
|
||||
"10/11/2016",
|
||||
"10/12/2016",
|
||||
"10/31/2016",
|
||||
"11/14/2016",
|
||||
"1/26/2017",
|
||||
"2/24/2017",
|
||||
"3/13/2017",
|
||||
"4/4/2017",
|
||||
"4/14/2017",
|
||||
"5/1/2017",
|
||||
"6/26/2017",
|
||||
"8/15/2017",
|
||||
"8/25/2017",
|
||||
"10/2/2017",
|
||||
"10/20/2017",
|
||||
"12/25/2017",
|
||||
"1/26/2018",
|
||||
"2/13/2018",
|
||||
"3/2/2018",
|
||||
"3/29/2018",
|
||||
"3/30/2018",
|
||||
"5/1/2018",
|
||||
"8/15/2018",
|
||||
"8/22/2018",
|
||||
"9/13/2018",
|
||||
"9/20/2018",
|
||||
"10/2/2018",
|
||||
"10/18/2018",
|
||||
"11/8/2018",
|
||||
"11/23/2018",
|
||||
"12/25/2018",
|
||||
"3/4/2019",
|
||||
"3/21/2019",
|
||||
"4/17/2019",
|
||||
"4/19/2019",
|
||||
"4/29/2019",
|
||||
"5/1/2019",
|
||||
"6/5/2019",
|
||||
"8/12/2019",
|
||||
"8/15/2019",
|
||||
"9/2/2019",
|
||||
"9/10/2019",
|
||||
"10/2/2019",
|
||||
"10/8/2019",
|
||||
"10/21/2019",
|
||||
"10/28/2019",
|
||||
"11/12/2019",
|
||||
"12/25/2019",
|
||||
"2/21/2020",
|
||||
"3/10/2020",
|
||||
"4/2/2020",
|
||||
"4/6/2020",
|
||||
"4/10/2020",
|
||||
"4/14/2020",
|
||||
"5/1/2020",
|
||||
"5/25/2020",
|
||||
"10/2/2020",
|
||||
"11/16/2020",
|
||||
"11/30/2020",
|
||||
"12/25/2020",
|
||||
"1/26/2021",
|
||||
"3/11/2021",
|
||||
"3/29/2021",
|
||||
"4/2/2021",
|
||||
"4/14/2021",
|
||||
"4/21/2021",
|
||||
"5/13/2021",
|
||||
"7/21/2021",
|
||||
"8/19/2021",
|
||||
"9/10/2021",
|
||||
"10/15/2021",
|
||||
"11/5/2021",
|
||||
"11/19/2021",
|
||||
"1/26/2022",
|
||||
"4/14/2022",
|
||||
"8/15/2022",
|
||||
"1/26/2023",
|
||||
"4/14/2023",
|
||||
"5/1/2023",
|
||||
"8/15/2023",
|
||||
"10/2/2023",
|
||||
"12/25/2023",
|
||||
"1/26/2024",
|
||||
"5/1/2024",
|
||||
"8/15/2024",
|
||||
"10/2/2024",
|
||||
"12/25/2024",
|
||||
"4/14/2025",
|
||||
"5/1/2025",
|
||||
"8/15/2025",
|
||||
"10/2/2025",
|
||||
"12/25/2025",
|
||||
"1/26/2026",
|
||||
"4/14/2026",
|
||||
"5/1/2026",
|
||||
"10/2/2026",
|
||||
"12/25/2026",
|
||||
"1/26/2027",
|
||||
"4/14/2027",
|
||||
"1/26/2028",
|
||||
"4/14/2028",
|
||||
"5/1/2028",
|
||||
"8/15/2028",
|
||||
"10/2/2028",
|
||||
"12/25/2028",
|
||||
"1/26/2029",
|
||||
"5/1/2029",
|
||||
"8/15/2029",
|
||||
"10/2/2029",
|
||||
"12/25/2029",
|
||||
"5/1/2030",
|
||||
"8/15/2030",
|
||||
"10/2/2030",
|
||||
"12/25/2030"
|
||||
],
|
||||
"earlyCloses": {}
|
||||
},
|
||||
|
||||
"Equity-india-[*]": {
|
||||
"dataTimeZone": "Asia/Kolkata",
|
||||
"exchangeTimeZone": "Asia/Kolkata",
|
||||
|
||||
@@ -41,7 +41,8 @@ namespace QuantConnect.Lean.Engine.DataFeeds
|
||||
private readonly HashSet<SecurityType> _unsupportedSecurityType;
|
||||
private readonly DataPricesList _dataPrices;
|
||||
private readonly Api.Api _api;
|
||||
private readonly bool _subscribedToEquityMapAndFactorFiles;
|
||||
private readonly bool _subscribedToIndiaEquityMapAndFactorFiles;
|
||||
private readonly bool _subscribedToUsaEquityMapAndFactorFiles;
|
||||
private readonly bool _subscribedToFutureMapAndFactorFiles;
|
||||
private volatile bool _invalidSecurityTypeLog;
|
||||
|
||||
@@ -71,13 +72,18 @@ namespace QuantConnect.Lean.Engine.DataFeeds
|
||||
if (productItem.Id == 37)
|
||||
{
|
||||
// Determine if the user is subscribed to Equity map and factor files (Data product Id 37)
|
||||
_subscribedToEquityMapAndFactorFiles = true;
|
||||
_subscribedToUsaEquityMapAndFactorFiles = true;
|
||||
}
|
||||
else if (productItem.Id == 137)
|
||||
{
|
||||
// Determine if the user is subscribed to Future map and factor files (Data product Id 137)
|
||||
_subscribedToFutureMapAndFactorFiles = true;
|
||||
}
|
||||
else if (productItem.Id == 172)
|
||||
{
|
||||
// Determine if the user is subscribed to India map and factor files (Data product Id 172)
|
||||
_subscribedToIndiaEquityMapAndFactorFiles = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Verify user has agreed to data provider agreements
|
||||
@@ -161,7 +167,7 @@ namespace QuantConnect.Lean.Engine.DataFeeds
|
||||
}
|
||||
|
||||
// Some security types can't be downloaded, lets attempt to extract that information
|
||||
if (LeanData.TryParseSecurityType(filePath, out SecurityType securityType) && _unsupportedSecurityType.Contains(securityType))
|
||||
if (LeanData.TryParseSecurityType(filePath, out SecurityType securityType, out var market) && _unsupportedSecurityType.Contains(securityType))
|
||||
{
|
||||
// we do support future auxiliary data (map and factor files)
|
||||
if (securityType != SecurityType.Future || !IsAuxiliaryData(filePath))
|
||||
@@ -192,12 +198,20 @@ namespace QuantConnect.Lean.Engine.DataFeeds
|
||||
}
|
||||
}
|
||||
// Final check; If we want to download and the request requires equity data we need to be sure they are subscribed to map and factor files
|
||||
else if (!_subscribedToEquityMapAndFactorFiles && (securityType == SecurityType.Equity || securityType == SecurityType.Option || IsAuxiliaryData(filePath)))
|
||||
else if (!_subscribedToUsaEquityMapAndFactorFiles && market.Equals(Market.USA, StringComparison.InvariantCultureIgnoreCase)
|
||||
&& (securityType == SecurityType.Equity || securityType == SecurityType.Option || IsAuxiliaryData(filePath)))
|
||||
{
|
||||
throw new ArgumentException("ApiDataProvider(): Must be subscribed to map and factor files to use the ApiDataProvider " +
|
||||
"to download Equity data from QuantConnect. " +
|
||||
"Please visit https://www.quantconnect.com/datasets/quantconnect-security-master for details.");
|
||||
}
|
||||
else if (!_subscribedToIndiaEquityMapAndFactorFiles && market.Equals(Market.India, StringComparison.InvariantCultureIgnoreCase)
|
||||
&& (securityType == SecurityType.Equity || securityType == SecurityType.Option || IsAuxiliaryData(filePath)))
|
||||
{
|
||||
throw new ArgumentException("ApiDataProvider(): Must be subscribed to map and factor files to use the ApiDataProvider " +
|
||||
"to download India data from QuantConnect. " +
|
||||
"Please visit https://www.quantconnect.com/datasets/truedata-india-equity-security-master for details.");
|
||||
}
|
||||
}
|
||||
|
||||
return shouldDownload;
|
||||
|
||||
@@ -33,8 +33,9 @@ namespace QuantConnect.Lean.Engine.DataFeeds.Enumerators
|
||||
private readonly IEnumerator<BaseData> _rawDataEnumerator;
|
||||
private readonly SubscriptionDataConfig _config;
|
||||
private readonly IFactorFileProvider _factorFileProvider;
|
||||
private DateTime _lastTradableDate;
|
||||
private DateTime _nextTradableDate;
|
||||
private IFactorProvider _factorFile;
|
||||
private bool _liveMode;
|
||||
|
||||
/// <summary>
|
||||
/// Explicit interface implementation for <see cref="Current"/>
|
||||
@@ -57,13 +58,16 @@ namespace QuantConnect.Lean.Engine.DataFeeds.Enumerators
|
||||
/// <param name="config">The <see cref="SubscriptionDataConfig"/> to enumerate for.
|
||||
/// Will determine the <see cref="DataNormalizationMode"/> to use.</param>
|
||||
/// <param name="factorFileProvider">The <see cref="IFactorFileProvider"/> instance to use</param>
|
||||
/// <param name="liveMode">True, is this is a live mode data stream</param>
|
||||
public PriceScaleFactorEnumerator(
|
||||
IEnumerator<BaseData> rawDataEnumerator,
|
||||
SubscriptionDataConfig config,
|
||||
IFactorFileProvider factorFileProvider)
|
||||
IFactorFileProvider factorFileProvider,
|
||||
bool liveMode = false)
|
||||
{
|
||||
_lastTradableDate = DateTime.MinValue;
|
||||
_config = config;
|
||||
_liveMode = liveMode;
|
||||
_nextTradableDate = DateTime.MinValue;
|
||||
_rawDataEnumerator = rawDataEnumerator;
|
||||
_factorFileProvider = factorFileProvider;
|
||||
}
|
||||
@@ -93,11 +97,18 @@ namespace QuantConnect.Lean.Engine.DataFeeds.Enumerators
|
||||
&& _factorFileProvider != null
|
||||
&& _config.DataNormalizationMode != DataNormalizationMode.Raw)
|
||||
{
|
||||
if (Current.Time.Date > _lastTradableDate)
|
||||
if (Current.Time >= _nextTradableDate)
|
||||
{
|
||||
_factorFile = _factorFileProvider.Get(_config.Symbol);
|
||||
_lastTradableDate = Current.Time.Date;
|
||||
_config.PriceScaleFactor = _factorFile.GetPriceScale(_lastTradableDate, _config.DataNormalizationMode, _config.ContractDepthOffset, _config.DataMappingMode);
|
||||
_config.PriceScaleFactor = _factorFile.GetPriceScale(Current.Time.Date, _config.DataNormalizationMode, _config.ContractDepthOffset, _config.DataMappingMode);
|
||||
|
||||
// update factor files every day
|
||||
_nextTradableDate = Current.Time.Date.AddDays(1);
|
||||
if (_liveMode)
|
||||
{
|
||||
// in live trading we add a offset to make sure new factor files are available
|
||||
_nextTradableDate = _nextTradableDate.Add(Time.LiveAuxiliaryDataOffset);
|
||||
}
|
||||
}
|
||||
|
||||
Current = Current.Normalize(_config.PriceScaleFactor, _config.DataNormalizationMode, _config.SumOfDividends);
|
||||
|
||||
@@ -237,6 +237,17 @@ namespace QuantConnect.Lean.Engine.DataFeeds
|
||||
}
|
||||
}
|
||||
|
||||
// scale prices before 'SubscriptionFilterEnumerator' since it updates securities realtime price
|
||||
// and before fill forwarding so we don't happen to apply twice the factor
|
||||
if (request.Configuration.PricesShouldBeScaled(liveMode:true))
|
||||
{
|
||||
enumerator = new PriceScaleFactorEnumerator(
|
||||
enumerator,
|
||||
request.Configuration,
|
||||
_factorFileProvider,
|
||||
liveMode:true);
|
||||
}
|
||||
|
||||
if (request.Configuration.FillDataForward)
|
||||
{
|
||||
var fillForwardResolution = _subscriptions.UpdateAndGetFillForwardResolution(request.Configuration);
|
||||
|
||||
@@ -39,6 +39,7 @@ namespace QuantConnect.Tests.Algorithm
|
||||
private TestHistoryProvider _testHistoryProvider;
|
||||
private IDataProvider _dataProvider;
|
||||
private IMapFileProvider _mapFileProvider;
|
||||
private IDataCacheProvider _cacheProvider;
|
||||
private IFactorFileProvider _factorFileProvider;
|
||||
|
||||
[SetUp]
|
||||
@@ -47,31 +48,57 @@ namespace QuantConnect.Tests.Algorithm
|
||||
_algorithm = new QCAlgorithm();
|
||||
_algorithm.SubscriptionManager.SetDataManager(new DataManagerStub(_algorithm));
|
||||
_algorithm.HistoryProvider = _testHistoryProvider = new TestHistoryProvider();
|
||||
}
|
||||
|
||||
[OneTimeSetUp]
|
||||
public void OneTimeSetUp()
|
||||
{
|
||||
_dataProvider = TestGlobals.DataProvider;
|
||||
_mapFileProvider = TestGlobals.MapFileProvider;
|
||||
_factorFileProvider = TestGlobals.FactorFileProvider;
|
||||
_cacheProvider = new ZipDataCacheProvider(TestGlobals.DataProvider);
|
||||
}
|
||||
|
||||
[OneTimeTearDown]
|
||||
public void OneTimeTearDown()
|
||||
{
|
||||
_cacheProvider.DisposeSafely();
|
||||
}
|
||||
|
||||
[TestCase(Resolution.Daily)]
|
||||
[TestCase(Resolution.Hour)]
|
||||
[TestCase(Resolution.Minute)]
|
||||
[TestCase(Resolution.Second)]
|
||||
public void TickResolutionSubscriptionHistoryRequestOtherResolution(Resolution resolution)
|
||||
{
|
||||
var start = new DateTime(2013, 10, 07);
|
||||
_algorithm = GetAlgorithm(start.AddDays(1));
|
||||
|
||||
_algorithm.AddEquity(Symbols.SPY, Resolution.Tick);
|
||||
// Trades and quotes
|
||||
var result = _algorithm.History(new [] { Symbols.SPY }, start, _algorithm.Time, resolution).ToList();
|
||||
|
||||
Assert.IsNotEmpty(result);
|
||||
Assert.IsTrue(result.All(slice =>
|
||||
{
|
||||
foreach (var bar in slice.Bars.Values)
|
||||
{
|
||||
return (bar.EndTime - bar.Time) == resolution.ToTimeSpan();
|
||||
}
|
||||
foreach (var bar in slice.QuoteBars.Values)
|
||||
{
|
||||
return (bar.EndTime - bar.Time) == resolution.ToTimeSpan();
|
||||
}
|
||||
|
||||
return false;
|
||||
}));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TickResolutionHistoryRequest()
|
||||
{
|
||||
_algorithm = new QCAlgorithm();
|
||||
_algorithm.SubscriptionManager.SetDataManager(new DataManagerStub(_algorithm));
|
||||
_algorithm.HistoryProvider = new SubscriptionDataReaderHistoryProvider();
|
||||
var zipCacheProvider = new ZipDataCacheProvider(_dataProvider);
|
||||
_algorithm.HistoryProvider.Initialize(new HistoryProviderInitializeParameters(
|
||||
null,
|
||||
null,
|
||||
_dataProvider,
|
||||
zipCacheProvider,
|
||||
_mapFileProvider,
|
||||
_factorFileProvider,
|
||||
null,
|
||||
false,
|
||||
new DataPermissionManager()));
|
||||
_algorithm.SetStartDate(2013, 10, 08);
|
||||
var start = new DateTime(2013, 10, 07);
|
||||
_algorithm = GetAlgorithm(start.AddDays(1));
|
||||
|
||||
// Trades and quotes
|
||||
var result = _algorithm.History(new [] { Symbols.SPY }, start.AddHours(9.8), start.AddHours(10), Resolution.Tick).ToList();
|
||||
@@ -79,7 +106,6 @@ namespace QuantConnect.Tests.Algorithm
|
||||
// Just Trades
|
||||
var result2 = _algorithm.History<Tick>(Symbols.SPY, start.AddHours(9.8), start.AddHours(10), Resolution.Tick).ToList();
|
||||
|
||||
zipCacheProvider.DisposeSafely();
|
||||
Assert.IsNotEmpty(result);
|
||||
Assert.IsNotEmpty(result2);
|
||||
|
||||
@@ -178,8 +204,7 @@ namespace QuantConnect.Tests.Algorithm
|
||||
[Test]
|
||||
public void GetLastKnownPriceOfIlliquidAsset_RealData()
|
||||
{
|
||||
var cacheProvider = new ZipDataCacheProvider(_dataProvider);
|
||||
var algorithm = GetAlgorithm(cacheProvider,new DateTime(2014, 6, 6, 11, 0, 0));
|
||||
var algorithm = GetAlgorithm(new DateTime(2014, 6, 6, 11, 0, 0));
|
||||
|
||||
//20140606_twx_minute_quote_american_call_230000_20150117.csv
|
||||
var optionSymbol = Symbol.CreateOption("TWX", Market.USA, OptionStyle.American, OptionRight.Call, 23, new DateTime(2015,1,17));
|
||||
@@ -190,8 +215,6 @@ namespace QuantConnect.Tests.Algorithm
|
||||
|
||||
// Data gap of more than 15 minutes
|
||||
Assert.Greater((algorithm.Time - lastKnownPrice.EndTime).TotalMinutes, 15);
|
||||
|
||||
cacheProvider.DisposeSafely();
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -218,22 +241,18 @@ namespace QuantConnect.Tests.Algorithm
|
||||
[Test]
|
||||
public void GetLastKnownPriceOfCustomData()
|
||||
{
|
||||
var cacheProvider = new ZipDataCacheProvider(_dataProvider);
|
||||
var algorithm = GetAlgorithm(cacheProvider, new DateTime(2018, 4, 4));
|
||||
var algorithm = GetAlgorithm(new DateTime(2018, 4, 4));
|
||||
|
||||
var alpha = algorithm.AddData<AlphaStreamsPortfolioState>("9fc8ef73792331b11dbd5429a");
|
||||
|
||||
var lastKnownPrice = algorithm.GetLastKnownPrice(alpha);
|
||||
Assert.IsNotNull(lastKnownPrice);
|
||||
|
||||
cacheProvider.DisposeSafely();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetLastKnownPricesEquity()
|
||||
{
|
||||
var cacheProvider = new ZipDataCacheProvider(_dataProvider);
|
||||
var algorithm = GetAlgorithm(cacheProvider, new DateTime(2013, 10, 8));
|
||||
var algorithm = GetAlgorithm(new DateTime(2013, 10, 8));
|
||||
|
||||
var equity = algorithm.AddEquity("SPY");
|
||||
|
||||
@@ -241,42 +260,34 @@ namespace QuantConnect.Tests.Algorithm
|
||||
Assert.AreEqual(2, lastKnownPrices.Count);
|
||||
Assert.AreEqual(1, lastKnownPrices.Count(data => data.GetType() == typeof(TradeBar)));
|
||||
Assert.AreEqual(1, lastKnownPrices.Count(data => data.GetType() == typeof(QuoteBar)));
|
||||
|
||||
cacheProvider.DisposeSafely();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetLastKnownPriceEquity()
|
||||
{
|
||||
var cacheProvider = new ZipDataCacheProvider(_dataProvider);
|
||||
var algorithm = GetAlgorithm(cacheProvider, new DateTime(2013, 10, 8));
|
||||
var algorithm = GetAlgorithm(new DateTime(2013, 10, 8));
|
||||
|
||||
var equity = algorithm.AddEquity("SPY");
|
||||
|
||||
var lastKnownPrice = algorithm.GetLastKnownPrice(equity);
|
||||
Assert.AreEqual(typeof(TradeBar), lastKnownPrice.GetType());
|
||||
|
||||
cacheProvider.DisposeSafely();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetLastKnownPriceOption()
|
||||
{
|
||||
var cacheProvider = new ZipDataCacheProvider(_dataProvider);
|
||||
var algorithm = GetAlgorithm(cacheProvider, new DateTime(2014, 06, 09));
|
||||
var algorithm = GetAlgorithm(new DateTime(2014, 06, 09));
|
||||
|
||||
var option = algorithm.AddOptionContract(Symbols.CreateOptionSymbol("AAPL", OptionRight.Call, 250m, new DateTime(2016, 01, 15)));
|
||||
|
||||
var lastKnownPrice = algorithm.GetLastKnownPrice(option);
|
||||
Assert.AreEqual(typeof(QuoteBar), lastKnownPrice.GetType());
|
||||
cacheProvider.DisposeSafely();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetLastKnownPricesOption()
|
||||
{
|
||||
var cacheProvider = new ZipDataCacheProvider(_dataProvider);
|
||||
var algorithm = GetAlgorithm(cacheProvider, new DateTime(2014, 06, 09));
|
||||
var algorithm = GetAlgorithm(new DateTime(2014, 06, 09));
|
||||
|
||||
var option = algorithm.AddOptionContract(Symbols.CreateOptionSymbol("AAPL", OptionRight.Call, 250m, new DateTime(2016, 01, 15)));
|
||||
|
||||
@@ -284,29 +295,23 @@ namespace QuantConnect.Tests.Algorithm
|
||||
Assert.AreEqual(2, lastKnownPrices.Count);
|
||||
Assert.AreEqual(1, lastKnownPrices.Count(data => data.GetType() == typeof(TradeBar)));
|
||||
Assert.AreEqual(1, lastKnownPrices.Count(data => data.GetType() == typeof(QuoteBar)));
|
||||
|
||||
cacheProvider.DisposeSafely();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetLastKnownPriceFuture()
|
||||
{
|
||||
var cacheProvider = new ZipDataCacheProvider(_dataProvider);
|
||||
var algorithm = GetAlgorithm(cacheProvider, new DateTime(2013, 10, 8));
|
||||
var algorithm = GetAlgorithm(new DateTime(2013, 10, 8));
|
||||
|
||||
var future = algorithm.AddSecurity(Symbols.CreateFutureSymbol(Futures.Indices.SP500EMini, new DateTime(2013, 12, 20)));
|
||||
|
||||
var lastKnownPrice = algorithm.GetLastKnownPrice(future);
|
||||
Assert.AreEqual(typeof(QuoteBar), lastKnownPrice.GetType());
|
||||
|
||||
cacheProvider.DisposeSafely();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetLastKnownPricesFuture()
|
||||
{
|
||||
var cacheProvider = new ZipDataCacheProvider(_dataProvider);
|
||||
var algorithm = GetAlgorithm(cacheProvider, new DateTime(2013, 10, 8));
|
||||
var algorithm = GetAlgorithm(new DateTime(2013, 10, 8));
|
||||
|
||||
var future = algorithm.AddSecurity(Symbols.CreateFutureSymbol(Futures.Indices.SP500EMini, new DateTime(2013, 12, 20)));
|
||||
|
||||
@@ -314,28 +319,13 @@ namespace QuantConnect.Tests.Algorithm
|
||||
Assert.AreEqual(2, lastKnownPrices.Count);
|
||||
Assert.AreEqual(1, lastKnownPrices.Count(data => data.GetType() == typeof(TradeBar)));
|
||||
Assert.AreEqual(1, lastKnownPrices.Count(data => data.GetType() == typeof(QuoteBar)));
|
||||
|
||||
cacheProvider.DisposeSafely();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TickResolutionOpenInterestHistoryRequestIsNotFilteredWhenRequestedExplicitly()
|
||||
{
|
||||
_algorithm = new QCAlgorithm();
|
||||
_algorithm.SubscriptionManager.SetDataManager(new DataManagerStub(_algorithm));
|
||||
_algorithm.HistoryProvider = new SubscriptionDataReaderHistoryProvider();
|
||||
var zipCacheProvider = new ZipDataCacheProvider(_dataProvider);
|
||||
_algorithm.HistoryProvider.Initialize(new HistoryProviderInitializeParameters(
|
||||
null,
|
||||
null,
|
||||
_dataProvider,
|
||||
zipCacheProvider,
|
||||
_mapFileProvider,
|
||||
_factorFileProvider,
|
||||
null,
|
||||
false,
|
||||
new DataPermissionManager()));
|
||||
var start = new DateTime(2014, 6, 05);
|
||||
_algorithm = GetAlgorithm(start);
|
||||
_algorithm.SetStartDate(start);
|
||||
_algorithm.SetDateTime(start.AddDays(2));
|
||||
|
||||
@@ -343,7 +333,6 @@ namespace QuantConnect.Tests.Algorithm
|
||||
var optionSymbol = Symbol.CreateOption("TWX", Market.USA, OptionStyle.American, OptionRight.Call, 23, new DateTime(2015, 1, 17));
|
||||
var openInterests = _algorithm.History<OpenInterest>(optionSymbol, start, start.AddDays(2), Resolution.Minute).ToList();
|
||||
|
||||
zipCacheProvider.DisposeSafely();
|
||||
Assert.IsNotEmpty(openInterests);
|
||||
|
||||
Assert.AreEqual(2, openInterests.Count);
|
||||
@@ -356,28 +345,14 @@ namespace QuantConnect.Tests.Algorithm
|
||||
[Test]
|
||||
public void TickResolutionOpenInterestHistoryRequestIsFilteredByDefault_SingleSymbol()
|
||||
{
|
||||
_algorithm = new QCAlgorithm();
|
||||
_algorithm.SubscriptionManager.SetDataManager(new DataManagerStub(_algorithm));
|
||||
_algorithm.HistoryProvider = new SubscriptionDataReaderHistoryProvider();
|
||||
var zipCacheProvider = new ZipDataCacheProvider(_dataProvider);
|
||||
_algorithm.HistoryProvider.Initialize(new HistoryProviderInitializeParameters(
|
||||
null,
|
||||
null,
|
||||
_dataProvider,
|
||||
zipCacheProvider,
|
||||
_mapFileProvider,
|
||||
_factorFileProvider,
|
||||
null,
|
||||
false,
|
||||
new DataPermissionManager()));
|
||||
var start = new DateTime(2014, 6, 05);
|
||||
_algorithm = GetAlgorithm(start);
|
||||
_algorithm.SetStartDate(start);
|
||||
_algorithm.SetDateTime(start.AddDays(2));
|
||||
|
||||
var optionSymbol = Symbol.CreateOption("TWX", Market.USA, OptionStyle.American, OptionRight.Call, 23, new DateTime(2015, 1, 17));
|
||||
var result = _algorithm.History(new[] { optionSymbol }, start, start.AddDays(2), Resolution.Minute, fillForward:false).ToList();
|
||||
|
||||
zipCacheProvider.DisposeSafely();
|
||||
Assert.IsNotEmpty(result);
|
||||
Assert.IsTrue(result.Any(slice => slice.ContainsKey(optionSymbol)));
|
||||
|
||||
@@ -389,21 +364,8 @@ namespace QuantConnect.Tests.Algorithm
|
||||
[Test]
|
||||
public void TickResolutionOpenInterestHistoryRequestIsFilteredByDefault_MultipleSymbols()
|
||||
{
|
||||
_algorithm = new QCAlgorithm();
|
||||
_algorithm.SubscriptionManager.SetDataManager(new DataManagerStub(_algorithm));
|
||||
_algorithm.HistoryProvider = new SubscriptionDataReaderHistoryProvider();
|
||||
var zipCacheProvider = new ZipDataCacheProvider(_dataProvider);
|
||||
_algorithm.HistoryProvider.Initialize(new HistoryProviderInitializeParameters(
|
||||
null,
|
||||
null,
|
||||
_dataProvider,
|
||||
zipCacheProvider,
|
||||
_mapFileProvider,
|
||||
_factorFileProvider,
|
||||
null,
|
||||
false,
|
||||
new DataPermissionManager()));
|
||||
var start = new DateTime(2014, 6, 05);
|
||||
_algorithm = GetAlgorithm(start.AddDays(1));
|
||||
_algorithm.SetStartDate(start);
|
||||
_algorithm.SetDateTime(start.AddDays(2));
|
||||
|
||||
@@ -411,7 +373,6 @@ namespace QuantConnect.Tests.Algorithm
|
||||
var optionSymbol2 = Symbol.CreateOption("AAPL", Market.USA, OptionStyle.American, OptionRight.Call, 500, new DateTime(2015, 1, 17));
|
||||
var result = _algorithm.History(new[] { optionSymbol, optionSymbol2 }, start, start.AddDays(2), Resolution.Minute, fillForward: false).ToList();
|
||||
|
||||
zipCacheProvider.DisposeSafely();
|
||||
Assert.IsNotEmpty(result);
|
||||
|
||||
Assert.IsTrue(result.Any(slice => slice.ContainsKey(optionSymbol)));
|
||||
@@ -422,7 +383,7 @@ namespace QuantConnect.Tests.Algorithm
|
||||
Assert.AreEqual(0, openInterests.Count);
|
||||
}
|
||||
|
||||
private QCAlgorithm GetAlgorithm(IDataCacheProvider cacheProvider, DateTime dateTime)
|
||||
private QCAlgorithm GetAlgorithm(DateTime dateTime)
|
||||
{
|
||||
var algorithm = new QCAlgorithm();
|
||||
algorithm.SubscriptionManager.SetDataManager(new DataManagerStub(algorithm));
|
||||
@@ -433,7 +394,7 @@ namespace QuantConnect.Tests.Algorithm
|
||||
null,
|
||||
null,
|
||||
_dataProvider,
|
||||
cacheProvider,
|
||||
_cacheProvider,
|
||||
_mapFileProvider,
|
||||
_factorFileProvider,
|
||||
null,
|
||||
|
||||
@@ -76,6 +76,16 @@ namespace QuantConnect.Tests.Brokerages.Tradier
|
||||
return false;
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetQuotesDoesNotReturnNull()
|
||||
{
|
||||
var tradier = (TradierBrokerage) Brokerage;
|
||||
var quotes = tradier.GetQuotes(new List<string> { "VXX190517P00016000" });
|
||||
|
||||
Assert.IsNotNull(quotes);
|
||||
Assert.IsEmpty(quotes);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current market price of the specified security
|
||||
/// </summary>
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
/*
|
||||
* 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 System;
|
||||
using System.Collections.Generic;
|
||||
using NUnit.Framework;
|
||||
using QuantConnect.Brokerages.Zerodha.Messages;
|
||||
|
||||
namespace QuantConnect.Tests.Brokerages.Zerodha
|
||||
{
|
||||
[TestFixture]
|
||||
public class KiteTests
|
||||
{
|
||||
[Test]
|
||||
public void HistoricalCandleData()
|
||||
{
|
||||
var timeStamp = new DateTimeOffset(2021, 06, 11, 9, 15, 0, new TimeSpan(5, 30, 0));
|
||||
List<object> param = new List<object>(){ timeStamp, "1575", "1610.5", "1572", "1608.75", "2179" };
|
||||
var expectedCandleData = new Historical(param);
|
||||
|
||||
Assert.AreEqual(new DateTime(2021, 06, 11, 3, 45, 0), expectedCandleData.TimeStamp);
|
||||
Assert.AreEqual(1575, expectedCandleData.Open);
|
||||
Assert.AreEqual(1610.5, expectedCandleData.High);
|
||||
Assert.AreEqual(1572, expectedCandleData.Low);
|
||||
Assert.AreEqual(1608.75, expectedCandleData.Close);
|
||||
Assert.AreEqual(2179, expectedCandleData.Volume);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,100 +0,0 @@
|
||||
/*
|
||||
* 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 System;
|
||||
using NUnit.Framework;
|
||||
using QuantConnect.Brokerages.Zerodha;
|
||||
using QuantConnect.Configuration;
|
||||
using QuantConnect.Data;
|
||||
using QuantConnect.Data.Market;
|
||||
using QuantConnect.Logging;
|
||||
using QuantConnect.Securities;
|
||||
|
||||
namespace QuantConnect.Tests.Brokerages.Zerodha
|
||||
{
|
||||
[TestFixture, Ignore("This test requires a configured and active Zerodha account")]
|
||||
public class ZerodhaBrokerageHistoryProviderTests
|
||||
{
|
||||
private static TestCaseData[] TestParameters
|
||||
{
|
||||
get
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
// valid parameters
|
||||
new TestCaseData(Symbols.SBIN, Resolution.Tick, Time.OneMinute, false),
|
||||
new TestCaseData(Symbols.SBIN, Resolution.Second, Time.OneMinute, false),
|
||||
new TestCaseData(Symbols.SBIN, Resolution.Minute, Time.OneHour, false),
|
||||
new TestCaseData(Symbols.SBIN, Resolution.Hour, Time.OneDay, false),
|
||||
new TestCaseData(Symbols.SBIN, Resolution.Daily, TimeSpan.FromDays(15), false),
|
||||
|
||||
// invalid period, throws "System.ArgumentException : Invalid date range specified"
|
||||
new TestCaseData(Symbols.SBIN, Resolution.Daily, TimeSpan.FromDays(-15), true),
|
||||
|
||||
// invalid security type, throws "System.ArgumentException : Invalid security type: Forex"
|
||||
new TestCaseData(Symbols.EURUSD, Resolution.Daily, TimeSpan.FromDays(15), true)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
[Test, TestCaseSource(nameof(TestParameters))]
|
||||
public void GetsHistory(Symbol symbol, Resolution resolution, TimeSpan period, bool throwsException)
|
||||
{
|
||||
TestDelegate test = () =>
|
||||
{
|
||||
var accessToken = Config.Get("zerodha-access-token");
|
||||
var apiKey = Config.Get("zerodha-api-key");
|
||||
var tradingSegment = Config.Get("zerodha-trading-segment");
|
||||
var productType = Config.Get("zerodha-product-type");
|
||||
var brokerage = new ZerodhaBrokerage(tradingSegment, productType, apiKey, accessToken, null,null,null);
|
||||
|
||||
var now = DateTime.UtcNow;
|
||||
|
||||
var request = new HistoryRequest(now.Add(-period),
|
||||
now,
|
||||
typeof(QuoteBar),
|
||||
symbol,
|
||||
resolution,
|
||||
SecurityExchangeHours.AlwaysOpen(TimeZones.Kolkata),
|
||||
TimeZones.Kolkata,
|
||||
Resolution.Minute,
|
||||
false,
|
||||
false,
|
||||
DataNormalizationMode.Adjusted,
|
||||
TickType.Quote)
|
||||
{ };
|
||||
|
||||
|
||||
var history = brokerage.GetHistory(request);
|
||||
|
||||
foreach (var slice in history)
|
||||
{
|
||||
Log.Trace("{0}: {1} - {2} / {3}", slice.Time, slice.Symbol, slice.Price, slice.IsFillForward);
|
||||
}
|
||||
|
||||
Log.Trace("Base currency: " + brokerage.AccountBaseCurrency);
|
||||
};
|
||||
|
||||
if (throwsException)
|
||||
{
|
||||
Assert.Throws<ArgumentException>(test);
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert.DoesNotThrow(test);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,706 +0,0 @@
|
||||
/*
|
||||
* 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 Moq;
|
||||
using NUnit.Framework;
|
||||
using QuantConnect.Brokerages;
|
||||
using QuantConnect.Brokerages.Zerodha;
|
||||
using QuantConnect.Configuration;
|
||||
using QuantConnect.Data;
|
||||
using QuantConnect.Data.Market;
|
||||
using QuantConnect.Interfaces;
|
||||
using QuantConnect.Lean.Engine.DataFeeds;
|
||||
using QuantConnect.Logging;
|
||||
using QuantConnect.Orders;
|
||||
using QuantConnect.Securities;
|
||||
using QuantConnect.Tests.Common.Securities;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
|
||||
namespace QuantConnect.Tests.Brokerages.Zerodha
|
||||
{
|
||||
[TestFixture, Ignore("This test requires a configured and active Zerodha account")]
|
||||
public class ZerodhaBrokerageTests
|
||||
{
|
||||
|
||||
|
||||
private static IOrderProperties orderProperties = new IndiaOrderProperties(exchange: Exchange.NSE);
|
||||
|
||||
private IBrokerage _brokerage;
|
||||
private OrderProvider _orderProvider;
|
||||
private SecurityProvider _securityProvider;
|
||||
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
Log.Trace("");
|
||||
Log.Trace("");
|
||||
Log.Trace("--- SETUP ---");
|
||||
Log.Trace("");
|
||||
Log.Trace("");
|
||||
// we want to regenerate these for each test
|
||||
_brokerage = null;
|
||||
_orderProvider = null;
|
||||
_securityProvider = null;
|
||||
Thread.Sleep(1000);
|
||||
CancelOpenOrders();
|
||||
LiquidateZerodhaHoldings();
|
||||
Thread.Sleep(1000);
|
||||
}
|
||||
|
||||
[TearDown]
|
||||
public void Teardown()
|
||||
{
|
||||
try
|
||||
{
|
||||
Log.Trace("");
|
||||
Log.Trace("");
|
||||
Log.Trace("--- TEARDOWN ---");
|
||||
Log.Trace("");
|
||||
Log.Trace("");
|
||||
Thread.Sleep(1000);
|
||||
CancelOpenOrders();
|
||||
LiquidateZerodhaHoldings();
|
||||
Thread.Sleep(1000);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_brokerage != null)
|
||||
{
|
||||
DisposeBrokerage(_brokerage);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Disposes of the brokerage and any external resources started in order to create it
|
||||
/// </summary>
|
||||
/// <param name="brokerage">The brokerage instance to be disposed of</param>
|
||||
protected virtual void DisposeBrokerage(IBrokerage brokerage)
|
||||
{
|
||||
brokerage.Disconnect();
|
||||
}
|
||||
|
||||
public IBrokerage Brokerage
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_brokerage == null)
|
||||
{
|
||||
_brokerage = InitializeBrokerage();
|
||||
}
|
||||
return _brokerage;
|
||||
}
|
||||
}
|
||||
|
||||
private IBrokerage InitializeBrokerage()
|
||||
{
|
||||
Log.Trace("");
|
||||
Log.Trace("- INITIALIZING BROKERAGE -");
|
||||
Log.Trace("");
|
||||
|
||||
var brokerage = CreateBrokerage(OrderProvider, SecurityProvider);
|
||||
brokerage.Connect();
|
||||
|
||||
if (!brokerage.IsConnected)
|
||||
{
|
||||
Assert.Fail("Failed to connect to brokerage");
|
||||
}
|
||||
|
||||
Log.Trace("");
|
||||
Log.Trace("GET OPEN ORDERS");
|
||||
Log.Trace("");
|
||||
foreach (var openOrder in brokerage.GetOpenOrders())
|
||||
{
|
||||
OrderProvider.Add(openOrder);
|
||||
}
|
||||
|
||||
Log.Trace("");
|
||||
Log.Trace("GET ACCOUNT HOLDINGS");
|
||||
Log.Trace("");
|
||||
foreach (var accountHolding in brokerage.GetAccountHoldings())
|
||||
{
|
||||
// these securities don't need to be real, just used for the ISecurityProvider impl, required
|
||||
// by brokerages to track holdings
|
||||
SecurityProvider[accountHolding.Symbol] = CreateSecurity(accountHolding.Symbol);
|
||||
}
|
||||
brokerage.OrderStatusChanged += (sender, args) =>
|
||||
{
|
||||
Log.Trace("");
|
||||
Log.Trace("ORDER STATUS CHANGED: " + args);
|
||||
Log.Trace("");
|
||||
|
||||
// we need to keep this maintained properly
|
||||
if (args.Status == OrderStatus.Filled || args.Status == OrderStatus.PartiallyFilled)
|
||||
{
|
||||
Log.Trace("FILL EVENT: " + args.FillQuantity + " units of " + args.Symbol.ToString());
|
||||
|
||||
Security security;
|
||||
if (_securityProvider.TryGetValue(args.Symbol, out security))
|
||||
{
|
||||
var holding = _securityProvider[args.Symbol].Holdings;
|
||||
holding.SetHoldings(args.FillPrice, holding.Quantity + args.FillQuantity);
|
||||
}
|
||||
else
|
||||
{
|
||||
_securityProvider[args.Symbol] = CreateSecurity(args.Symbol);
|
||||
_securityProvider[args.Symbol].Holdings.SetHoldings(args.FillPrice, args.FillQuantity);
|
||||
}
|
||||
|
||||
Log.Trace("--HOLDINGS: " + _securityProvider[args.Symbol]);
|
||||
|
||||
// update order mapping
|
||||
var order = _orderProvider.GetOrderById(args.OrderId);
|
||||
order.Status = args.Status;
|
||||
}
|
||||
};
|
||||
return brokerage;
|
||||
}
|
||||
|
||||
|
||||
internal static Security CreateSecurity(Symbol symbol)
|
||||
{
|
||||
return new Security(
|
||||
SecurityExchangeHours.AlwaysOpen(TimeZones.NewYork),
|
||||
new SubscriptionDataConfig(
|
||||
typeof(TradeBar),
|
||||
symbol,
|
||||
Resolution.Minute,
|
||||
TimeZones.NewYork,
|
||||
TimeZones.NewYork,
|
||||
false,
|
||||
false,
|
||||
false
|
||||
),
|
||||
new Cash(Currencies.USD, 0, 1m),
|
||||
SymbolProperties.GetDefault(Currencies.USD),
|
||||
ErrorCurrencyConverter.Instance,
|
||||
RegisteredSecurityDataTypesProvider.Null,
|
||||
new SecurityCache()
|
||||
);
|
||||
}
|
||||
|
||||
public OrderProvider OrderProvider
|
||||
{
|
||||
get { return _orderProvider ?? (_orderProvider = new OrderProvider()); }
|
||||
}
|
||||
|
||||
public SecurityProvider SecurityProvider
|
||||
{
|
||||
get { return _securityProvider ?? (_securityProvider = new SecurityProvider()); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This is used to ensure each test starts with a clean, known state.
|
||||
/// </summary>
|
||||
protected void LiquidateZerodhaHoldings()
|
||||
{
|
||||
Log.Trace("");
|
||||
Log.Trace("LIQUIDATE HOLDINGS");
|
||||
Log.Trace("");
|
||||
|
||||
var holdings = Brokerage.GetAccountHoldings();
|
||||
|
||||
foreach (var holding in holdings)
|
||||
{
|
||||
if (holding.Quantity == 0) continue;
|
||||
Log.Trace("Liquidating: " + holding);
|
||||
var order = new MarketOrder(holding.Symbol, -holding.Quantity, DateTime.UtcNow,properties:orderProperties);
|
||||
_orderProvider.Add(order);
|
||||
PlaceZerodhaOrderWaitForStatus(order, OrderStatus.Filled);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Provides the data required to test each order type in various cases
|
||||
/// </summary>
|
||||
private static TestCaseData[] OrderParameters()
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
new TestCaseData(new MarketOrderTestParameters(Symbols.IDEA,orderProperties)).SetName("MarketOrder"),
|
||||
new TestCaseData(new LimitOrderTestParameters(Symbols.IDEA, 9.00m, 9.30m,orderProperties)).SetName("LimitOrder"),
|
||||
new TestCaseData(new StopMarketOrderTestParameters(Symbols.IDEA, 10.50m, 9.50m,orderProperties)).SetName("StopMarketOrder"),
|
||||
//new TestCaseData(new StopLimitOrderTestParameters(Symbols.IDEA, 9.00m, 10.50m,orderProperties)).SetName("StopLimitOrder")
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates the brokerage under test
|
||||
/// </summary>
|
||||
/// <returns>A connected brokerage instance</returns>
|
||||
protected IBrokerage CreateBrokerage(IOrderProvider orderProvider, ISecurityProvider securityProvider)
|
||||
{
|
||||
|
||||
var securities = new SecurityManager(new TimeKeeper(DateTime.UtcNow, TimeZones.Kolkata))
|
||||
{
|
||||
{ Symbol, CreateSecurity(Symbol) }
|
||||
};
|
||||
|
||||
var transactions = new SecurityTransactionManager(null, securities);
|
||||
transactions.SetOrderProcessor(new FakeOrderProcessor());
|
||||
|
||||
var algorithm = new Mock<IAlgorithm>();
|
||||
algorithm.Setup(a => a.Transactions).Returns(transactions);
|
||||
algorithm.Setup(a => a.BrokerageModel).Returns(new ZerodhaBrokerageModel());
|
||||
algorithm.Setup(a => a.Portfolio).Returns(new SecurityPortfolioManager(securities, transactions));
|
||||
|
||||
var accessToken = Config.Get("zerodha-access-token");
|
||||
var apiKey = Config.Get("zerodha-api-key");
|
||||
var tradingSegment = Config.Get("zerodha-trading-segment");
|
||||
var productType = Config.Get("zerodha-product-type");
|
||||
var zerodha = new ZerodhaBrokerage(tradingSegment, productType, apiKey, accessToken, algorithm.Object, algorithm.Object.Portfolio, new AggregationManager());
|
||||
|
||||
return zerodha;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the symbol to be traded, must be shortable
|
||||
/// </summary>
|
||||
protected Symbol Symbol => Symbols.IDEA;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the security type associated with the <see cref="BrokerageTests.Symbol"/>
|
||||
/// </summary>
|
||||
protected SecurityType SecurityType => SecurityType.Equity;
|
||||
|
||||
/// <summary>
|
||||
/// Returns wether or not the brokers order methods implementation are async
|
||||
/// </summary>
|
||||
protected bool IsAsync()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets the default order quantity
|
||||
/// </summary>
|
||||
protected virtual decimal GetDefaultQuantity()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current market price of the specified security
|
||||
/// </summary>
|
||||
protected decimal GetAskPrice(Symbol symbol)
|
||||
{
|
||||
var zerodha = (ZerodhaBrokerage)Brokerage;
|
||||
var quotes = zerodha.GetQuote(symbol);
|
||||
return quotes.LastPrice;
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ShortIdea()
|
||||
{
|
||||
PlaceZerodhaOrderWaitForStatus(new MarketOrder(Symbols.IDEA, -1, DateTime.Now, properties: orderProperties), OrderStatus.Submitted, allowFailedSubmission: true);
|
||||
|
||||
// wait for output to be generated
|
||||
Thread.Sleep(20 * 1000);
|
||||
}
|
||||
|
||||
[Test, TestCaseSource(nameof(OrderParameters))]
|
||||
public void CancelOrders(OrderTestParameters parameters)
|
||||
{
|
||||
const int secondsTimeout = 20;
|
||||
Log.Trace("");
|
||||
Log.Trace("CANCEL ORDERS");
|
||||
Log.Trace("");
|
||||
|
||||
var order = PlaceZerodhaOrderWaitForStatus(parameters.CreateLongOrder(GetDefaultQuantity()), parameters.ExpectedStatus);
|
||||
|
||||
var canceledOrderStatusEvent = new ManualResetEvent(false);
|
||||
EventHandler<OrderEvent> orderStatusCallback = (sender, fill) =>
|
||||
{
|
||||
if (fill.Status == OrderStatus.Canceled)
|
||||
{
|
||||
canceledOrderStatusEvent.Set();
|
||||
}
|
||||
};
|
||||
Brokerage.OrderStatusChanged += orderStatusCallback;
|
||||
var cancelResult = false;
|
||||
try
|
||||
{
|
||||
cancelResult = Brokerage.CancelOrder(order);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
Log.Error(exception);
|
||||
}
|
||||
|
||||
Assert.AreEqual(IsCancelAsync() || parameters.ExpectedCancellationResult, cancelResult);
|
||||
|
||||
if (parameters.ExpectedCancellationResult)
|
||||
{
|
||||
// We expect the OrderStatus.Canceled event
|
||||
canceledOrderStatusEvent.WaitOneAssertFail(1000 * secondsTimeout, "Order timedout to cancel");
|
||||
}
|
||||
|
||||
var openOrders = Brokerage.GetOpenOrders();
|
||||
var cancelledOrder = openOrders.FirstOrDefault(x => x.Id == order.Id);
|
||||
Assert.IsNull(cancelledOrder);
|
||||
|
||||
//canceledOrderStatusEvent.Reset();
|
||||
|
||||
//var cancelResultSecondTime = false;
|
||||
//try
|
||||
//{
|
||||
// cancelResultSecondTime = Brokerage.CancelOrder(order);
|
||||
//}
|
||||
//catch (Exception exception)
|
||||
//{
|
||||
// Log.Error(exception);
|
||||
//}
|
||||
//Assert.AreEqual(IsCancelAsync(), cancelResultSecondTime);
|
||||
//// We do NOT expect the OrderStatus.Canceled event
|
||||
//Assert.IsFalse(canceledOrderStatusEvent.WaitOne(new TimeSpan(0, 0, 10)));
|
||||
|
||||
//Brokerage.OrderStatusChanged -= orderStatusCallback;
|
||||
}
|
||||
|
||||
|
||||
[Test]
|
||||
public void ValidateStopLimitOrders()
|
||||
{
|
||||
var zerodha = (ZerodhaBrokerage)Brokerage;
|
||||
var symbol = Symbol;
|
||||
var lastPrice = GetAskPrice(symbol.Value);
|
||||
|
||||
// Buy StopLimit order below market TODO: This might not work because of the Zerodha structure. Verify this.
|
||||
//var stopPrice = lastPrice - 0.10m;
|
||||
//var limitPrice = stopPrice + 0.10m;
|
||||
//var order = new StopLimitOrder(symbol, 1, stopPrice, limitPrice, DateTime.UtcNow, properties: orderProperties);
|
||||
//Assert.IsTrue(zerodha.PlaceOrder(order));
|
||||
|
||||
// Buy StopLimit order above market
|
||||
var stopPrice = lastPrice + 0.20m;
|
||||
var limitPrice = stopPrice + 0.25m;
|
||||
var order = new StopLimitOrder(symbol, 1, stopPrice, limitPrice, DateTime.UtcNow, properties: orderProperties);
|
||||
Assert.IsTrue(zerodha.PlaceOrder(order));
|
||||
|
||||
// In case there is no position, the following sell orders would not be placed
|
||||
// So build a position for them.
|
||||
var marketOrder = new MarketOrder(symbol, 2, DateTime.UtcNow, properties: orderProperties);
|
||||
Assert.IsTrue(zerodha.PlaceOrder(marketOrder));
|
||||
|
||||
Thread.Sleep(20000);
|
||||
// Sell StopLimit order below market
|
||||
stopPrice = lastPrice - 0.25m;
|
||||
limitPrice = stopPrice - 0.5m;
|
||||
order = new StopLimitOrder(symbol, -1, stopPrice, limitPrice, DateTime.UtcNow, properties: orderProperties);
|
||||
Assert.IsTrue(zerodha.PlaceOrder(order));
|
||||
|
||||
// Sell StopLimit order above market. TODO: This might not work because of the Zerodha structure. Verify this
|
||||
//stopPrice = lastPrice + 0.5m;
|
||||
//limitPrice = stopPrice - 0.25m ;
|
||||
//order = new StopLimitOrder(symbol, -1, stopPrice, limitPrice, DateTime.UtcNow, properties: orderProperties);
|
||||
//Assert.IsTrue(zerodha.PlaceOrder(order));
|
||||
}
|
||||
|
||||
|
||||
[Test, TestCaseSource(nameof(OrderParameters))]
|
||||
public void LongFromZero(OrderTestParameters parameters)
|
||||
{
|
||||
Log.Trace("");
|
||||
Log.Trace("LONG FROM ZERO");
|
||||
Log.Trace("");
|
||||
PlaceZerodhaOrderWaitForStatus(parameters.CreateLongOrder(GetDefaultQuantity()), parameters.ExpectedStatus);
|
||||
}
|
||||
|
||||
|
||||
[Test, TestCaseSource(nameof(OrderParameters))]
|
||||
public void CloseFromLong(OrderTestParameters parameters)
|
||||
{
|
||||
Log.Trace("");
|
||||
Log.Trace("CLOSE FROM LONG");
|
||||
Log.Trace("");
|
||||
// first go long
|
||||
PlaceZerodhaOrderWaitForStatus(parameters.CreateLongMarketOrder(GetDefaultQuantity()), OrderStatus.Filled);
|
||||
|
||||
// now close it
|
||||
PlaceZerodhaOrderWaitForStatus(parameters.CreateShortOrder(GetDefaultQuantity()), parameters.ExpectedStatus);
|
||||
}
|
||||
|
||||
[Test, TestCaseSource(nameof(OrderParameters))]
|
||||
public void ShortFromZero(OrderTestParameters parameters)
|
||||
{
|
||||
Log.Trace("");
|
||||
Log.Trace("SHORT FROM ZERO");
|
||||
Log.Trace("");
|
||||
PlaceZerodhaOrderWaitForStatus(parameters.CreateShortOrder(GetDefaultQuantity()), parameters.ExpectedStatus);
|
||||
}
|
||||
|
||||
[Test, TestCaseSource(nameof(OrderParameters))]
|
||||
public virtual void CloseFromShort(OrderTestParameters parameters)
|
||||
{
|
||||
Log.Trace("");
|
||||
Log.Trace("CLOSE FROM SHORT");
|
||||
Log.Trace("");
|
||||
// first go short
|
||||
PlaceZerodhaOrderWaitForStatus(parameters.CreateShortMarketOrder(GetDefaultQuantity()), OrderStatus.Filled);
|
||||
|
||||
// now close it
|
||||
PlaceZerodhaOrderWaitForStatus(parameters.CreateLongOrder(GetDefaultQuantity()), parameters.ExpectedStatus);
|
||||
}
|
||||
|
||||
[Test, TestCaseSource(nameof(OrderParameters))]
|
||||
public virtual void ShortFromLong(OrderTestParameters parameters)
|
||||
{
|
||||
Log.Trace("");
|
||||
Log.Trace("SHORT FROM LONG");
|
||||
Log.Trace("");
|
||||
// first go long
|
||||
PlaceZerodhaOrderWaitForStatus(parameters.CreateLongMarketOrder(GetDefaultQuantity()));
|
||||
|
||||
// now go net short
|
||||
var order = PlaceZerodhaOrderWaitForStatus(parameters.CreateShortOrder(2 * GetDefaultQuantity()), parameters.ExpectedStatus);
|
||||
|
||||
if (parameters.ModifyUntilFilled)
|
||||
{
|
||||
ModifyOrderUntilFilled(order, parameters);
|
||||
}
|
||||
}
|
||||
|
||||
[Test, Ignore("This test requires reading the output and selection of a low volume security for the Brokerage")]
|
||||
public void PartialFills()
|
||||
{
|
||||
var manualResetEvent = new ManualResetEvent(false);
|
||||
|
||||
var qty = 1000000m;
|
||||
var remaining = qty;
|
||||
var sync = new object();
|
||||
Brokerage.OrderStatusChanged += (sender, orderEvent) =>
|
||||
{
|
||||
lock (sync)
|
||||
{
|
||||
remaining -= orderEvent.FillQuantity;
|
||||
Console.WriteLine("Remaining: " + remaining + " FillQuantity: " + orderEvent.FillQuantity);
|
||||
if (orderEvent.Status == OrderStatus.Filled)
|
||||
{
|
||||
manualResetEvent.Set();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// pick a security with low, but some, volume
|
||||
var symbol = Symbols.EURUSD;
|
||||
var order = new MarketOrder(symbol, qty, DateTime.UtcNow) { Id = 1 };
|
||||
OrderProvider.Add(order);
|
||||
Brokerage.PlaceOrder(order);
|
||||
|
||||
// pause for a while to wait for fills to come in
|
||||
manualResetEvent.WaitOne(2500);
|
||||
manualResetEvent.WaitOne(2500);
|
||||
manualResetEvent.WaitOne(2500);
|
||||
|
||||
Console.WriteLine("Remaining: " + remaining);
|
||||
Assert.AreEqual(0, remaining);
|
||||
}
|
||||
|
||||
[Test, TestCaseSource(nameof(OrderParameters))]
|
||||
public virtual void LongFromShort(OrderTestParameters parameters)
|
||||
{
|
||||
Log.Trace("");
|
||||
Log.Trace("LONG FROM SHORT");
|
||||
Log.Trace("");
|
||||
// first fo short
|
||||
PlaceZerodhaOrderWaitForStatus(parameters.CreateShortMarketOrder(-GetDefaultQuantity()), OrderStatus.Filled);
|
||||
|
||||
// now go long
|
||||
var order = PlaceZerodhaOrderWaitForStatus(parameters.CreateLongOrder(2 * GetDefaultQuantity()), parameters.ExpectedStatus);
|
||||
|
||||
if (parameters.ModifyUntilFilled)
|
||||
{
|
||||
ModifyOrderUntilFilled(order, parameters);
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetCashBalanceContainsSomething()
|
||||
{
|
||||
Log.Trace("");
|
||||
Log.Trace("GET CASH BALANCE");
|
||||
Log.Trace("");
|
||||
var balance = Brokerage.GetCashBalance();
|
||||
Assert.IsTrue(balance.Any());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetAccountHoldings()
|
||||
{
|
||||
Log.Trace("");
|
||||
Log.Trace("GET ACCOUNT HOLDINGS");
|
||||
Log.Trace("");
|
||||
var before = Brokerage.GetAccountHoldings();
|
||||
|
||||
PlaceZerodhaOrderWaitForStatus(new MarketOrder(Symbol, GetDefaultQuantity(), DateTime.UtcNow,properties:orderProperties));
|
||||
|
||||
Thread.Sleep(3000);
|
||||
|
||||
var after = Brokerage.GetAccountHoldings();
|
||||
|
||||
var beforeHoldings = before.FirstOrDefault(x => x.Symbol == Symbol);
|
||||
var afterHoldings = after.FirstOrDefault(x => x.Symbol == Symbol);
|
||||
|
||||
var beforeQuantity = beforeHoldings == null ? 0 : beforeHoldings.Quantity;
|
||||
var afterQuantity = afterHoldings == null ? 0 : afterHoldings.Quantity;
|
||||
|
||||
Assert.AreEqual(GetDefaultQuantity(), afterQuantity - beforeQuantity);
|
||||
}
|
||||
|
||||
|
||||
[Test]
|
||||
public void IsConnected()
|
||||
{
|
||||
Assert.IsTrue(Brokerage.IsConnected);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Places the specified order with the brokerage and wait until we get the <paramref name="expectedStatus"/> back via an OrderStatusChanged event.
|
||||
/// This function handles adding the order to the <see cref="IOrderProvider"/> instance as well as incrementing the order ID.
|
||||
/// </summary>
|
||||
/// <param name="order">The order to be submitted</param>
|
||||
/// <param name="expectedStatus">The status to wait for</param>
|
||||
/// <param name="secondsTimeout">Maximum amount of time to wait for <paramref name="expectedStatus"/></param>
|
||||
/// <param name="allowFailedSubmission">Allow failed order submission</param>
|
||||
/// <returns>The same order that was submitted.</returns>
|
||||
protected Order PlaceZerodhaOrderWaitForStatus(Order order, OrderStatus expectedStatus = OrderStatus.Filled,
|
||||
double secondsTimeout = 10.0, bool allowFailedSubmission = false)
|
||||
{
|
||||
var requiredStatusEvent = new ManualResetEvent(false);
|
||||
var desiredStatusEvent = new ManualResetEvent(false);
|
||||
EventHandler<OrderEvent> brokerageOnOrderStatusChanged = (sender, args) =>
|
||||
{
|
||||
// no matter what, every order should fire at least one of these
|
||||
if (args.Status == OrderStatus.Submitted || args.Status == OrderStatus.Invalid)
|
||||
{
|
||||
Log.Trace("");
|
||||
Log.Trace("SUBMITTED: " + args);
|
||||
Log.Trace("");
|
||||
requiredStatusEvent.Set();
|
||||
}
|
||||
// make sure we fire the status we're expecting
|
||||
if (args.Status == expectedStatus)
|
||||
{
|
||||
Log.Trace("");
|
||||
Log.Trace("EXPECTED: " + args);
|
||||
Log.Trace("");
|
||||
desiredStatusEvent.Set();
|
||||
}
|
||||
};
|
||||
|
||||
Brokerage.OrderStatusChanged += brokerageOnOrderStatusChanged;
|
||||
|
||||
OrderProvider.Add(order);
|
||||
if (!Brokerage.PlaceOrder(order) && !allowFailedSubmission)
|
||||
{
|
||||
Assert.Fail("Brokerage failed to place the order: " + order);
|
||||
}
|
||||
|
||||
|
||||
requiredStatusEvent.WaitOneAssertFail((int)(1000 * secondsTimeout), "Expected every order to fire a submitted or invalid status event");
|
||||
desiredStatusEvent.WaitOneAssertFail((int)(1000 * secondsTimeout), "OrderStatus " + expectedStatus + " was not encountered within the timeout. Order Id:" + order.Id);
|
||||
|
||||
|
||||
Brokerage.OrderStatusChanged -= brokerageOnOrderStatusChanged;
|
||||
|
||||
return order;
|
||||
}
|
||||
|
||||
protected void CancelOpenOrders()
|
||||
{
|
||||
Log.Trace("");
|
||||
Log.Trace("CANCEL OPEN ORDERS");
|
||||
Log.Trace("");
|
||||
var openOrders = Brokerage.GetOpenOrders();
|
||||
foreach (var openOrder in openOrders)
|
||||
{
|
||||
Log.Trace("Canceling: " + openOrder);
|
||||
Brokerage.CancelOrder(openOrder);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the specified order in the brokerage until it fills or reaches a timeout
|
||||
/// </summary>
|
||||
/// <param name="order">The order to be modified</param>
|
||||
/// <param name="parameters">The order test parameters that define how to modify the order</param>
|
||||
/// <param name="secondsTimeout">Maximum amount of time to wait until the order fills</param>
|
||||
protected void ModifyOrderUntilFilled(Order order, OrderTestParameters parameters, double secondsTimeout = 90)
|
||||
{
|
||||
if (order.Status == OrderStatus.Filled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var filledResetEvent = new ManualResetEvent(false);
|
||||
EventHandler<OrderEvent> brokerageOnOrderStatusChanged = (sender, args) =>
|
||||
{
|
||||
if (args.Status == OrderStatus.Filled)
|
||||
{
|
||||
filledResetEvent.Set();
|
||||
}
|
||||
if (args.Status == OrderStatus.Canceled || args.Status == OrderStatus.Invalid)
|
||||
{
|
||||
Log.Trace("ModifyOrderUntilFilled(): " + order);
|
||||
Assert.Fail("Unexpected order status: " + args.Status);
|
||||
}
|
||||
};
|
||||
|
||||
Brokerage.OrderStatusChanged += brokerageOnOrderStatusChanged;
|
||||
|
||||
Log.Trace("");
|
||||
Log.Trace("MODIFY UNTIL FILLED: " + order);
|
||||
Log.Trace("");
|
||||
var stopwatch = Stopwatch.StartNew();
|
||||
while (!filledResetEvent.WaitOne(3000) && stopwatch.Elapsed.TotalSeconds < secondsTimeout)
|
||||
{
|
||||
filledResetEvent.Reset();
|
||||
if (order.Status == OrderStatus.PartiallyFilled) continue;
|
||||
|
||||
var marketPrice = GetAskPrice(order.Symbol);
|
||||
Log.Trace("BrokerageTests.ModifyOrderUntilFilled(): Ask: " + marketPrice);
|
||||
|
||||
var updateOrder = parameters.ModifyOrderToFill(Brokerage, order, marketPrice);
|
||||
if (updateOrder)
|
||||
{
|
||||
if (order.Status == OrderStatus.Filled) break;
|
||||
|
||||
Log.Trace("BrokerageTests.ModifyOrderUntilFilled(): " + order);
|
||||
if (!Brokerage.UpdateOrder(order))
|
||||
{
|
||||
Assert.Fail("Brokerage failed to update the order");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Brokerage.OrderStatusChanged -= brokerageOnOrderStatusChanged;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns whether or not the brokers order cancel method implementation is async
|
||||
/// </summary>
|
||||
protected bool IsCancelAsync()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -23,6 +23,19 @@ namespace QuantConnect.Tests.Common.Util
|
||||
[TestFixture]
|
||||
public class ComposerTests
|
||||
{
|
||||
[Test]
|
||||
public void GetExportedValueByTypeName()
|
||||
{
|
||||
var instance = Composer.Instance.GetExportedValueByTypeName<IExport2>("Export6");
|
||||
Assert.AreEqual(typeof(Export6), instance.GetType());
|
||||
|
||||
var instance2 = Composer.Instance.GetExportedValueByTypeName<IExport2>("Export7");
|
||||
Assert.AreEqual(typeof(Export7), instance2.GetType());
|
||||
|
||||
var instance3 = Composer.Instance.GetExportedValueByTypeName<IExport2>("Export8", forceTypeNameOnExisting: false);
|
||||
Assert.AreNotEqual(typeof(Export8), instance3.GetType());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ComposesTypes()
|
||||
{
|
||||
@@ -103,5 +116,24 @@ namespace QuantConnect.Tests.Common.Util
|
||||
|
||||
public int Id { get { return 5; } }
|
||||
}
|
||||
|
||||
|
||||
[InheritedExport(typeof(IExport2))]
|
||||
interface IExport2
|
||||
{
|
||||
int Id { get; }
|
||||
}
|
||||
class Export6 : IExport2
|
||||
{
|
||||
public int Id { get { return 6; } }
|
||||
}
|
||||
class Export7 : IExport2
|
||||
{
|
||||
public int Id { get { return 7; } }
|
||||
}
|
||||
class Export8 : IExport2
|
||||
{
|
||||
public int Id { get { return 8; } }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -183,6 +183,7 @@ namespace QuantConnect.Tests.Common.Util
|
||||
Assert.IsTrue(LeanData.IsCommonLeanDataType(typeof(OpenInterest)));
|
||||
Assert.IsTrue(LeanData.IsCommonLeanDataType(typeof(TradeBar)));
|
||||
Assert.IsTrue(LeanData.IsCommonLeanDataType(typeof(QuoteBar)));
|
||||
Assert.IsTrue(LeanData.IsCommonLeanDataType(typeof(Tick)));
|
||||
Assert.IsFalse(LeanData.IsCommonLeanDataType(typeof(Bitcoin)));
|
||||
}
|
||||
|
||||
@@ -193,22 +194,23 @@ namespace QuantConnect.Tests.Common.Util
|
||||
Assert.AreEqual(LeanData.GetCommonTickTypeForCommonDataTypes(typeof(Tick), SecurityType.Forex), TickType.Quote);
|
||||
}
|
||||
|
||||
[TestCase("forex/fxcm/eurusd/20160101_quote.zip", true, SecurityType.Forex)]
|
||||
[TestCase("Data/f/fxcm/eurusd/20160101_quote.zip", false, SecurityType.Base)]
|
||||
[TestCase("ooooooooooooooooooooooooooooooooooooooooooooooooooooooo", false, SecurityType.Base)]
|
||||
[TestCase("", false, SecurityType.Base)]
|
||||
[TestCase(null, false, SecurityType.Base)]
|
||||
[TestCase("forex/fxcm/eurusd/20160101_quote.zip", true, SecurityType.Forex, Market.FXCM)]
|
||||
[TestCase("Data/f/fxcm/eurusd/20160101_quote.zip", false, SecurityType.Base, "")]
|
||||
[TestCase("ooooooooooooooooooooooooooooooooooooooooooooooooooooooo", false, SecurityType.Base, "")]
|
||||
[TestCase("", false, SecurityType.Base, "")]
|
||||
[TestCase(null, false, SecurityType.Base, "")]
|
||||
|
||||
[TestCase("Data/option/u sa/minute/aapl/20140606_trade_american.zip", true, SecurityType.Option)]
|
||||
[TestCase("../Data/equity/usa/daily/aapl.zip", true, SecurityType.Equity)]
|
||||
[TestCase("Data/cfd/oanda/minute/bcousd/20160101_trade.zip", true, SecurityType.Cfd)]
|
||||
[TestCase("Data\\alternative\\estimize\\consensus\\aapl.csv", true, SecurityType.Base)]
|
||||
[TestCase("../../../Data/option/usa/minute/spy/20200922_quote_american.zip", true, SecurityType.Option)]
|
||||
[TestCase("../../../Data/futureoption/comex/minute/og/20200428/20200105_quote_american.zip", true, SecurityType.FutureOption)]
|
||||
public void TryParseSecurityType(string path, bool result, SecurityType expectedSecurityType)
|
||||
[TestCase("Data/option/u sa/minute/aapl/20140606_trade_american.zip", true, SecurityType.Option, "")]
|
||||
[TestCase("../Data/equity/usa/daily/aapl.zip", true, SecurityType.Equity, "usa")]
|
||||
[TestCase("Data/cfd/oanda/minute/bcousd/20160101_trade.zip", true, SecurityType.Cfd, "oanda")]
|
||||
[TestCase("Data\\alternative\\estimize\\consensus\\aapl.csv", true, SecurityType.Base, "")]
|
||||
[TestCase("../../../Data/option/usa/minute/spy/20200922_quote_american.zip", true, SecurityType.Option, "usa")]
|
||||
[TestCase("../../../Data/futureoption/comex/minute/og/20200428/20200105_quote_american.zip", true, SecurityType.FutureOption, "comex")]
|
||||
public void TryParseSecurityType(string path, bool result, SecurityType expectedSecurityType, string market)
|
||||
{
|
||||
Assert.AreEqual(result, LeanData.TryParseSecurityType(path, out var securityType));
|
||||
Assert.AreEqual(result, LeanData.TryParseSecurityType(path, out var securityType, out var parsedMarket));
|
||||
Assert.AreEqual(expectedSecurityType, securityType);
|
||||
Assert.AreEqual(market, parsedMarket);
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
||||
@@ -31,7 +31,6 @@ namespace QuantConnect.Tests.Engine.DataFeeds
|
||||
[TestFixture]
|
||||
public class DataQueueHandlerManagerTests
|
||||
{
|
||||
[TestCase("ZerodhaBrokerage")]
|
||||
[TestCase("TradierBrokerage")]
|
||||
[TestCase("QuantConnect.Brokerages.InteractiveBrokers.InteractiveBrokersBrokerage")]
|
||||
[TestCase("OandaBrokerage")]
|
||||
@@ -51,7 +50,7 @@ namespace QuantConnect.Tests.Engine.DataFeeds
|
||||
var dataHandlers = Newtonsoft.Json.JsonConvert.SerializeObject(new[] { "FakeDataQueue" });
|
||||
var jobWithArrayIDQH = new LiveNodePacket
|
||||
{
|
||||
Brokerage = "ZerodhaBrokerage",
|
||||
Brokerage = "OandaBrokerage",
|
||||
DataQueueHandler = dataHandlers
|
||||
};
|
||||
var compositeDataQueueHandler = new DataQueueHandlerManager();
|
||||
@@ -74,7 +73,7 @@ namespace QuantConnect.Tests.Engine.DataFeeds
|
||||
var dataHandlers = Newtonsoft.Json.JsonConvert.SerializeObject(new[] { "FakeDataQueue" });
|
||||
var job = new LiveNodePacket
|
||||
{
|
||||
Brokerage = "ZerodhaBrokerage",
|
||||
Brokerage = "OandaBrokerage",
|
||||
DataQueueHandler = dataHandlers
|
||||
};
|
||||
var compositeDataQueueHandler = new DataQueueHandlerManager();
|
||||
@@ -107,7 +106,7 @@ namespace QuantConnect.Tests.Engine.DataFeeds
|
||||
public void DoubleSubscribe()
|
||||
{
|
||||
var compositeDataQueueHandler = new DataQueueHandlerManager();
|
||||
compositeDataQueueHandler.SetJob(new LiveNodePacket { Brokerage = "ZerodhaBrokerage", DataQueueHandler = "[ \"TestDataHandler\" ]" });
|
||||
compositeDataQueueHandler.SetJob(new LiveNodePacket { Brokerage = "OandaBrokerage", DataQueueHandler = "[ \"TestDataHandler\" ]" });
|
||||
|
||||
var dataConfig = GetConfig();
|
||||
var enumerator = compositeDataQueueHandler.Subscribe(dataConfig, (_, _) => {});
|
||||
@@ -121,7 +120,7 @@ namespace QuantConnect.Tests.Engine.DataFeeds
|
||||
{
|
||||
TestDataHandler.UnsubscribeCounter = 0;
|
||||
var compositeDataQueueHandler = new DataQueueHandlerManager();
|
||||
compositeDataQueueHandler.SetJob(new LiveNodePacket { Brokerage = "ZerodhaBrokerage", DataQueueHandler = "[ \"TestDataHandler\" ]" });
|
||||
compositeDataQueueHandler.SetJob(new LiveNodePacket { Brokerage = "OandaBrokerage", DataQueueHandler = "[ \"TestDataHandler\" ]" });
|
||||
|
||||
var dataConfig = GetConfig();
|
||||
var enumerator = compositeDataQueueHandler.Subscribe(dataConfig, (_, _) => {});
|
||||
@@ -142,7 +141,7 @@ namespace QuantConnect.Tests.Engine.DataFeeds
|
||||
TestDataHandler.UnsubscribeCounter = 0;
|
||||
TestDataHandler.SubscribeCounter = 0;
|
||||
var compositeDataQueueHandler = new DataQueueHandlerManager();
|
||||
compositeDataQueueHandler.SetJob(new LiveNodePacket { Brokerage = "ZerodhaBrokerage", DataQueueHandler = "[ \"TestDataHandler\" ]" });
|
||||
compositeDataQueueHandler.SetJob(new LiveNodePacket { Brokerage = "OandaBrokerage", DataQueueHandler = "[ \"TestDataHandler\" ]" });
|
||||
|
||||
var canonicalSymbol = Symbols.ES_Future_Chain.UpdateMappedSymbol(Symbols.Future_ESZ18_Dec2018.ID.ToString());
|
||||
var canonicalConfig = GetConfig(canonicalSymbol);
|
||||
|
||||
@@ -644,6 +644,74 @@ namespace QuantConnect.Tests.Engine.DataFeeds
|
||||
Log.Trace("Count: " + count + " ReaderCount: " + RestApiBaseData.ReaderCount);
|
||||
}
|
||||
|
||||
[TestCase(DataNormalizationMode.Raw)]
|
||||
[TestCase(DataNormalizationMode.BackwardsRatio)]
|
||||
[TestCase(DataNormalizationMode.BackwardsPanamaCanal)]
|
||||
[TestCase(DataNormalizationMode.ForwardPanamaCanal)]
|
||||
public void LivePriceScaling(DataNormalizationMode dataNormalizationMode)
|
||||
{
|
||||
var feed = RunDataFeed();
|
||||
_algorithm.SetFinishedWarmingUp();
|
||||
|
||||
var security = _algorithm.AddFuture("ES",
|
||||
dataNormalizationMode: dataNormalizationMode);
|
||||
var symbol = security.Symbol;
|
||||
|
||||
var receivedSecurityChanges = false;
|
||||
var receivedData = false;
|
||||
|
||||
var assertPrice = new Action<decimal>((decimal price) =>
|
||||
{
|
||||
if (dataNormalizationMode == DataNormalizationMode.ForwardPanamaCanal && price < 150)
|
||||
{
|
||||
throw new Exception($"unexpected price {price} for {symbol} @{security.LocalTime}");
|
||||
}
|
||||
else if (dataNormalizationMode == DataNormalizationMode.Raw && price == 2)
|
||||
{
|
||||
throw new Exception($"unexpected price {price} for {symbol} @{security.LocalTime}");
|
||||
}
|
||||
else if (dataNormalizationMode == DataNormalizationMode.BackwardsPanamaCanal && price < -150)
|
||||
{
|
||||
throw new Exception($"unexpected price {price} for {symbol} @{security.LocalTime}");
|
||||
}
|
||||
else if (dataNormalizationMode == DataNormalizationMode.BackwardsRatio && Math.Abs(price - 1.48m) > price * 0.1m)
|
||||
{
|
||||
throw new Exception($"unexpected price {price} for {symbol} @{security.LocalTime}");
|
||||
}
|
||||
});
|
||||
|
||||
var lastPrice = 0m;
|
||||
ConsumeBridge(feed, TimeSpan.FromSeconds(10), ts =>
|
||||
{
|
||||
foreach (var addedSecurity in ts.SecurityChanges.AddedSecurities)
|
||||
{
|
||||
if (addedSecurity.Symbol == symbol)
|
||||
{
|
||||
receivedSecurityChanges = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (ts.Slice.Bars.ContainsKey(symbol))
|
||||
{
|
||||
receivedData = true;
|
||||
assertPrice(ts.Slice.Bars[symbol].Price);
|
||||
}
|
||||
|
||||
if (lastPrice != security.Price && security.HasData)
|
||||
{
|
||||
lastPrice = security.Price;
|
||||
// assert realtime prices too
|
||||
assertPrice(lastPrice);
|
||||
}
|
||||
},
|
||||
alwaysInvoke: true,
|
||||
secondsTimeStep: 60 * 60 * 8,
|
||||
endDate: _startDate.AddDays(7));
|
||||
|
||||
Assert.IsTrue(receivedSecurityChanges, "Did not add symbol!");
|
||||
Assert.IsTrue(receivedData, "Did not get any symbol data!");
|
||||
}
|
||||
|
||||
[TestCase("AAPL", SecurityType.Equity)]
|
||||
[TestCase("BTCUSD", SecurityType.Crypto)]
|
||||
[TestCase("SPX500USD", SecurityType.Cfd)]
|
||||
@@ -653,7 +721,6 @@ namespace QuantConnect.Tests.Engine.DataFeeds
|
||||
public void UserDefinedUniverseSelection(string ticker, SecurityType securityType)
|
||||
{
|
||||
var feed = RunDataFeed();
|
||||
_algorithm.SetDateTime(_manualTimeProvider.GetUtcNow());
|
||||
_algorithm.SetFinishedWarmingUp();
|
||||
|
||||
Symbol symbol = null;
|
||||
@@ -1320,9 +1387,10 @@ namespace QuantConnect.Tests.Engine.DataFeeds
|
||||
Func<bool> canPerformSelection = null)
|
||||
{
|
||||
_algorithm.SetStartDate(_startDate);
|
||||
_algorithm.SetDateTime(_manualTimeProvider.GetUtcNow());
|
||||
|
||||
var lastTime = _manualTimeProvider.GetUtcNow();
|
||||
getNextTicksFunction = getNextTicksFunction ?? (fdqh =>
|
||||
getNextTicksFunction ??= (fdqh =>
|
||||
{
|
||||
var time = _manualTimeProvider.GetUtcNow();
|
||||
if (time == lastTime) return Enumerable.Empty<BaseData>();
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/*
|
||||
/*
|
||||
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
|
||||
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
|
||||
*
|
||||
@@ -19,6 +19,7 @@ using QuantConnect.Interfaces;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using QuantConnect.Configuration;
|
||||
using QuantConnect.ToolBox.BitfinexDownloader;
|
||||
|
||||
namespace QuantConnect.Tests.ToolBox
|
||||
{
|
||||
@@ -53,5 +54,26 @@ namespace QuantConnect.Tests.ToolBox
|
||||
|
||||
Assert.AreEqual(expectedCount, tickers.Count);
|
||||
}
|
||||
|
||||
[TestCase("--app=BFXDL --from-date=20171101-00:00:00 --tickers=1INCHUSD --resolution=Minute", 1)]
|
||||
[TestCase("--app=BFXDL --from-date=20171101-00:00:00 --tickers=1INCHUSD,ADAUSDT --resolution=Minute", 2)]
|
||||
[TestCase("--app=BFXDL --from-date=20171101-00:00:00 --tickers=1INCHUSD,tADAUST --resolution=Minute", 2)]
|
||||
public void CanParseBitfinexTickersCorrectly(string args, int expectedCount)
|
||||
{
|
||||
var options = ToolboxArgumentParser.ParseArguments(args.Split(' '));
|
||||
var tickers = ToolboxArgumentParser.GetTickers(options);
|
||||
|
||||
var downloader = new BitfinexDataDownloader();
|
||||
var count = 0;
|
||||
foreach (var ticker in tickers)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(downloader.GetSymbol(ticker)))
|
||||
{
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
Assert.AreEqual(expectedCount, count);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -97,7 +97,18 @@ namespace QuantConnect.ToolBox.BitfinexDownloader
|
||||
/// <returns></returns>
|
||||
internal Symbol GetSymbol(string ticker)
|
||||
{
|
||||
return _symbolMapper.GetLeanSymbol(ticker, SecurityType.Crypto, Market.Bitfinex);
|
||||
if (_symbolMapper.IsKnownBrokerageSymbol(ticker))
|
||||
{
|
||||
return _symbolMapper.GetLeanSymbol(ticker, SecurityType.Crypto, Market.Bitfinex);
|
||||
}
|
||||
else if (SymbolPropertiesDatabase.FromDataFolder().ContainsKey(Market.Bitfinex, ticker, SecurityType.Crypto))
|
||||
{
|
||||
return Symbol.Create(ticker, SecurityType.Crypto, Market.Bitfinex);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception($"Unknown ticker symbol: {ticker}");
|
||||
}
|
||||
}
|
||||
|
||||
#region Console Helper
|
||||
|
||||
@@ -36,7 +36,6 @@ using QuantConnect.ToolBox.Polygon;
|
||||
using QuantConnect.ToolBox.QuantQuoteConverter;
|
||||
using QuantConnect.ToolBox.RandomDataGenerator;
|
||||
using QuantConnect.ToolBox.YahooDownloader;
|
||||
using QuantConnect.ToolBox.ZerodhaDownloader;
|
||||
using QuantConnect.Util;
|
||||
using System;
|
||||
using System.IO;
|
||||
@@ -87,10 +86,6 @@ namespace QuantConnect.ToolBox
|
||||
: DateTime.UtcNow;
|
||||
switch (targetApp)
|
||||
{
|
||||
case "zdl":
|
||||
case "zerodhadownloader":
|
||||
ZerodhaDataDownloaderProgram.ZerodhaDataDownloader(tickers, market, resolution, securityType, fromDate, toDate);
|
||||
break;
|
||||
case "gdaxdl":
|
||||
case "gdaxdownloader":
|
||||
GDAXDownloaderProgram.GDAXDownloader(tickers, resolution, fromDate, toDate);
|
||||
|
||||
@@ -1,150 +0,0 @@
|
||||
/*
|
||||
* 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 System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NodaTime;
|
||||
using QuantConnect.Brokerages.Zerodha;
|
||||
using QuantConnect.Brokerages.Zerodha.Messages;
|
||||
using QuantConnect.Configuration;
|
||||
using QuantConnect.Data;
|
||||
using QuantConnect.Data.Market;
|
||||
using QuantConnect.Logging;
|
||||
using QuantConnect.Util;
|
||||
using QuantConnect.Securities;
|
||||
|
||||
namespace QuantConnect.ToolBox.ZerodhaDownloader
|
||||
{
|
||||
public class ZerodhaDataDownloaderProgram
|
||||
{
|
||||
private static readonly string _apiKey = Config.Get("zerodha-api-key");
|
||||
private static readonly string _accessToken = Config.Get("zerodha-access-token");
|
||||
|
||||
/// <summary>
|
||||
/// Zerodha Historical Data Downloader Toolbox Project For LEAN Algorithmic Trading Engine.
|
||||
/// By @itsbalamurali
|
||||
/// </summary>
|
||||
public static void ZerodhaDataDownloader(IList<string> tickers, string market, string resolution, string securityType, DateTime startDate, DateTime endDate)
|
||||
{
|
||||
|
||||
if (resolution.IsNullOrEmpty() || tickers.IsNullOrEmpty())
|
||||
{
|
||||
Log.Error("ZerodhaDataDownloader ERROR: '--tickers=', --securityType, '--market' or '--resolution=' parameter is missing");
|
||||
Log.Error("--tickers=eg JSWSTEEL,TCS,INFY");
|
||||
Log.Error("--market=MCX/NSE/NFO/CDS/BSE");
|
||||
Log.Error("--security-type=Equity/Future/Option/Commodity");
|
||||
Log.Error("--resolution=Minute/Hour/Daily/Tick");
|
||||
Environment.Exit(1);
|
||||
}
|
||||
try
|
||||
{
|
||||
var kite = new Kite(_apiKey, _accessToken);
|
||||
var symbolMapper = new ZerodhaSymbolMapper(kite);
|
||||
var castResolution = (Resolution)Enum.Parse(typeof(Resolution), resolution);
|
||||
var castSecurityType = (SecurityType)Enum.Parse(typeof(SecurityType), securityType);
|
||||
|
||||
// Load settings from config.json and create downloader
|
||||
var dataDirectory = Config.Get("data-folder", "../../../Data");
|
||||
var marketHoursDatabase = MarketHoursDatabase.FromDataFolder();
|
||||
|
||||
foreach (var pair in tickers)
|
||||
{
|
||||
var zerodhaTokenList = symbolMapper.GetZerodhaInstrumentTokenList(pair);
|
||||
|
||||
// Download data
|
||||
var pairObject = Symbol.Create(pair, castSecurityType, market);
|
||||
|
||||
var exchangeTimeZone = marketHoursDatabase.GetExchangeHours(market, pairObject, castSecurityType).TimeZone;
|
||||
var dataTimeZone = marketHoursDatabase.GetDataTimeZone(market, pairObject, castSecurityType);
|
||||
|
||||
if (pairObject.ID.SecurityType != SecurityType.Forex || pairObject.ID.SecurityType != SecurityType.Cfd || pairObject.ID.SecurityType != SecurityType.Crypto || pairObject.ID.SecurityType == SecurityType.Base)
|
||||
{
|
||||
|
||||
if (pairObject.ID.SecurityType == SecurityType.Forex || pairObject.ID.SecurityType == SecurityType.Cfd || pairObject.ID.SecurityType == SecurityType.Crypto || pairObject.ID.SecurityType == SecurityType.Base)
|
||||
{
|
||||
throw new ArgumentException("Invalid security type: " + pairObject.ID.SecurityType);
|
||||
}
|
||||
|
||||
if (startDate >= endDate)
|
||||
{
|
||||
throw new ArgumentException("Invalid date range specified");
|
||||
}
|
||||
|
||||
var start = startDate.ConvertTo(DateTimeZone.Utc, exchangeTimeZone);
|
||||
var end = endDate.ConvertTo(DateTimeZone.Utc, exchangeTimeZone);
|
||||
|
||||
// Write data
|
||||
var writer = new LeanDataWriter(castResolution, pairObject, dataDirectory);
|
||||
IList<TradeBar> fileEnum = new List<TradeBar>();
|
||||
IEnumerable<Historical> history = new List<Historical>();
|
||||
var timeSpan = new TimeSpan();
|
||||
switch (castResolution)
|
||||
{
|
||||
case Resolution.Tick:
|
||||
throw new ArgumentException("Zerodha Doesn't support tick resolution");
|
||||
|
||||
case Resolution.Minute:
|
||||
|
||||
if ((end - start).Days > 60)
|
||||
throw new ArgumentOutOfRangeException("For minutes data Zerodha support 60 days data download");
|
||||
history = GetHistoryFromZerodha(kite, zerodhaTokenList, startDate, endDate, "minute");
|
||||
timeSpan = Time.OneMinute;
|
||||
break;
|
||||
|
||||
case Resolution.Hour:
|
||||
if ((end - start).Days > 400)
|
||||
throw new ArgumentOutOfRangeException("For daily data Zerodha support 400 days data download");
|
||||
history = GetHistoryFromZerodha(kite, zerodhaTokenList, startDate, endDate, "60minute");
|
||||
timeSpan = Time.OneHour;
|
||||
break;
|
||||
|
||||
case Resolution.Daily:
|
||||
if ((end - start).Days > 400)
|
||||
throw new ArgumentOutOfRangeException("For daily data Zerodha support 400 days data download");
|
||||
history = GetHistoryFromZerodha(kite, zerodhaTokenList, startDate, endDate, "day");
|
||||
timeSpan = Time.OneDay;
|
||||
break;
|
||||
}
|
||||
|
||||
foreach (var bar in history)
|
||||
{
|
||||
var linedata = new TradeBar(bar.TimeStamp.ConvertFromUtc(dataTimeZone), pairObject, bar.Open, bar.High, bar.Low, bar.Close, bar.Volume, timeSpan);
|
||||
fileEnum.Add(linedata);
|
||||
}
|
||||
|
||||
writer.Write(fileEnum);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception err)
|
||||
{
|
||||
Log.Error($"ZerodhaDataDownloadManager.OnError(): Message: {err.Message} Exception: {err.InnerException}");
|
||||
}
|
||||
}
|
||||
|
||||
private static IEnumerable<Historical> GetHistoryFromZerodha(Kite kite, List<uint> zerodhaTokenList, DateTime startDate, DateTime endDate, string interval)
|
||||
{
|
||||
var history = Enumerable.Empty<Historical>();
|
||||
foreach (var token in zerodhaTokenList)
|
||||
{
|
||||
var tempHistory = kite.GetHistoricalData(token.ToStringInvariant(), startDate, endDate, interval);
|
||||
history = history.Concat(tempHistory);
|
||||
}
|
||||
history = history.OrderBy(x=>x.TimeStamp);
|
||||
return history;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user