Compare commits
33 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c75b4a98b4 | ||
|
|
288501bd3b | ||
|
|
9e7ead1a19 | ||
|
|
b80e274d4f | ||
|
|
9a355c9be5 | ||
|
|
303b95ab50 | ||
|
|
d826d267f4 | ||
|
|
eb55311052 | ||
|
|
27d18fa2e8 | ||
|
|
bb0c671e7c | ||
|
|
c8dc343c13 | ||
|
|
b6815d22de | ||
|
|
459f60603b | ||
|
|
1aaaa20c61 | ||
|
|
07b6572bf9 | ||
|
|
a675aca7e5 | ||
|
|
87db3fe379 | ||
|
|
74321d1727 | ||
|
|
9fd50a302e | ||
|
|
fc0b2f3fa4 | ||
|
|
c4a2d6eef4 | ||
|
|
c2b60e4e48 | ||
|
|
ca9e55fda6 | ||
|
|
b698641c90 | ||
|
|
e5c709ee29 | ||
|
|
ca787d0a25 | ||
|
|
b1a1277eca | ||
|
|
30d7fb042b | ||
|
|
d1bb70fbb7 | ||
|
|
0946bfc2fb | ||
|
|
f34be8e3ff | ||
|
|
e1d1e28bb8 | ||
|
|
5ea9f04b10 |
2
.github/workflows/gh-actions.yml
vendored
2
.github/workflows/gh-actions.yml
vendored
@@ -28,3 +28,5 @@ jobs:
|
||||
./ci_build_stubs.sh -t -g -p
|
||||
env:
|
||||
PYPI_API_TOKEN: ${{ secrets.PYPI_API_TOKEN }}
|
||||
ADDITIONAL_STUBS_REPOS: ${{ secrets.ADDITIONAL_STUBS_REPOS }}
|
||||
QC_GIT_TOKEN: ${{ secrets.QC_GIT_TOKEN }}
|
||||
|
||||
4
.vscode/launch.json
vendored
4
.vscode/launch.json
vendored
@@ -8,8 +8,8 @@
|
||||
marketplace.
|
||||
|
||||
Attach to Python:
|
||||
Will attempt to attach to LEAN running locally using PTVSD. Requires that the process is
|
||||
actively running and config is set: "debugging": true, "debugging-method": "PTVSD",
|
||||
Will attempt to attach to LEAN running locally using DebugPy. Requires that the process is
|
||||
actively running and config is set: "debugging": true, "debugging-method": "DebugPy",
|
||||
Requires Python extension from the marketplace. Currently only works with algorithms in
|
||||
Algorithm.Python directory. This is because we map that directory to our build directory
|
||||
that contains the py file at runtime. If using another location change "localRoot" value
|
||||
|
||||
2
.vscode/readme.md
vendored
2
.vscode/readme.md
vendored
@@ -95,7 +95,7 @@ Python algorithms require a little extra work in order to be able to debug them.
|
||||
First in order to debug a Python algorithm in VS Code we must make the following change to our configuration (Launcher\config.json) under the comment debugging configuration:
|
||||
|
||||
"debugging": true,
|
||||
"debugging-method": "PTVSD",
|
||||
"debugging-method": "DebugPy,
|
||||
|
||||
In setting this we are telling Lean to expect a debugger connection using ‘Python Tools for Visual Studio Debugger’. Once this is set Lean will stop upon initialization and await a connection to the debugger via port 5678.
|
||||
|
||||
|
||||
@@ -0,0 +1,150 @@
|
||||
/*
|
||||
* 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.Linq;
|
||||
using QuantConnect.Data;
|
||||
using QuantConnect.Interfaces;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace QuantConnect.Algorithm.CSharp
|
||||
{
|
||||
/// <summary>
|
||||
/// Regression algorithm reproducing issue where underlying option contract would be removed with the first call
|
||||
/// too RemoveOptionContract
|
||||
/// </summary>
|
||||
public class AddTwoAndRemoveOneOptionContractRegressionAlgorithm : QCAlgorithm, IRegressionAlgorithmDefinition
|
||||
{
|
||||
private Symbol _contract1;
|
||||
private Symbol _contract2;
|
||||
private bool _hasRemoved;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
SetStartDate(2014, 06, 06);
|
||||
SetEndDate(2014, 06, 06);
|
||||
|
||||
UniverseSettings.DataNormalizationMode = DataNormalizationMode.Raw;
|
||||
UniverseSettings.MinimumTimeInUniverse = TimeSpan.Zero;
|
||||
|
||||
var aapl = QuantConnect.Symbol.Create("AAPL", SecurityType.Equity, Market.USA);
|
||||
|
||||
var contracts = OptionChainProvider.GetOptionContractList(aapl, Time)
|
||||
.OrderBy(symbol => symbol.ID.Symbol)
|
||||
.Where(optionContract => optionContract.ID.OptionRight == OptionRight.Call
|
||||
&& optionContract.ID.OptionStyle == OptionStyle.American)
|
||||
.Take(2)
|
||||
.ToList();
|
||||
|
||||
_contract1 = contracts[0];
|
||||
_contract2 = contracts[1];
|
||||
AddOptionContract(_contract1);
|
||||
AddOptionContract(_contract2);
|
||||
}
|
||||
|
||||
public override void OnData(Slice slice)
|
||||
{
|
||||
if (slice.HasData)
|
||||
{
|
||||
if (!_hasRemoved)
|
||||
{
|
||||
RemoveOptionContract(_contract1);
|
||||
_hasRemoved = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
var subscriptions =
|
||||
SubscriptionManager.SubscriptionDataConfigService.GetSubscriptionDataConfigs("AAPL");
|
||||
if (subscriptions.Count == 0)
|
||||
{
|
||||
throw new Exception("No configuration for underlying was found!");
|
||||
}
|
||||
|
||||
if (!Portfolio.Invested)
|
||||
{
|
||||
Buy(_contract2, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnEndOfAlgorithm()
|
||||
{
|
||||
if (!_hasRemoved)
|
||||
{
|
||||
throw new Exception("Expect a single call to OnData where we removed the option and underlying");
|
||||
}
|
||||
}
|
||||
|
||||
/// <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 bool CanRunLocally { get; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// This is used by the regression test system to indicate which languages this algorithm is written in.
|
||||
/// </summary>
|
||||
public Language[] Languages { get; } = { Language.CSharp };
|
||||
|
||||
/// <summary>
|
||||
/// This is used by the regression test system to indicate what the expected statistics are from running the algorithm
|
||||
/// </summary>
|
||||
public Dictionary<string, string> ExpectedStatistics => new Dictionary<string, string>
|
||||
{
|
||||
{"Total Trades", "2"},
|
||||
{"Average Win", "0%"},
|
||||
{"Average Loss", "0%"},
|
||||
{"Compounding Annual Return", "0%"},
|
||||
{"Drawdown", "0%"},
|
||||
{"Expectancy", "0"},
|
||||
{"Net Profit", "0%"},
|
||||
{"Sharpe Ratio", "0"},
|
||||
{"Probabilistic Sharpe Ratio", "0%"},
|
||||
{"Loss Rate", "0%"},
|
||||
{"Win Rate", "0%"},
|
||||
{"Profit-Loss Ratio", "0"},
|
||||
{"Alpha", "0"},
|
||||
{"Beta", "0"},
|
||||
{"Annual Standard Deviation", "0"},
|
||||
{"Annual Variance", "0"},
|
||||
{"Information Ratio", "0"},
|
||||
{"Tracking Error", "0"},
|
||||
{"Treynor Ratio", "0"},
|
||||
{"Total Fees", "$2.00"},
|
||||
{"Estimated Strategy Capacity", "$230000.00"},
|
||||
{"Lowest Capacity Asset", "AAPL VXBK4QQIRLZA|AAPL R735QTJ8XC9X"},
|
||||
{"Fitness Score", "0"},
|
||||
{"Kelly Criterion Estimate", "0"},
|
||||
{"Kelly Criterion Probability Value", "0"},
|
||||
{"Sortino Ratio", "0"},
|
||||
{"Return Over Maximum Drawdown", "0"},
|
||||
{"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", "228194dcc6fd8689a67f383577ee2d85"}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -13,6 +13,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using QuantConnect.Data;
|
||||
using QuantConnect.Orders;
|
||||
using QuantConnect.Interfaces;
|
||||
@@ -62,7 +63,11 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
{
|
||||
foreach (var changedEvent in data.SymbolChangedEvents.Values)
|
||||
{
|
||||
Log($"{Time} - SymbolChanged event: {changedEvent}");
|
||||
Debug($"{Time} - SymbolChanged event: {changedEvent}");
|
||||
if (Time.TimeOfDay != TimeSpan.Zero)
|
||||
{
|
||||
throw new Exception($"{Time} unexpected symbol changed event {changedEvent}!");
|
||||
}
|
||||
}
|
||||
|
||||
if (!Portfolio.Invested)
|
||||
|
||||
@@ -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>
|
||||
@@ -72,6 +76,15 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
/// <param name="slice">The current slice of data keyed by symbol string</param>
|
||||
public override void OnData(Slice slice)
|
||||
{
|
||||
foreach (var changedEvent in slice.SymbolChangedEvents.Values)
|
||||
{
|
||||
Debug($"{Time} - SymbolChanged event: {changedEvent}");
|
||||
if (Time.TimeOfDay != TimeSpan.Zero)
|
||||
{
|
||||
throw new Exception($"{Time} unexpected symbol changed event {changedEvent}!");
|
||||
}
|
||||
}
|
||||
|
||||
if (!Portfolio.Invested)
|
||||
{
|
||||
foreach(var chain in slice.FutureChains)
|
||||
@@ -112,6 +125,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>
|
||||
|
||||
@@ -46,7 +46,7 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
public override void Initialize()
|
||||
{
|
||||
SetStartDate(2013, 10, 08);
|
||||
SetEndDate(2013, 10, 10);
|
||||
SetEndDate(2014, 10, 10);
|
||||
SetCash(1000000);
|
||||
|
||||
var futureSP500 = AddFuture(RootSP500, Resolution);
|
||||
@@ -77,7 +77,7 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
).FirstOrDefault();
|
||||
|
||||
// if found, trade it
|
||||
if (contract != null)
|
||||
if (contract != null && IsMarketOpen(contract.Symbol))
|
||||
{
|
||||
_contractSymbol = contract.Symbol;
|
||||
MarketOrder(_contractSymbol, 1);
|
||||
@@ -88,6 +88,14 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
{
|
||||
Liquidate();
|
||||
}
|
||||
|
||||
foreach (var changedEvent in slice.SymbolChangedEvents.Values)
|
||||
{
|
||||
if (Time.TimeOfDay != TimeSpan.Zero)
|
||||
{
|
||||
throw new Exception($"{Time} unexpected symbol changed event {changedEvent}!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -105,34 +113,34 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
/// </summary>
|
||||
public virtual Dictionary<string, string> ExpectedStatistics => new Dictionary<string, string>
|
||||
{
|
||||
{"Total Trades", "6"},
|
||||
{"Average Win", "0%"},
|
||||
{"Average Loss", "-0.10%"},
|
||||
{"Compounding Annual Return", "-23.119%"},
|
||||
{"Drawdown", "0.300%"},
|
||||
{"Expectancy", "-1"},
|
||||
{"Net Profit", "-0.276%"},
|
||||
{"Sharpe Ratio", "-13.736"},
|
||||
{"Total Trades", "92"},
|
||||
{"Average Win", "0.08%"},
|
||||
{"Average Loss", "-0.01%"},
|
||||
{"Compounding Annual Return", "-0.450%"},
|
||||
{"Drawdown", "0.500%"},
|
||||
{"Expectancy", "-0.824"},
|
||||
{"Net Profit", "-0.453%"},
|
||||
{"Sharpe Ratio", "-1.803"},
|
||||
{"Probabilistic Sharpe Ratio", "0%"},
|
||||
{"Loss Rate", "100%"},
|
||||
{"Win Rate", "0%"},
|
||||
{"Profit-Loss Ratio", "0"},
|
||||
{"Alpha", "-0.526"},
|
||||
{"Beta", "0.057"},
|
||||
{"Annual Standard Deviation", "0.015"},
|
||||
{"Loss Rate", "98%"},
|
||||
{"Win Rate", "2%"},
|
||||
{"Profit-Loss Ratio", "7.09"},
|
||||
{"Alpha", "-0.003"},
|
||||
{"Beta", "-0.001"},
|
||||
{"Annual Standard Deviation", "0.002"},
|
||||
{"Annual Variance", "0"},
|
||||
{"Information Ratio", "-31.088"},
|
||||
{"Tracking Error", "0.189"},
|
||||
{"Treynor Ratio", "-3.51"},
|
||||
{"Total Fees", "$11.10"},
|
||||
{"Estimated Strategy Capacity", "$200000000.00"},
|
||||
{"Lowest Capacity Asset", "GC VOFJUCDY9XNH"},
|
||||
{"Fitness Score", "0"},
|
||||
{"Information Ratio", "-1.394"},
|
||||
{"Tracking Error", "0.089"},
|
||||
{"Treynor Ratio", "4.298"},
|
||||
{"Total Fees", "$170.20"},
|
||||
{"Estimated Strategy Capacity", "$36000.00"},
|
||||
{"Lowest Capacity Asset", "ES VP274HSU1AF5"},
|
||||
{"Fitness Score", "0.009"},
|
||||
{"Kelly Criterion Estimate", "0"},
|
||||
{"Kelly Criterion Probability Value", "0"},
|
||||
{"Sortino Ratio", "-17.118"},
|
||||
{"Return Over Maximum Drawdown", "-83.844"},
|
||||
{"Portfolio Turnover", "0.16"},
|
||||
{"Sortino Ratio", "-0.8"},
|
||||
{"Return Over Maximum Drawdown", "-0.992"},
|
||||
{"Portfolio Turnover", "0.025"},
|
||||
{"Total Insights Generated", "0"},
|
||||
{"Total Insights Closed", "0"},
|
||||
{"Total Insights Analysis Completed", "0"},
|
||||
@@ -146,7 +154,7 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
{"Mean Population Magnitude", "0%"},
|
||||
{"Rolling Averaged Population Direction", "0%"},
|
||||
{"Rolling Averaged Population Magnitude", "0%"},
|
||||
{"OrderListHash", "512f55519e5221c7e82e1d9f5ddd1b9f"}
|
||||
{"OrderListHash", "09b2f274fa2385597a803e58b784f675"}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,34 +49,34 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
/// </summary>
|
||||
public override Dictionary<string, string> ExpectedStatistics => new Dictionary<string, string>
|
||||
{
|
||||
{"Total Trades", "140"},
|
||||
{"Total Trades", "1988"},
|
||||
{"Average Win", "0.01%"},
|
||||
{"Average Loss", "-0.02%"},
|
||||
{"Compounding Annual Return", "-38.171%"},
|
||||
{"Drawdown", "0.400%"},
|
||||
{"Expectancy", "-0.369"},
|
||||
{"Net Profit", "-0.394%"},
|
||||
{"Sharpe Ratio", "-24.82"},
|
||||
{"Average Loss", "0.00%"},
|
||||
{"Compounding Annual Return", "-4.120%"},
|
||||
{"Drawdown", "4.200%"},
|
||||
{"Expectancy", "-0.870"},
|
||||
{"Net Profit", "-4.150%"},
|
||||
{"Sharpe Ratio", "-6.061"},
|
||||
{"Probabilistic Sharpe Ratio", "0%"},
|
||||
{"Loss Rate", "66%"},
|
||||
{"Win Rate", "34%"},
|
||||
{"Profit-Loss Ratio", "0.84"},
|
||||
{"Alpha", "0.42"},
|
||||
{"Beta", "-0.041"},
|
||||
{"Annual Standard Deviation", "0.01"},
|
||||
{"Loss Rate", "97%"},
|
||||
{"Win Rate", "3%"},
|
||||
{"Profit-Loss Ratio", "2.92"},
|
||||
{"Alpha", "-0.027"},
|
||||
{"Beta", "-0.006"},
|
||||
{"Annual Standard Deviation", "0.005"},
|
||||
{"Annual Variance", "0"},
|
||||
{"Information Ratio", "-65.112"},
|
||||
{"Tracking Error", "0.253"},
|
||||
{"Treynor Ratio", "6.024"},
|
||||
{"Total Fees", "$259.00"},
|
||||
{"Estimated Strategy Capacity", "$130000.00"},
|
||||
{"Lowest Capacity Asset", "GC VOFJUCDY9XNH"},
|
||||
{"Fitness Score", "0"},
|
||||
{"Information Ratio", "-1.66"},
|
||||
{"Tracking Error", "0.089"},
|
||||
{"Treynor Ratio", "4.919"},
|
||||
{"Total Fees", "$3677.80"},
|
||||
{"Estimated Strategy Capacity", "$2000.00"},
|
||||
{"Lowest Capacity Asset", "ES VP274HSU1AF5"},
|
||||
{"Fitness Score", "0.128"},
|
||||
{"Kelly Criterion Estimate", "0"},
|
||||
{"Kelly Criterion Probability Value", "0"},
|
||||
{"Sortino Ratio", "-43.422"},
|
||||
{"Return Over Maximum Drawdown", "-100.459"},
|
||||
{"Portfolio Turnover", "4.716"},
|
||||
{"Sortino Ratio", "-6.856"},
|
||||
{"Return Over Maximum Drawdown", "-0.995"},
|
||||
{"Portfolio Turnover", "0.648"},
|
||||
{"Total Insights Generated", "0"},
|
||||
{"Total Insights Closed", "0"},
|
||||
{"Total Insights Analysis Completed", "0"},
|
||||
@@ -90,7 +90,7 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
{"Mean Population Magnitude", "0%"},
|
||||
{"Rolling Averaged Population Direction", "0%"},
|
||||
{"Rolling Averaged Population Magnitude", "0%"},
|
||||
{"OrderListHash", "320067074c8dd771f69602ab07001f1e"}
|
||||
{"OrderListHash", "87d2b127c9859cad9d2c65ac9d76deb5"}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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"}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -69,7 +69,7 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
var contractsByExpiration = chain.Where(x => x.Expiry != Time.Date).OrderBy(x => x.Expiry);
|
||||
var contract = contractsByExpiration.FirstOrDefault();
|
||||
|
||||
if (contract != null)
|
||||
if (contract != null && IsMarketOpen(contract.Symbol))
|
||||
{
|
||||
// if found, trade it
|
||||
MarketOrder(contract.Symbol, 1);
|
||||
|
||||
@@ -76,7 +76,7 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
.ThenByDescending(x => x.Right)
|
||||
.FirstOrDefault();
|
||||
|
||||
if (atmContract != null)
|
||||
if (atmContract != null && IsMarketOpen(atmContract.Symbol))
|
||||
{
|
||||
// if found, trade it
|
||||
MarketOrder(atmContract.Symbol, 1);
|
||||
|
||||
85
Algorithm.CSharp/BinanceCashAccountFeeRegressionAlgorithm.cs
Normal file
85
Algorithm.CSharp/BinanceCashAccountFeeRegressionAlgorithm.cs
Normal file
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* 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.Brokerages;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace QuantConnect.Algorithm.CSharp
|
||||
{
|
||||
/// <summary>
|
||||
/// Binance cash account regression algorithm, reproduces issue https://github.com/QuantConnect/Lean/issues/6123
|
||||
/// </summary>
|
||||
public class BinanceCashAccountFeeRegressionAlgorithm : CryptoCashAccountFeeRegressionAlgorithm
|
||||
{
|
||||
public override void Initialize()
|
||||
{
|
||||
SetAccountCurrency("USDT");
|
||||
SetStartDate(2018, 05, 02);
|
||||
SetEndDate(2018, 05, 03);
|
||||
BrokerageName = BrokerageName.Binance;
|
||||
Pair = "BTCUSDT";
|
||||
base.Initialize();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This is used by the regression test system to indicate what the expected statistics are from running the algorithm
|
||||
/// </summary>
|
||||
public override Dictionary<string, string> ExpectedStatistics => new()
|
||||
{
|
||||
{"Total Trades", "49"},
|
||||
{"Average Win", "0%"},
|
||||
{"Average Loss", "0%"},
|
||||
{"Compounding Annual Return", "0%"},
|
||||
{"Drawdown", "0%"},
|
||||
{"Expectancy", "0"},
|
||||
{"Net Profit", "0%"},
|
||||
{"Sharpe Ratio", "0"},
|
||||
{"Probabilistic Sharpe Ratio", "0%"},
|
||||
{"Loss Rate", "0%"},
|
||||
{"Win Rate", "0%"},
|
||||
{"Profit-Loss Ratio", "0"},
|
||||
{"Alpha", "0"},
|
||||
{"Beta", "0"},
|
||||
{"Annual Standard Deviation", "0"},
|
||||
{"Annual Variance", "0"},
|
||||
{"Information Ratio", "0"},
|
||||
{"Tracking Error", "0"},
|
||||
{"Treynor Ratio", "0"},
|
||||
{"Total Fees", "$45.62"},
|
||||
{"Estimated Strategy Capacity", "$220000.00"},
|
||||
{"Lowest Capacity Asset", "BTCUSDT 18N"},
|
||||
{"Fitness Score", "0.208"},
|
||||
{"Kelly Criterion Estimate", "0"},
|
||||
{"Kelly Criterion Probability Value", "0"},
|
||||
{"Sortino Ratio", "79228162514264337593543950335"},
|
||||
{"Return Over Maximum Drawdown", "26.189"},
|
||||
{"Portfolio Turnover", "0.208"},
|
||||
{"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", "USDT0"},
|
||||
{"Total Accumulated Estimated Alpha Value", "USDT0"},
|
||||
{"Mean Population Estimated Insight Value", "USDT0"},
|
||||
{"Mean Population Direction", "0%"},
|
||||
{"Mean Population Magnitude", "0%"},
|
||||
{"Rolling Averaged Population Direction", "0%"},
|
||||
{"Rolling Averaged Population Magnitude", "0%"},
|
||||
{"OrderListHash", "7417649395922ff3791471b4f3b5c021"}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* 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.Brokerages;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace QuantConnect.Algorithm.CSharp
|
||||
{
|
||||
/// <summary>
|
||||
/// Bitfinex cash account regression algorithm, reproduces issue https://github.com/QuantConnect/Lean/issues/6123
|
||||
/// </summary>
|
||||
public class BitfinexCashAccountFeeRegressionAlgorithm : CryptoCashAccountFeeRegressionAlgorithm
|
||||
{
|
||||
public override void Initialize()
|
||||
{
|
||||
SetStartDate(2013, 10, 02);
|
||||
SetEndDate(2013, 10, 03);
|
||||
BrokerageName = BrokerageName.Bitfinex;
|
||||
Pair = "BTCUSD";
|
||||
base.Initialize();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This is used by the regression test system to indicate what the expected statistics are from running the algorithm
|
||||
/// </summary>
|
||||
public override Dictionary<string, string> ExpectedStatistics => new()
|
||||
{
|
||||
{"Total Trades", "49"},
|
||||
{"Average Win", "0%"},
|
||||
{"Average Loss", "0%"},
|
||||
{"Compounding Annual Return", "0%"},
|
||||
{"Drawdown", "0%"},
|
||||
{"Expectancy", "0"},
|
||||
{"Net Profit", "0%"},
|
||||
{"Sharpe Ratio", "0"},
|
||||
{"Probabilistic Sharpe Ratio", "0%"},
|
||||
{"Loss Rate", "0%"},
|
||||
{"Win Rate", "0%"},
|
||||
{"Profit-Loss Ratio", "0"},
|
||||
{"Alpha", "0"},
|
||||
{"Beta", "0"},
|
||||
{"Annual Standard Deviation", "0"},
|
||||
{"Annual Variance", "0"},
|
||||
{"Information Ratio", "0"},
|
||||
{"Tracking Error", "0"},
|
||||
{"Treynor Ratio", "0"},
|
||||
{"Total Fees", "$1.13"},
|
||||
{"Estimated Strategy Capacity", "$2000.00"},
|
||||
{"Lowest Capacity Asset", "BTCUSD E3"},
|
||||
{"Fitness Score", "0.002"},
|
||||
{"Kelly Criterion Estimate", "0"},
|
||||
{"Kelly Criterion Probability Value", "0"},
|
||||
{"Sortino Ratio", "79228162514264337593543950335"},
|
||||
{"Return Over Maximum Drawdown", "79228162514264337593543950335"},
|
||||
{"Portfolio Turnover", "0.002"},
|
||||
{"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", "7f892f0c42d8826ff770ee602fe207a2"}
|
||||
};
|
||||
}
|
||||
}
|
||||
105
Algorithm.CSharp/CryptoCashAccountFeeRegressionAlgorithm.cs
Normal file
105
Algorithm.CSharp/CryptoCashAccountFeeRegressionAlgorithm.cs
Normal file
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
* 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.Linq;
|
||||
using QuantConnect.Util;
|
||||
using QuantConnect.Data;
|
||||
using QuantConnect.Orders;
|
||||
using QuantConnect.Interfaces;
|
||||
using QuantConnect.Brokerages;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace QuantConnect.Algorithm.CSharp
|
||||
{
|
||||
/// <summary>
|
||||
/// Base crypto cash account regression algorithm trading in and out
|
||||
/// </summary>
|
||||
public abstract class CryptoCashAccountFeeRegressionAlgorithm : QCAlgorithm, IRegressionAlgorithmDefinition
|
||||
{
|
||||
private Symbol _symbol;
|
||||
|
||||
/// <summary>
|
||||
/// The target brokerage model name
|
||||
/// </summary>
|
||||
protected BrokerageName BrokerageName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The pair to add and trade
|
||||
/// </summary>
|
||||
protected string Pair { get; set; }
|
||||
|
||||
/// <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()
|
||||
{
|
||||
SetBrokerageModel(BrokerageName, AccountType.Cash);
|
||||
_symbol = AddCrypto(Pair, Resolution.Hour).Symbol;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// OnData event is the primary entry point for your algorithm. Each new data point will be pumped in here.
|
||||
/// </summary>
|
||||
/// <param name="data">Slice object keyed by symbol containing the stock data</param>
|
||||
public override void OnData(Slice data)
|
||||
{
|
||||
if (!Portfolio.Invested)
|
||||
{
|
||||
CurrencyPairUtil.DecomposeCurrencyPair(_symbol, out var baseCurrency, out var quoteCurrency);
|
||||
|
||||
var initialQuoteCurrency = Portfolio.CashBook[quoteCurrency].Amount;
|
||||
var ticket = Buy(_symbol, 0.1m);
|
||||
var filledEvent = ticket.OrderEvents.Single(orderEvent => orderEvent.Status == OrderStatus.Filled);
|
||||
|
||||
if (Portfolio.CashBook[baseCurrency].Amount != ticket.QuantityFilled
|
||||
|| filledEvent.FillQuantity != ticket.QuantityFilled
|
||||
|| (0.1m - filledEvent.OrderFee.Value.Amount) != ticket.QuantityFilled)
|
||||
{
|
||||
throw new Exception($"Unexpected BaseCurrency porfoltio status. Event {filledEvent}. CashBook: {Portfolio.CashBook}. ");
|
||||
}
|
||||
|
||||
if (Portfolio.CashBook[quoteCurrency].Amount != (initialQuoteCurrency - 0.1m * filledEvent.FillPrice))
|
||||
{
|
||||
throw new Exception($"Unexpected QuoteCurrency porfoltio status. Event {filledEvent}. CashBook: {Portfolio.CashBook}. ");
|
||||
}
|
||||
|
||||
if (Securities[_symbol].Holdings.Quantity != (0.1m - filledEvent.OrderFee.Value.Amount))
|
||||
{
|
||||
throw new Exception($"Unexpected Holdings: {Securities[_symbol].Holdings}. Event {filledEvent}");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Liquidate();
|
||||
}
|
||||
}
|
||||
|
||||
/// <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 bool CanRunLocally { get; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// This is used by the regression test system to indicate which languages this algorithm is written in.
|
||||
/// </summary>
|
||||
public Language[] Languages { get; } = { Language.CSharp };
|
||||
|
||||
/// <summary>
|
||||
/// This is used by the regression test system to indicate what the expected statistics are from running the algorithm
|
||||
/// </summary>
|
||||
public abstract Dictionary<string, string> ExpectedStatistics { get; }
|
||||
}
|
||||
}
|
||||
@@ -18,7 +18,9 @@ using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using Newtonsoft.Json;
|
||||
using QuantConnect.Data;
|
||||
using QuantConnect.Data.UniverseSelection;
|
||||
using QuantConnect.Interfaces;
|
||||
using QuantConnect.Securities;
|
||||
|
||||
namespace QuantConnect.Algorithm.CSharp
|
||||
{
|
||||
@@ -31,12 +33,14 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
/// <meta name="tag" content="regression test" />
|
||||
public class CustomDataRegressionAlgorithm : QCAlgorithm, IRegressionAlgorithmDefinition
|
||||
{
|
||||
private bool _warmedUpChecked = false;
|
||||
|
||||
/// <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()
|
||||
{
|
||||
SetStartDate(2011, 9, 13);
|
||||
SetStartDate(2011, 9, 14);
|
||||
SetEndDate(2015, 12, 01);
|
||||
|
||||
//Set the cash for the strategy:
|
||||
@@ -45,6 +49,9 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
//Define the symbol and "type" of our generic data:
|
||||
var resolution = LiveMode ? Resolution.Second : Resolution.Daily;
|
||||
AddData<Bitcoin>("BTC", resolution);
|
||||
|
||||
var seeder = new FuncSecuritySeeder(GetLastKnownPrices);
|
||||
SetSecurityInitializer(security => seeder.SeedSecurity(security));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -66,6 +73,30 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnSecuritiesChanged(SecurityChanges changes)
|
||||
{
|
||||
changes.FilterCustomSecurities = false;
|
||||
foreach (var addedSecurity in changes.AddedSecurities)
|
||||
{
|
||||
if (addedSecurity.Symbol.Value == "BTC")
|
||||
{
|
||||
_warmedUpChecked = true;
|
||||
}
|
||||
if (!addedSecurity.HasData)
|
||||
{
|
||||
throw new Exception($"Security {addedSecurity.Symbol} was not warmed up!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnEndOfAlgorithm()
|
||||
{
|
||||
if (!_warmedUpChecked)
|
||||
{
|
||||
throw new Exception($"Security was not warmed up!");
|
||||
}
|
||||
}
|
||||
|
||||
/// <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>
|
||||
@@ -84,30 +115,30 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
{"Total Trades", "1"},
|
||||
{"Average Win", "0%"},
|
||||
{"Average Loss", "0%"},
|
||||
{"Compounding Annual Return", "157.497%"},
|
||||
{"Compounding Annual Return", "157.655%"},
|
||||
{"Drawdown", "84.800%"},
|
||||
{"Expectancy", "0"},
|
||||
{"Net Profit", "5319.007%"},
|
||||
{"Sharpe Ratio", "2.086"},
|
||||
{"Probabilistic Sharpe Ratio", "69.456%"},
|
||||
{"Sharpe Ratio", "2.123"},
|
||||
{"Probabilistic Sharpe Ratio", "70.581%"},
|
||||
{"Loss Rate", "0%"},
|
||||
{"Win Rate", "0%"},
|
||||
{"Profit-Loss Ratio", "0"},
|
||||
{"Alpha", "1.747"},
|
||||
{"Beta", "0.047"},
|
||||
{"Alpha", "1.776"},
|
||||
{"Beta", "0.059"},
|
||||
{"Annual Standard Deviation", "0.84"},
|
||||
{"Annual Variance", "0.706"},
|
||||
{"Information Ratio", "1.922"},
|
||||
{"Tracking Error", "0.848"},
|
||||
{"Treynor Ratio", "37.473"},
|
||||
{"Information Ratio", "1.962"},
|
||||
{"Tracking Error", "0.847"},
|
||||
{"Treynor Ratio", "30.455"},
|
||||
{"Total Fees", "$0.00"},
|
||||
{"Estimated Strategy Capacity", "$0"},
|
||||
{"Lowest Capacity Asset", "BTC.Bitcoin 2S"},
|
||||
{"Fitness Score", "0"},
|
||||
{"Kelly Criterion Estimate", "0"},
|
||||
{"Kelly Criterion Probability Value", "0"},
|
||||
{"Sortino Ratio", "2.269"},
|
||||
{"Return Over Maximum Drawdown", "1.858"},
|
||||
{"Sortino Ratio", "2.271"},
|
||||
{"Return Over Maximum Drawdown", "1.86"},
|
||||
{"Portfolio Turnover", "0"},
|
||||
{"Total Insights Generated", "0"},
|
||||
{"Total Insights Closed", "0"},
|
||||
|
||||
@@ -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%"},
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/*
|
||||
/*
|
||||
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
|
||||
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
|
||||
*
|
||||
@@ -18,6 +18,7 @@ using QuantConnect.Indicators;
|
||||
using QuantConnect.Interfaces;
|
||||
using QuantConnect.Storage;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace QuantConnect.Algorithm.CSharp
|
||||
@@ -29,7 +30,7 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
/// history call. This pattern can be equally applied to a machine learning model being
|
||||
/// trained and then saving the model weights in the object store.
|
||||
/// </summary>
|
||||
public class ObjectStoreExampleAlgorithm : QCAlgorithm
|
||||
public class ObjectStoreExampleAlgorithm : QCAlgorithm, IRegressionAlgorithmDefinition
|
||||
{
|
||||
private const string SPY_Close_ObjectStore_Key = "spy_close";
|
||||
private Symbol SPY;
|
||||
@@ -127,5 +128,64 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <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 bool CanRunLocally { get; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// This is used by the regression test system to indicate which languages this algorithm is written in.
|
||||
/// </summary>
|
||||
public 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 Dictionary<string, string> ExpectedStatistics => new Dictionary<string, string>
|
||||
{
|
||||
{"Total Trades", "1"},
|
||||
{"Average Win", "0%"},
|
||||
{"Average Loss", "0%"},
|
||||
{"Compounding Annual Return", "271.453%"},
|
||||
{"Drawdown", "2.200%"},
|
||||
{"Expectancy", "0"},
|
||||
{"Net Profit", "1.692%"},
|
||||
{"Sharpe Ratio", "8.888"},
|
||||
{"Probabilistic Sharpe Ratio", "67.609%"},
|
||||
{"Loss Rate", "0%"},
|
||||
{"Win Rate", "0%"},
|
||||
{"Profit-Loss Ratio", "0"},
|
||||
{"Alpha", "-0.005"},
|
||||
{"Beta", "0.996"},
|
||||
{"Annual Standard Deviation", "0.222"},
|
||||
{"Annual Variance", "0.049"},
|
||||
{"Information Ratio", "-14.565"},
|
||||
{"Tracking Error", "0.001"},
|
||||
{"Treynor Ratio", "1.978"},
|
||||
{"Total Fees", "$3.44"},
|
||||
{"Estimated Strategy Capacity", "$56000000.00"},
|
||||
{"Lowest Capacity Asset", "SPY R735QTJ8XC9X"},
|
||||
{"Fitness Score", "0.248"},
|
||||
{"Kelly Criterion Estimate", "0"},
|
||||
{"Kelly Criterion Probability Value", "0"},
|
||||
{"Sortino Ratio", "79228162514264337593543950335"},
|
||||
{"Return Over Maximum Drawdown", "93.728"},
|
||||
{"Portfolio Turnover", "0.248"},
|
||||
{"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", "9e4bfd2eb0b81ee5bc1b197a87ccedbe"}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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}")
|
||||
|
||||
@@ -23,7 +23,7 @@ class BasicTemplateFuturesDailyAlgorithm(QCAlgorithm):
|
||||
|
||||
def Initialize(self):
|
||||
self.SetStartDate(2013, 10, 8)
|
||||
self.SetEndDate(2013, 10, 10)
|
||||
self.SetEndDate(2014, 10, 10)
|
||||
self.SetCash(1000000)
|
||||
|
||||
self.contractSymbol = None
|
||||
@@ -50,6 +50,7 @@ class BasicTemplateFuturesDailyAlgorithm(QCAlgorithm):
|
||||
front = sorted(contracts, key = lambda x: x.Expiry, reverse=True)[0]
|
||||
|
||||
self.contractSymbol = front.Symbol
|
||||
self.MarketOrder(front.Symbol , 1)
|
||||
if self.IsMarketOpen(self.contractSymbol):
|
||||
self.MarketOrder(front.Symbol , 1)
|
||||
else:
|
||||
self.Liquidate()
|
||||
|
||||
@@ -23,7 +23,7 @@ class BasicTemplateFuturesHourlyAlgorithm(QCAlgorithm):
|
||||
|
||||
def Initialize(self):
|
||||
self.SetStartDate(2013, 10, 8)
|
||||
self.SetEndDate(2013, 10, 10)
|
||||
self.SetEndDate(2014, 10, 10)
|
||||
self.SetCash(1000000)
|
||||
|
||||
self.contractSymbol = None
|
||||
@@ -50,6 +50,7 @@ class BasicTemplateFuturesHourlyAlgorithm(QCAlgorithm):
|
||||
front = sorted(contracts, key = lambda x: x.Expiry, reverse=True)[0]
|
||||
|
||||
self.contractSymbol = front.Symbol
|
||||
self.MarketOrder(front.Symbol , 1)
|
||||
if self.IsMarketOpen(self.contractSymbol):
|
||||
self.MarketOrder(front.Symbol , 1)
|
||||
else:
|
||||
self.Liquidate()
|
||||
|
||||
@@ -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.")
|
||||
|
||||
@@ -51,7 +51,7 @@ class BasicTemplateOptionsDailyAlgorithm(QCAlgorithm):
|
||||
contracts = sorted(chain, key = lambda x: x.Expiry)
|
||||
|
||||
# if found, trade it
|
||||
if len(contracts) == 0: return
|
||||
if len(contracts) == 0 or not self.IsMarketOpen(contracts[0].Symbol): return
|
||||
symbol = contracts[0].Symbol
|
||||
self.MarketOrder(symbol, 1)
|
||||
|
||||
|
||||
@@ -57,7 +57,7 @@ class BasicTemplateOptionsHourlyAlgorithm(QCAlgorithm):
|
||||
key = lambda x: x.Right, reverse=True)
|
||||
|
||||
# if found, trade it
|
||||
if len(contracts) == 0: return
|
||||
if len(contracts) == 0 or not self.IsMarketOpen(contracts[0].Symbol): return
|
||||
symbol = contracts[0].Symbol
|
||||
self.MarketOrder(symbol, 1)
|
||||
self.MarketOnCloseOrder(symbol, -1)
|
||||
|
||||
@@ -25,18 +25,33 @@ class CustomDataRegressionAlgorithm(QCAlgorithm):
|
||||
|
||||
def Initialize(self):
|
||||
|
||||
self.SetStartDate(2011,9,13) # Set Start Date
|
||||
self.SetStartDate(2011,9,14) # Set Start Date
|
||||
self.SetEndDate(2015,12,1) # Set End Date
|
||||
self.SetCash(100000) # Set Strategy Cash
|
||||
|
||||
resolution = Resolution.Second if self.LiveMode else Resolution.Daily
|
||||
self.AddData(Bitcoin, "BTC", resolution)
|
||||
|
||||
seeder = FuncSecuritySeeder(self.GetLastKnownPrices)
|
||||
self.SetSecurityInitializer(lambda x: seeder.SeedSecurity(x))
|
||||
self._warmedUpChecked = False
|
||||
|
||||
def OnData(self, data):
|
||||
if not self.Portfolio.Invested:
|
||||
if data['BTC'].Close != 0 :
|
||||
self.Order('BTC', self.Portfolio.MarginRemaining/abs(data['BTC'].Close + 1))
|
||||
|
||||
def OnSecuritiesChanged(self, changes):
|
||||
changes.FilterCustomSecurities = False
|
||||
for addedSecurity in changes.AddedSecurities:
|
||||
if addedSecurity.Symbol.Value == "BTC":
|
||||
self._warmedUpChecked = True
|
||||
if not addedSecurity.HasData:
|
||||
raise ValueError(f"Security {addedSecurity.Symbol} was not warmed up!")
|
||||
|
||||
def OnEndOfAlgorithm(self):
|
||||
if not self._warmedUpChecked:
|
||||
raise ValueError("Security was not warmed up!")
|
||||
|
||||
class Bitcoin(PythonData):
|
||||
'''Custom Data Type: Bitcoin data from Quandl - http://www.quandl.com/help/api-for-bitcoin-data'''
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
# limitations under the License.
|
||||
|
||||
from AlgorithmImports import *
|
||||
from QuantConnect.Algorithm.CSharp import *
|
||||
|
||||
### <summary>
|
||||
### Basic template algorithm simply initializes the date range and cash. This is a skeleton
|
||||
|
||||
@@ -13,11 +13,10 @@
|
||||
|
||||
from AlgorithmImports import *
|
||||
|
||||
from io import StringIO
|
||||
from keras.models import Sequential
|
||||
from keras.models import *
|
||||
from tensorflow import keras
|
||||
from keras.layers import Dense, Activation
|
||||
from keras.optimizers import SGD
|
||||
from keras.utils.generic_utils import serialize_keras_object
|
||||
|
||||
class KerasNeuralNetworkAlgorithm(QCAlgorithm):
|
||||
|
||||
@@ -32,11 +31,13 @@ class KerasNeuralNetworkAlgorithm(QCAlgorithm):
|
||||
symbol = self.AddEquity(ticker).Symbol
|
||||
|
||||
# Read the model saved in the ObjectStore
|
||||
if self.ObjectStore.ContainsKey(f'{symbol}_model'):
|
||||
modelStr = self.ObjectStore.Read(f'{symbol}_model')
|
||||
config = json.loads(modelStr)['config']
|
||||
self.modelBySymbol[symbol] = Sequential.from_config(config)
|
||||
self.Debug(f'Model for {symbol} sucessfully retrieved from the ObjectStore')
|
||||
for kvp in self.ObjectStore:
|
||||
key = f'{symbol}_model'
|
||||
if not key == kvp.Key or kvp.Value is None:
|
||||
continue
|
||||
filePath = self.ObjectStore.GetFilePath(kvp.Key)
|
||||
self.modelBySymbol[symbol] = keras.models.load_model(filePath)
|
||||
self.Debug(f'Model for {symbol} sucessfully retrieved. File {filePath}. Size {kvp.Value.Length}. Weights {self.modelBySymbol[symbol].get_weights()}')
|
||||
|
||||
# Look-back period for training set
|
||||
self.lookback = 30
|
||||
@@ -51,19 +52,21 @@ class KerasNeuralNetworkAlgorithm(QCAlgorithm):
|
||||
self.Schedule.On(
|
||||
self.DateRules.EveryDay("SPY"),
|
||||
self.TimeRules.AfterMarketOpen("SPY", 30),
|
||||
self.Trade)
|
||||
self.Trade)
|
||||
|
||||
|
||||
def OnEndOfAlgorithm(self):
|
||||
''' Save the data and the mode using the ObjectStore '''
|
||||
for symbol, model in self.modelBySymbol.items():
|
||||
modelStr = json.dumps(serialize_keras_object(model))
|
||||
self.ObjectStore.Save(f'{symbol}_model', modelStr)
|
||||
key = f'{symbol}_model'
|
||||
file = self.ObjectStore.GetFilePath(key)
|
||||
model.save(file)
|
||||
self.ObjectStore.Save(key)
|
||||
self.Debug(f'Model for {symbol} sucessfully saved in the ObjectStore')
|
||||
|
||||
|
||||
def NeuralNetworkTraining(self):
|
||||
'''Train the Neural Network and save the model in the ObjectStore'''
|
||||
'''Train the Neural Network and save the model in the ObjectStore'''
|
||||
symbols = self.Securities.keys()
|
||||
|
||||
# Daily historical data is used to train the machine learning model
|
||||
@@ -89,19 +92,18 @@ class KerasNeuralNetworkAlgorithm(QCAlgorithm):
|
||||
# choose loss function and optimizing method
|
||||
model.compile(loss='mse', optimizer=sgd)
|
||||
|
||||
# pick an iteration number large enough for convergence
|
||||
# pick an iteration number large enough for convergence
|
||||
for step in range(200):
|
||||
# training the model
|
||||
cost = model.train_on_batch(predictor, predictand)
|
||||
|
||||
self.modelBySymbol[symbol] = model
|
||||
|
||||
|
||||
def Trade(self):
|
||||
'''
|
||||
Predict the price using the trained model and out-of-sample data
|
||||
Enter or exit positions based on relationship of the open price of the current bar and the prices defined by the machine learning model.
|
||||
Liquidate if the open price is below the sell price and buy if the open price is above the buy price
|
||||
Liquidate if the open price is below the sell price and buy if the open price is above the buy price
|
||||
'''
|
||||
target = 1 / len(self.Securities)
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -1269,13 +1269,11 @@ namespace QuantConnect.Algorithm
|
||||
[DocumentationAttribute(SecuritiesAndPortfolio)]
|
||||
public bool IsMarketOpen(Symbol symbol)
|
||||
{
|
||||
var exchangeHours = MarketHoursDatabase
|
||||
.FromDataFolder()
|
||||
.GetExchangeHours(symbol.ID.Market, symbol, symbol.SecurityType);
|
||||
|
||||
var time = UtcTime.ConvertFromUtc(exchangeHours.TimeZone);
|
||||
|
||||
return exchangeHours.IsOpen(time, false);
|
||||
if (Securities.TryGetValue(symbol, out var security))
|
||||
{
|
||||
return security.IsMarketOpen(false);
|
||||
}
|
||||
return symbol.IsMarketOpen(UtcTime, false);
|
||||
}
|
||||
|
||||
private SubmitOrderRequest CreateSubmitOrderRequest(OrderType orderType, Security security, decimal quantity, string tag, IOrderProperties properties, decimal stopPrice = 0m, decimal limitPrice = 0m, decimal triggerPrice = 0m)
|
||||
|
||||
@@ -1981,8 +1981,9 @@ namespace QuantConnect.Algorithm
|
||||
Universe universe;
|
||||
if (!UniverseManager.TryGetValue(universeSymbol, out universe))
|
||||
{
|
||||
var settings = new UniverseSettings(UniverseSettings) { DataNormalizationMode = DataNormalizationMode.Raw, Resolution = underlyingConfigs.GetHighestResolution() };
|
||||
universe = _pendingUniverseAdditions.FirstOrDefault(u => u.Configuration.Symbol == universeSymbol)
|
||||
?? AddUniverse(new OptionContractUniverse(new SubscriptionDataConfig(configs.First(), symbol: universeSymbol), UniverseSettings));
|
||||
?? AddUniverse(new OptionContractUniverse(new SubscriptionDataConfig(configs.First(), symbol: universeSymbol), settings));
|
||||
}
|
||||
|
||||
// update the universe
|
||||
|
||||
@@ -65,7 +65,9 @@ namespace QuantConnect.Algorithm.Selection
|
||||
_symbols.Remove(removedSymbol);
|
||||
|
||||
// the option has been removed! This can happen when the user manually removed the option contract we remove the underlying
|
||||
if (removedSymbol.SecurityType.IsOption())
|
||||
// but only if there isn't any other option selected using the same underlying!
|
||||
if (removedSymbol.SecurityType.IsOption()
|
||||
&& !_symbols.Any(symbol => symbol.SecurityType.IsOption() && symbol.Underlying == removedSymbol.Underlying))
|
||||
{
|
||||
Remove(removedSymbol.Underlying);
|
||||
}
|
||||
|
||||
@@ -48,11 +48,18 @@ namespace QuantConnect.AlgorithmFactory
|
||||
|
||||
/// <summary>
|
||||
/// Python Tool for Visual Studio Debugger for remote python debugging.
|
||||
/// <see cref="Language.Python"/> will use 'Python Extension in VS Code'
|
||||
///or 'Python Tools in Visual Studio'
|
||||
/// <see cref="Language.Python"/>. Deprecated, routes to DebugPy which
|
||||
/// is it's replacement. Used in the same way.
|
||||
/// </summary>
|
||||
PTVSD,
|
||||
|
||||
/// <summary>
|
||||
/// DebugPy - a debugger for Python.
|
||||
/// <see cref="Language.Python"/> can use `Python Extension` in VS Code
|
||||
/// or attach to Python in Visual Studio
|
||||
/// </summary>
|
||||
DebugPy,
|
||||
|
||||
/// <summary>
|
||||
/// PyCharm PyDev Debugger for remote python debugging.
|
||||
/// <see cref="Language.Python"/> will use 'Python Debug Server' in PyCharm
|
||||
@@ -68,7 +75,7 @@ namespace QuantConnect.AlgorithmFactory
|
||||
if (language == Language.Python)
|
||||
{
|
||||
DebuggingMethod debuggingType;
|
||||
Enum.TryParse(Config.Get("debugging-method", DebuggingMethod.LocalCmdline.ToString()), out debuggingType);
|
||||
Enum.TryParse(Config.Get("debugging-method", DebuggingMethod.LocalCmdline.ToString()), true, out debuggingType);
|
||||
|
||||
Log.Trace("DebuggerHelper.Initialize(): initializing python...");
|
||||
PythonInitializer.Initialize();
|
||||
@@ -91,8 +98,9 @@ while not sys.gettrace():
|
||||
break;
|
||||
|
||||
case DebuggingMethod.PTVSD:
|
||||
Log.Trace("DebuggerHelper.Initialize(): waiting for PTVSD debugger to attach at localhost:5678...");
|
||||
PythonEngine.RunSimpleString("import ptvsd; ptvsd.enable_attach(); ptvsd.wait_for_attach()");
|
||||
case DebuggingMethod.DebugPy:
|
||||
Log.Trace("DebuggerHelper.Initialize(): debugpy waiting for attach at port 5678...");
|
||||
PythonEngine.RunSimpleString("import debugpy; debugpy.listen(('0.0.0.0', 5678)); debugpy.wait_for_client()");
|
||||
break;
|
||||
|
||||
case DebuggingMethod.PyCharm:
|
||||
|
||||
@@ -41,7 +41,6 @@
|
||||
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
|
||||
<PackageReference Include="NodaTime" Version="3.0.5" />
|
||||
<PackageReference Include="RestSharp" Version="106.12.0" />
|
||||
<PackageReference Include="SharpZipLib" Version="1.2.0" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="..\Common\Properties\SharedAssemblyInfo.cs" Link="Properties\SharedAssemblyInfo.cs" />
|
||||
|
||||
@@ -279,12 +279,12 @@ namespace QuantConnect.Brokerages.Backtesting
|
||||
continue;
|
||||
}
|
||||
|
||||
var fills = new OrderEvent[0];
|
||||
var fills = Array.Empty<OrderEvent>();
|
||||
|
||||
Security security;
|
||||
if (!Algorithm.Securities.TryGetValue(order.Symbol, out security))
|
||||
{
|
||||
Log.Error("BacktestingBrokerage.Scan(): Unable to process order: " + order.Id + ". The security no longer exists.");
|
||||
Log.Error($"BacktestingBrokerage.Scan(): Unable to process order: {order.Id}. The security no longer exists. UtcTime: {Algorithm.UtcTime}");
|
||||
// invalidate the order in the algorithm before removing
|
||||
OnOrderEvent(new OrderEvent(order,
|
||||
Algorithm.UtcTime,
|
||||
|
||||
@@ -149,7 +149,10 @@ namespace QuantConnect.Brokerages
|
||||
return SubscriptionManager?.GetSubscribedSymbols() ?? Enumerable.Empty<Symbol>();
|
||||
}
|
||||
|
||||
private void ConnectSync()
|
||||
/// <summary>
|
||||
/// Start websocket connect
|
||||
/// </summary>
|
||||
protected void ConnectSync()
|
||||
{
|
||||
var resetEvent = new ManualResetEvent(false);
|
||||
EventHandler triggerEvent = (o, args) => resetEvent.Set();
|
||||
|
||||
@@ -28,21 +28,27 @@ using System.Linq;
|
||||
using System.Net;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using QuantConnect.Brokerages.Binance.Messages;
|
||||
using Order = QuantConnect.Orders.Order;
|
||||
|
||||
namespace QuantConnect.Brokerages.Binance
|
||||
{
|
||||
/// <summary>
|
||||
/// Binance REST API implementation
|
||||
/// Binance REST API base implementation
|
||||
/// </summary>
|
||||
public class BinanceRestApiClient : IDisposable
|
||||
public abstract class BinanceBaseRestApiClient : IDisposable
|
||||
{
|
||||
private const string UserDataStreamEndpoint = "/api/v3/userDataStream";
|
||||
// depends on SPOT or MARGIN trading
|
||||
private readonly string _apiPrefix;
|
||||
private readonly string _wsPrefix;
|
||||
|
||||
private string UserDataStreamEndpoint => $"{_wsPrefix}/userDataStream";
|
||||
|
||||
private readonly SymbolPropertiesDatabaseSymbolMapper _symbolMapper;
|
||||
private readonly ISecurityProvider _securityProvider;
|
||||
private readonly IRestClient _restClient;
|
||||
private readonly RateGate _restRateLimiter = new RateGate(10, TimeSpan.FromSeconds(1));
|
||||
private readonly object _listenKeyLocker = new object();
|
||||
private readonly RateGate _restRateLimiter = new(10, TimeSpan.FromSeconds(1));
|
||||
private readonly object _listenKeyLocker = new();
|
||||
|
||||
/// <summary>
|
||||
/// Event that fires each time an order is filled
|
||||
@@ -80,21 +86,25 @@ namespace QuantConnect.Brokerages.Binance
|
||||
public string SessionId { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="BinanceRestApiClient"/> class.
|
||||
/// Initializes a new instance of the <see cref="BinanceBaseRestApiClient"/> class.
|
||||
/// </summary>
|
||||
/// <param name="symbolMapper">The symbol mapper.</param>
|
||||
/// <param name="securityProvider">The holdings provider.</param>
|
||||
/// <param name="apiKey">The Binance API key</param>
|
||||
/// <param name="apiSecret">The The Binance API secret</param>
|
||||
/// <param name="restApiUrl">The Binance API rest url</param>
|
||||
public BinanceRestApiClient(SymbolPropertiesDatabaseSymbolMapper symbolMapper, ISecurityProvider securityProvider,
|
||||
string apiKey, string apiSecret, string restApiUrl)
|
||||
/// <param name="restApiPrefix">REST API path prefix depending on SPOT or CROSS MARGIN trading</param>
|
||||
/// <param name="wsApiPrefix">REST API path prefix for user data streaming auth process depending on SPOT or CROSS MARGIN trading</param>
|
||||
public BinanceBaseRestApiClient(SymbolPropertiesDatabaseSymbolMapper symbolMapper, ISecurityProvider securityProvider,
|
||||
string apiKey, string apiSecret, string restApiUrl, string restApiPrefix, string wsApiPrefix)
|
||||
{
|
||||
_symbolMapper = symbolMapper;
|
||||
_securityProvider = securityProvider;
|
||||
_restClient = new RestClient(restApiUrl);
|
||||
ApiKey = apiKey;
|
||||
ApiSecret = apiSecret;
|
||||
_apiPrefix = restApiPrefix;
|
||||
_wsPrefix = wsApiPrefix;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -110,10 +120,10 @@ namespace QuantConnect.Brokerages.Binance
|
||||
/// Gets the total account cash balance for specified account type
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public Messages.AccountInformation GetCashBalance()
|
||||
public BalanceEntry[] GetCashBalance()
|
||||
{
|
||||
var queryString = $"timestamp={GetNonce()}";
|
||||
var endpoint = $"/api/v3/account?{queryString}&signature={AuthenticationToken(queryString)}";
|
||||
var endpoint = $"{_apiPrefix}/account?{queryString}&signature={AuthenticationToken(queryString)}";
|
||||
var request = new RestRequest(endpoint, Method.GET);
|
||||
request.AddHeader(KeyHeader, ApiKey);
|
||||
|
||||
@@ -123,9 +133,20 @@ namespace QuantConnect.Brokerages.Binance
|
||||
throw new Exception($"BinanceBrokerage.GetCashBalance: request failed: [{(int)response.StatusCode}] {response.StatusDescription}, Content: {response.Content}, ErrorMessage: {response.ErrorMessage}");
|
||||
}
|
||||
|
||||
return JsonConvert.DeserializeObject<Messages.AccountInformation>(response.Content);
|
||||
return JsonConvert
|
||||
.DeserializeObject<AccountInformation>(response.Content, CreateAccountConverter())
|
||||
.Balances
|
||||
.Where(s => s.Amount != 0)
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deserialize Binance account information
|
||||
/// </summary>
|
||||
/// <param name="content">API response content</param>
|
||||
/// <returns>Cash or Margin Account</returns>
|
||||
protected abstract JsonConverter CreateAccountConverter();
|
||||
|
||||
/// <summary>
|
||||
/// Gets all orders not yet closed
|
||||
/// </summary>
|
||||
@@ -133,7 +154,7 @@ namespace QuantConnect.Brokerages.Binance
|
||||
public IEnumerable<Messages.OpenOrder> GetOpenOrders()
|
||||
{
|
||||
var queryString = $"timestamp={GetNonce()}";
|
||||
var endpoint = $"/api/v3/openOrders?{queryString}&signature={AuthenticationToken(queryString)}";
|
||||
var endpoint = $"{_apiPrefix}/openOrders?{queryString}&signature={AuthenticationToken(queryString)}";
|
||||
var request = new RestRequest(endpoint, Method.GET);
|
||||
request.AddHeader(KeyHeader, ApiKey);
|
||||
|
||||
@@ -153,53 +174,11 @@ namespace QuantConnect.Brokerages.Binance
|
||||
/// <returns>True if the request for a new order has been placed, false otherwise</returns>
|
||||
public bool PlaceOrder(Order order)
|
||||
{
|
||||
// supported time in force values {GTC, IOC, FOK}
|
||||
// use GTC as LEAN doesn't support others yet
|
||||
IDictionary<string, object> body = new Dictionary<string, object>()
|
||||
{
|
||||
{ "symbol", _symbolMapper.GetBrokerageSymbol(order.Symbol) },
|
||||
{ "quantity", Math.Abs(order.Quantity).ToString(CultureInfo.InvariantCulture) },
|
||||
{ "side", ConvertOrderDirection(order.Direction) }
|
||||
};
|
||||
var body = CreateOrderBody(order);
|
||||
|
||||
switch (order)
|
||||
{
|
||||
case LimitOrder limitOrder:
|
||||
body["type"] = (order.Properties as BinanceOrderProperties)?.PostOnly == true
|
||||
? "LIMIT_MAKER"
|
||||
: "LIMIT";
|
||||
body["price"] = limitOrder.LimitPrice.ToString(CultureInfo.InvariantCulture);
|
||||
// timeInForce is not required for LIMIT_MAKER
|
||||
if (Equals(body["type"], "LIMIT"))
|
||||
body["timeInForce"] = "GTC";
|
||||
break;
|
||||
case MarketOrder:
|
||||
body["type"] = "MARKET";
|
||||
break;
|
||||
case StopLimitOrder stopLimitOrder:
|
||||
var ticker = GetTickerPrice(order);
|
||||
var stopPrice = stopLimitOrder.StopPrice;
|
||||
if (order.Direction == OrderDirection.Sell)
|
||||
{
|
||||
body["type"] = stopPrice <= ticker ? "STOP_LOSS_LIMIT" : "TAKE_PROFIT_LIMIT";
|
||||
}
|
||||
else
|
||||
{
|
||||
body["type"] = stopPrice <= ticker ? "TAKE_PROFIT_LIMIT" : "STOP_LOSS_LIMIT";
|
||||
}
|
||||
|
||||
body["timeInForce"] = "GTC";
|
||||
body["stopPrice"] = stopPrice.ToStringInvariant();
|
||||
body["price"] = stopLimitOrder.LimitPrice.ToStringInvariant();
|
||||
break;
|
||||
default:
|
||||
throw new NotSupportedException($"BinanceBrokerage.ConvertOrderType: Unsupported order type: {order.Type}");
|
||||
}
|
||||
|
||||
const string endpoint = "/api/v3/order";
|
||||
body["timestamp"] = GetNonce();
|
||||
body["signature"] = AuthenticationToken(body.ToQueryString());
|
||||
var request = new RestRequest(endpoint, Method.POST);
|
||||
var request = new RestRequest($"{_apiPrefix}/order", Method.POST);
|
||||
request.AddHeader(KeyHeader, ApiKey);
|
||||
request.AddParameter(
|
||||
"application/x-www-form-urlencoded",
|
||||
@@ -242,6 +221,58 @@ namespace QuantConnect.Brokerages.Binance
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create account new order body payload
|
||||
/// </summary>
|
||||
/// <param name="order">Lean order</param>
|
||||
protected virtual IDictionary<string, object> CreateOrderBody(Order order)
|
||||
{
|
||||
// supported time in force values {GTC, IOC, FOK}
|
||||
// use GTC as LEAN doesn't support others yet
|
||||
var body = new Dictionary<string, object>
|
||||
{
|
||||
{ "symbol", _symbolMapper.GetBrokerageSymbol(order.Symbol) },
|
||||
{ "quantity", Math.Abs(order.Quantity).ToString(CultureInfo.InvariantCulture) },
|
||||
{ "side", ConvertOrderDirection(order.Direction) }
|
||||
};
|
||||
|
||||
switch (order)
|
||||
{
|
||||
case LimitOrder limitOrder:
|
||||
body["type"] = (order.Properties as BinanceOrderProperties)?.PostOnly == true
|
||||
? "LIMIT_MAKER"
|
||||
: "LIMIT";
|
||||
body["price"] = limitOrder.LimitPrice.ToString(CultureInfo.InvariantCulture);
|
||||
// timeInForce is not required for LIMIT_MAKER
|
||||
if (Equals(body["type"], "LIMIT"))
|
||||
body["timeInForce"] = "GTC";
|
||||
break;
|
||||
case MarketOrder:
|
||||
body["type"] = "MARKET";
|
||||
break;
|
||||
case StopLimitOrder stopLimitOrder:
|
||||
var ticker = GetTickerPrice(order);
|
||||
var stopPrice = stopLimitOrder.StopPrice;
|
||||
if (order.Direction == OrderDirection.Sell)
|
||||
{
|
||||
body["type"] = stopPrice <= ticker ? "STOP_LOSS_LIMIT" : "TAKE_PROFIT_LIMIT";
|
||||
}
|
||||
else
|
||||
{
|
||||
body["type"] = stopPrice <= ticker ? "TAKE_PROFIT_LIMIT" : "STOP_LOSS_LIMIT";
|
||||
}
|
||||
|
||||
body["timeInForce"] = "GTC";
|
||||
body["stopPrice"] = stopPrice.ToStringInvariant();
|
||||
body["price"] = stopLimitOrder.LimitPrice.ToStringInvariant();
|
||||
break;
|
||||
default:
|
||||
throw new NotSupportedException($"BinanceBrokerage.ConvertOrderType: Unsupported order type: {order.Type}");
|
||||
}
|
||||
|
||||
return body;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Cancels the order with the specified ID
|
||||
/// </summary>
|
||||
@@ -264,7 +295,7 @@ namespace QuantConnect.Brokerages.Binance
|
||||
body["timestamp"] = GetNonce();
|
||||
body["signature"] = AuthenticationToken(body.ToQueryString());
|
||||
|
||||
var request = new RestRequest("/api/v3/order", Method.DELETE);
|
||||
var request = new RestRequest($"{_apiPrefix}/order", Method.DELETE);
|
||||
request.AddHeader(KeyHeader, ApiKey);
|
||||
request.AddParameter(
|
||||
"application/x-www-form-urlencoded",
|
||||
@@ -382,7 +413,10 @@ namespace QuantConnect.Brokerages.Binance
|
||||
Encoding.UTF8.GetBytes($"listenKey={SessionId}"),
|
||||
ParameterType.RequestBody
|
||||
);
|
||||
ExecuteRestRequest(request);
|
||||
if (ExecuteRestRequest(request).StatusCode == HttpStatusCode.OK)
|
||||
{
|
||||
SessionId = null;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/*
|
||||
/*
|
||||
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
|
||||
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
|
||||
*
|
||||
@@ -27,7 +27,7 @@ namespace QuantConnect.Brokerages.Binance
|
||||
switch (raw.LazyToUpper())
|
||||
{
|
||||
case "NEW":
|
||||
return OrderStatus.New;
|
||||
return OrderStatus.Submitted;
|
||||
|
||||
case "PARTIALLY_FILLED":
|
||||
return OrderStatus.PartiallyFilled;
|
||||
|
||||
@@ -51,7 +51,9 @@ namespace QuantConnect.Brokerages.Binance
|
||||
private string _webSocketBaseUrl;
|
||||
private Timer _keepAliveTimer;
|
||||
private Timer _reconnectTimer;
|
||||
private BinanceRestApiClient _apiClient;
|
||||
private Lazy<BinanceBaseRestApiClient> _apiClientLazy;
|
||||
private BinanceBaseRestApiClient ApiClient => _apiClientLazy?.Value;
|
||||
|
||||
private BrokerageConcurrentMessageHandler<WebSocketMessage> _messageHandler;
|
||||
|
||||
private const int MaximumSymbolsPerConnection = 512;
|
||||
@@ -91,8 +93,9 @@ namespace QuantConnect.Brokerages.Binance
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the websocket connection is connected or in the process of connecting
|
||||
/// WebSocket is responsible for Binance UserData stream only.
|
||||
/// </summary>
|
||||
public override bool IsConnected => WebSocket.IsOpen;
|
||||
public override bool IsConnected => _apiClientLazy?.IsValueCreated != true || WebSocket?.IsOpen == true;
|
||||
|
||||
/// <summary>
|
||||
/// Creates wss connection
|
||||
@@ -102,12 +105,12 @@ namespace QuantConnect.Brokerages.Binance
|
||||
if (IsConnected)
|
||||
return;
|
||||
|
||||
_apiClient.CreateListenKey();
|
||||
_reconnectTimer.Start();
|
||||
|
||||
WebSocket.Initialize($"{_webSocketBaseUrl}/{_apiClient.SessionId}");
|
||||
|
||||
base.Connect();
|
||||
// cannot reach this code if rest api client is not created
|
||||
// WebSocket is responsible for Binance UserData stream only
|
||||
// as a result we don't need to connect user data stream if BinanceBrokerage is used as DQH only
|
||||
// or until Algorithm is actually initialized
|
||||
ApiClient.CreateListenKey();
|
||||
Connect(ApiClient.SessionId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -115,10 +118,11 @@ namespace QuantConnect.Brokerages.Binance
|
||||
/// </summary>
|
||||
public override void Disconnect()
|
||||
{
|
||||
_reconnectTimer.Stop();
|
||||
if (WebSocket?.IsOpen != true)
|
||||
return;
|
||||
|
||||
WebSocket?.Close();
|
||||
_apiClient.StopSession();
|
||||
_reconnectTimer.Stop();
|
||||
WebSocket.Close();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -127,11 +131,7 @@ namespace QuantConnect.Brokerages.Binance
|
||||
/// <returns></returns>
|
||||
public override List<Holding> GetAccountHoldings()
|
||||
{
|
||||
if (_algorithm.BrokerageModel.AccountType == AccountType.Cash)
|
||||
{
|
||||
return base.GetAccountHoldings(_job?.BrokerageData, _algorithm.Securities.Values);
|
||||
}
|
||||
return _apiClient.GetAccountHoldings();
|
||||
return base.GetAccountHoldings(_job?.BrokerageData, _algorithm.Securities.Values);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -140,8 +140,7 @@ namespace QuantConnect.Brokerages.Binance
|
||||
/// <returns></returns>
|
||||
public override List<CashAmount> GetCashBalance()
|
||||
{
|
||||
var account = _apiClient.GetCashBalance();
|
||||
var balances = account.Balances?.Where(balance => balance.Amount > 0).ToList();
|
||||
var balances = ApiClient.GetCashBalance();
|
||||
if (balances == null || !balances.Any())
|
||||
return new List<CashAmount>();
|
||||
|
||||
@@ -156,7 +155,7 @@ namespace QuantConnect.Brokerages.Binance
|
||||
/// <returns></returns>
|
||||
public override List<Order> GetOpenOrders()
|
||||
{
|
||||
var orders = _apiClient.GetOpenOrders();
|
||||
var orders = ApiClient.GetOpenOrders();
|
||||
List<Order> list = new List<Order>();
|
||||
foreach (var item in orders)
|
||||
{
|
||||
@@ -221,7 +220,7 @@ namespace QuantConnect.Brokerages.Binance
|
||||
|
||||
_messageHandler.WithLockedStream(() =>
|
||||
{
|
||||
submitted = _apiClient.PlaceOrder(order);
|
||||
submitted = ApiClient.PlaceOrder(order);
|
||||
});
|
||||
|
||||
return submitted;
|
||||
@@ -248,7 +247,7 @@ namespace QuantConnect.Brokerages.Binance
|
||||
|
||||
_messageHandler.WithLockedStream(() =>
|
||||
{
|
||||
submitted = _apiClient.CancelOrder(order);
|
||||
submitted = ApiClient.CancelOrder(order);
|
||||
});
|
||||
|
||||
return submitted;
|
||||
@@ -277,7 +276,7 @@ namespace QuantConnect.Brokerages.Binance
|
||||
|
||||
var period = request.Resolution.ToTimeSpan();
|
||||
|
||||
foreach (var kline in _apiClient.GetHistory(request))
|
||||
foreach (var kline in ApiClient.GetHistory(request))
|
||||
{
|
||||
yield return new TradeBar()
|
||||
{
|
||||
@@ -320,7 +319,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,
|
||||
@@ -388,7 +387,10 @@ namespace QuantConnect.Brokerages.Binance
|
||||
{
|
||||
_keepAliveTimer.DisposeSafely();
|
||||
_reconnectTimer.DisposeSafely();
|
||||
_apiClient.DisposeSafely();
|
||||
if (_apiClientLazy?.IsValueCreated == true)
|
||||
{
|
||||
ApiClient.DisposeSafely();
|
||||
}
|
||||
_webSocketRateLimiter.DisposeSafely();
|
||||
}
|
||||
|
||||
@@ -411,14 +413,14 @@ namespace QuantConnect.Brokerages.Binance
|
||||
/// <param name="algorithm">the algorithm instance is required to retrieve account type</param>
|
||||
/// <param name="aggregator">the aggregator for consolidating ticks</param>
|
||||
/// <param name="job">The live job packet</param>
|
||||
private void Initialize(string wssUrl, string restApiUrl,string apiKey, string apiSecret,
|
||||
private void Initialize(string wssUrl, string restApiUrl, string apiKey, string apiSecret,
|
||||
IAlgorithm algorithm, IDataAggregator aggregator, LiveNodePacket job)
|
||||
{
|
||||
if (IsInitialized)
|
||||
{
|
||||
return;
|
||||
}
|
||||
base.Initialize(wssUrl, new WebSocketClientWrapper(), null, apiKey, apiSecret);
|
||||
base.Initialize(wssUrl, new WebSocketClientWrapper(), null, apiKey, apiSecret);
|
||||
_job = job;
|
||||
_algorithm = algorithm;
|
||||
_aggregator = aggregator;
|
||||
@@ -441,15 +443,32 @@ namespace QuantConnect.Brokerages.Binance
|
||||
|
||||
SubscriptionManager = subscriptionManager;
|
||||
|
||||
_apiClient = new BinanceRestApiClient(_symbolMapper,
|
||||
algorithm?.Portfolio,
|
||||
apiKey,
|
||||
apiSecret,
|
||||
restApiUrl);
|
||||
// can be null, if BinanceBrokerage is used as DataQueueHandler only
|
||||
if (_algorithm != null)
|
||||
{
|
||||
// Binance rest api endpoint is different for sport and margin trading
|
||||
// we need to delay initialization of rest api client until Algorithm is initialized
|
||||
// and user brokerage choise is actually applied
|
||||
_apiClientLazy = new Lazy<BinanceBaseRestApiClient>(() =>
|
||||
{
|
||||
BinanceBaseRestApiClient apiClient = _algorithm.BrokerageModel.AccountType == AccountType.Cash
|
||||
? new BinanceSpotRestApiClient(_symbolMapper, algorithm?.Portfolio, apiKey, apiSecret, restApiUrl)
|
||||
: new BinanceCrossMarginRestApiClient(_symbolMapper, algorithm?.Portfolio, apiKey, apiSecret,
|
||||
restApiUrl);
|
||||
|
||||
_apiClient.OrderSubmit += (s, e) => OnOrderSubmit(e);
|
||||
_apiClient.OrderStatusChanged += (s, e) => OnOrderEvent(e);
|
||||
_apiClient.Message += (s, e) => OnMessage(e);
|
||||
apiClient.OrderSubmit += (s, e) => OnOrderSubmit(e);
|
||||
apiClient.OrderStatusChanged += (s, e) => OnOrderEvent(e);
|
||||
apiClient.Message += (s, e) => OnMessage(e);
|
||||
|
||||
// once we know the api endpoint we can subscribe to user data stream
|
||||
apiClient.CreateListenKey();
|
||||
_keepAliveTimer.Elapsed += (s, e) => apiClient.SessionKeepAlive();
|
||||
|
||||
Connect(apiClient.SessionId);
|
||||
|
||||
return apiClient;
|
||||
});
|
||||
}
|
||||
|
||||
// User data streams will close after 60 minutes. It's recommended to send a ping about every 30 minutes.
|
||||
// Source: https://github.com/binance-exchange/binance-official-api-docs/blob/master/user-data-stream.md#pingkeep-alive-a-listenkey
|
||||
@@ -458,10 +477,16 @@ namespace QuantConnect.Brokerages.Binance
|
||||
// 30 minutes
|
||||
Interval = 30 * 60 * 1000
|
||||
};
|
||||
_keepAliveTimer.Elapsed += (s, e) => _apiClient.SessionKeepAlive();
|
||||
|
||||
WebSocket.Open += (s, e) => { _keepAliveTimer.Start(); };
|
||||
WebSocket.Closed += (s, e) => { _keepAliveTimer.Stop(); };
|
||||
WebSocket.Open += (s, e) =>
|
||||
{
|
||||
_keepAliveTimer.Start();
|
||||
};
|
||||
WebSocket.Closed += (s, e) =>
|
||||
{
|
||||
ApiClient.StopSession();
|
||||
_keepAliveTimer.Stop();
|
||||
};
|
||||
|
||||
// A single connection to stream.binance.com is only valid for 24 hours; expect to be disconnected at the 24 hour mark
|
||||
// Source: https://github.com/binance-exchange/binance-official-api-docs/blob/master/web-socket-streams.md#general-wss-information
|
||||
@@ -592,5 +617,17 @@ namespace QuantConnect.Brokerages.Binance
|
||||
|
||||
return dict;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Force reconnect websocket
|
||||
/// </summary>
|
||||
private void Connect(string sessionId)
|
||||
{
|
||||
Log.Trace("BaseWebSocketsBrokerage.Connect(): Connecting...");
|
||||
|
||||
_reconnectTimer.Start();
|
||||
WebSocket.Initialize($"{_webSocketBaseUrl}/{sessionId}");
|
||||
ConnectSync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
55
Brokerages/Binance/BinanceCrossMarginRestApiClient.cs
Normal file
55
Brokerages/Binance/BinanceCrossMarginRestApiClient.cs
Normal file
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* 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.Collections.Generic;
|
||||
using Newtonsoft.Json;
|
||||
using QuantConnect.Brokerages.Binance.Messages;
|
||||
using QuantConnect.Securities;
|
||||
using Order = QuantConnect.Orders.Order;
|
||||
|
||||
namespace QuantConnect.Brokerages.Binance
|
||||
{
|
||||
/// <summary>
|
||||
/// Binance REST API implementation
|
||||
/// </summary>
|
||||
public class BinanceCrossMarginRestApiClient : BinanceBaseRestApiClient
|
||||
{
|
||||
private const string _apiPrefix = "/sapi/v1/margin";
|
||||
private const string _wsPrefix = "/sapi/v1";
|
||||
|
||||
public BinanceCrossMarginRestApiClient(
|
||||
SymbolPropertiesDatabaseSymbolMapper symbolMapper,
|
||||
ISecurityProvider securityProvider,
|
||||
string apiKey,
|
||||
string apiSecret,
|
||||
string restApiUrl
|
||||
)
|
||||
: base(symbolMapper, securityProvider, apiKey, apiSecret, restApiUrl, _apiPrefix, _wsPrefix)
|
||||
{
|
||||
}
|
||||
|
||||
protected override JsonConverter CreateAccountConverter()
|
||||
=> new MarginAccountConverter();
|
||||
|
||||
protected override IDictionary<string, object> CreateOrderBody(Order order)
|
||||
{
|
||||
var body = base.CreateOrderBody(order);
|
||||
body["isisolated"] = "FALSE";
|
||||
body["sideEffectType"] = "MARGIN_BUY";
|
||||
|
||||
return body;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
/*
|
||||
/*
|
||||
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
|
||||
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
|
||||
*
|
||||
@@ -11,28 +11,33 @@
|
||||
* 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 Newtonsoft.Json;
|
||||
using QuantConnect.Brokerages.Binance.Messages;
|
||||
using QuantConnect.Securities;
|
||||
|
||||
namespace QuantConnect.Packets
|
||||
namespace QuantConnect.Brokerages.Binance
|
||||
{
|
||||
/// <summary>
|
||||
/// A debugging breakpoint
|
||||
/// Binance Spot REST API implementation
|
||||
/// </summary>
|
||||
public class Breakpoint
|
||||
public class BinanceSpotRestApiClient : BinanceBaseRestApiClient
|
||||
{
|
||||
/// <summary>
|
||||
/// The file name
|
||||
/// </summary>
|
||||
[JsonProperty(PropertyName = "fileName")]
|
||||
public string FileName { get; set; }
|
||||
private const string _apiPrefix = "/api/v3";
|
||||
|
||||
/// <summary>
|
||||
/// The line number
|
||||
/// </summary>
|
||||
[JsonProperty(PropertyName = "lineNumber")]
|
||||
public int LineNumber { get; set; }
|
||||
public BinanceSpotRestApiClient(
|
||||
SymbolPropertiesDatabaseSymbolMapper symbolMapper,
|
||||
ISecurityProvider securityProvider,
|
||||
string apiKey,
|
||||
string apiSecret,
|
||||
string restApiUrl
|
||||
)
|
||||
: base(symbolMapper, securityProvider, apiKey, apiSecret, restApiUrl, _apiPrefix, _apiPrefix)
|
||||
{
|
||||
}
|
||||
|
||||
protected override JsonConverter CreateAccountConverter()
|
||||
=> new SpotAccountConverter();
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
/*
|
||||
/*
|
||||
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
|
||||
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
|
||||
*
|
||||
@@ -24,15 +24,27 @@ namespace QuantConnect.Brokerages.Binance.Messages
|
||||
|
||||
public class AccountInformation
|
||||
{
|
||||
public Balance[] Balances { get; set; }
|
||||
public BalanceEntry[] Balances { get; set; }
|
||||
}
|
||||
|
||||
public class Balance
|
||||
{
|
||||
public string Asset { get; set; }
|
||||
public decimal Free { get; set; }
|
||||
public decimal Locked { get; set; }
|
||||
public decimal Amount => Free + Locked;
|
||||
}
|
||||
public class BalanceEntry
|
||||
{
|
||||
public string Asset { get; set; }
|
||||
public decimal Free { get; set; }
|
||||
public decimal Locked { get; set; }
|
||||
public virtual decimal Amount { get; }
|
||||
}
|
||||
|
||||
public class SpotBalance : BalanceEntry
|
||||
{
|
||||
public override decimal Amount => Free + Locked;
|
||||
}
|
||||
|
||||
public class MarginBalance : BalanceEntry
|
||||
{
|
||||
public decimal Borrowed { get; set; }
|
||||
public decimal NetAsset { get; set; }
|
||||
public override decimal Amount => NetAsset;
|
||||
}
|
||||
|
||||
public class PriceTicker
|
||||
|
||||
57
Brokerages/Binance/Messages/MarginAccountConverter.cs
Normal file
57
Brokerages/Binance/Messages/MarginAccountConverter.cs
Normal file
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* 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 Newtonsoft.Json;
|
||||
using System;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace QuantConnect.Brokerages.Binance.Messages
|
||||
{
|
||||
/// <summary>
|
||||
/// Deserializes cross margin Account data
|
||||
/// https://binance-docs.github.io/apidocs/spot/en/#query-cross-margin-account-details-user_data
|
||||
/// </summary>
|
||||
public class MarginAccountConverter : JsonConverter
|
||||
{
|
||||
public override bool CanConvert(Type objectType)
|
||||
=> typeof(AccountInformation).IsAssignableFrom(objectType);
|
||||
|
||||
/// <summary>Reads the JSON representation of the margin account data and asset balances.</summary>
|
||||
/// <param name="reader">The <see cref="T:Newtonsoft.Json.JsonReader" /> to read from.</param>
|
||||
/// <param name="objectType">Type of the object.</param>
|
||||
/// <param name="existingValue">The existing value of object being read.</param>
|
||||
/// <param name="serializer">The calling serializer.</param>
|
||||
/// <returns>The object value.</returns>
|
||||
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
|
||||
{
|
||||
JObject token = JObject.Load(reader);
|
||||
var balances = token.GetValue("userAssets", StringComparison.OrdinalIgnoreCase).ToObject<MarginBalance[]>();
|
||||
if (balances == null)
|
||||
{
|
||||
throw new ArgumentException("userAssets parameter name is not specified.");
|
||||
}
|
||||
|
||||
return new AccountInformation()
|
||||
{
|
||||
Balances = balances
|
||||
};
|
||||
}
|
||||
|
||||
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
58
Brokerages/Binance/Messages/SpotAccountConverter.cs
Normal file
58
Brokerages/Binance/Messages/SpotAccountConverter.cs
Normal file
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* 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 Newtonsoft.Json;
|
||||
using System;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace QuantConnect.Brokerages.Binance.Messages
|
||||
{
|
||||
/// <summary>
|
||||
/// Deserializes Spot Account data
|
||||
/// https://binance-docs.github.io/apidocs/spot/en/#account-information-user_data
|
||||
/// </summary>
|
||||
public class SpotAccountConverter : JsonConverter
|
||||
{
|
||||
public override bool CanConvert(Type objectType)
|
||||
=> typeof(AccountInformation).IsAssignableFrom(objectType);
|
||||
|
||||
/// <summary>Reads the JSON representation of the spot account data and asset balances.</summary>
|
||||
/// <param name="reader">The <see cref="T:Newtonsoft.Json.JsonReader" /> to read from.</param>
|
||||
/// <param name="objectType">Type of the object.</param>
|
||||
/// <param name="existingValue">The existing value of object being read.</param>
|
||||
/// <param name="serializer">The calling serializer.</param>
|
||||
/// <returns>The object value.</returns>
|
||||
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
|
||||
{
|
||||
JObject token = JObject.Load(reader);
|
||||
var balances = token.GetValue("balances", StringComparison.OrdinalIgnoreCase).ToObject<SpotBalance[]>();
|
||||
if (balances == null)
|
||||
{
|
||||
throw new ArgumentException("userAssets parameter name is not specified.");
|
||||
}
|
||||
|
||||
return new AccountInformation()
|
||||
{
|
||||
Balances = balances
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -24,7 +24,6 @@ using QuantConnect.Orders;
|
||||
using QuantConnect.Orders.Fees;
|
||||
using QuantConnect.Packets;
|
||||
using QuantConnect.Securities;
|
||||
using QuantConnect.Securities.Crypto;
|
||||
using QuantConnect.Util;
|
||||
using RestSharp;
|
||||
using System;
|
||||
@@ -49,7 +48,6 @@ namespace QuantConnect.Brokerages.Bitfinex
|
||||
private IAlgorithm _algorithm;
|
||||
private readonly RateGate _restRateLimiter = new RateGate(10, TimeSpan.FromMinutes(1));
|
||||
private readonly ConcurrentDictionary<int, decimal> _fills = new ConcurrentDictionary<int, decimal>();
|
||||
private SymbolPropertiesDatabase _symbolPropertiesDatabase;
|
||||
private IDataAggregator _aggregator;
|
||||
|
||||
// map Bitfinex ClientOrderId -> LEAN order (only used for orders submitted in PlaceOrder, not for existing orders)
|
||||
@@ -188,7 +186,6 @@ namespace QuantConnect.Brokerages.Bitfinex
|
||||
TimeSpan.Zero,
|
||||
_connectionRateLimiter);
|
||||
|
||||
_symbolPropertiesDatabase = SymbolPropertiesDatabase.FromDataFolder();
|
||||
_algorithm = algorithm;
|
||||
_aggregator = aggregator;
|
||||
|
||||
@@ -473,27 +470,14 @@ namespace QuantConnect.Brokerages.Bitfinex
|
||||
: OrderStatus.PartiallyFilled;
|
||||
}
|
||||
|
||||
if (_algorithm.BrokerageModel.AccountType == AccountType.Cash &&
|
||||
order.Direction == OrderDirection.Buy)
|
||||
if (_algorithm.BrokerageModel.AccountType == AccountType.Cash && order.Direction == OrderDirection.Buy)
|
||||
{
|
||||
var symbolProperties = _symbolPropertiesDatabase.GetSymbolProperties(symbol.ID.Market,
|
||||
symbol,
|
||||
symbol.SecurityType,
|
||||
AccountBaseCurrency);
|
||||
Crypto.DecomposeCurrencyPair(symbol, symbolProperties, out var baseCurrency, out var _);
|
||||
|
||||
CurrencyPairUtil.DecomposeCurrencyPair(symbol, out var baseCurrency, out _);
|
||||
if (orderFee.Value.Currency != baseCurrency)
|
||||
{
|
||||
OnMessage(new BrokerageMessageEvent(BrokerageMessageType.Error, "UnexpectedFeeCurrency", $"Unexpected fee currency {orderFee.Value.Currency} for symbol {symbol}. OrderId {order.Id}. BrokerageOrderId {brokerId}. " +
|
||||
"This error can happen because your account is Margin type and Lean is configured to be Cash type or while using Cash type the Bitfinex account fee settings are set to 'Asset Trading Fee' and should be set to 'Currency Exchange Fee'."));
|
||||
}
|
||||
else
|
||||
{
|
||||
// fees are debited in the base currency, so we have to subtract them from the filled quantity
|
||||
fillQuantity -= orderFee.Value.Amount;
|
||||
|
||||
orderFee = new ModifiedFillQuantityOrderFee(orderFee.Value);
|
||||
}
|
||||
}
|
||||
|
||||
var orderEvent = new OrderEvent
|
||||
|
||||
@@ -23,7 +23,6 @@ using QuantConnect.Logging;
|
||||
using QuantConnect.Orders;
|
||||
using QuantConnect.Packets;
|
||||
using QuantConnect.Securities;
|
||||
using QuantConnect.Securities.Crypto;
|
||||
using QuantConnect.Util;
|
||||
using RestSharp;
|
||||
using System;
|
||||
@@ -308,16 +307,7 @@ namespace QuantConnect.Brokerages.Bitfinex
|
||||
foreach (var holding in GetAccountHoldings().Where(x => x.Symbol.SecurityType == SecurityType.Crypto))
|
||||
{
|
||||
var defaultQuoteCurrency = _algorithm.Portfolio.CashBook.AccountCurrency;
|
||||
|
||||
var symbolProperties = _symbolPropertiesDatabase.GetSymbolProperties(
|
||||
holding.Symbol.ID.Market,
|
||||
holding.Symbol,
|
||||
holding.Symbol.SecurityType,
|
||||
defaultQuoteCurrency);
|
||||
|
||||
string baseCurrency;
|
||||
string quoteCurrency;
|
||||
Crypto.DecomposeCurrencyPair(holding.Symbol, symbolProperties, out baseCurrency, out quoteCurrency);
|
||||
CurrencyPairUtil.DecomposeCurrencyPair(holding.Symbol, out var baseCurrency, out var quoteCurrency, defaultQuoteCurrency);
|
||||
|
||||
var baseQuantity = holding.Quantity;
|
||||
CashAmount baseCurrencyAmount;
|
||||
@@ -443,7 +433,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);
|
||||
|
||||
@@ -148,7 +148,7 @@ namespace QuantConnect.Brokerages
|
||||
/// <summary>
|
||||
/// Wraps IsAlive
|
||||
/// </summary>
|
||||
public bool IsOpen => _client != null && _client.State == WebSocketState.Open;
|
||||
public bool IsOpen => _client?.State == WebSocketState.Open;
|
||||
|
||||
/// <summary>
|
||||
/// Wraps message event
|
||||
|
||||
@@ -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 *
|
||||
@@ -60,7 +61,6 @@ from QuantConnect.Data.Shortable import *
|
||||
from QuantConnect.Orders.Slippage import *
|
||||
from QuantConnect.Securities.Forex import *
|
||||
from QuantConnect.Data.Fundamental import *
|
||||
from QuantConnect.Algorithm.CSharp import *
|
||||
from QuantConnect.Securities.Option import *
|
||||
from QuantConnect.Securities.Equity import *
|
||||
from QuantConnect.Securities.Future import *
|
||||
|
||||
@@ -66,13 +66,25 @@ namespace QuantConnect.Api
|
||||
/// </returns>
|
||||
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
|
||||
{
|
||||
var jObject = JObject.Load(reader);
|
||||
if (reader.TokenType == JsonToken.StartArray)
|
||||
{
|
||||
if (JArray.Load(reader).Count == 0)
|
||||
{
|
||||
return new ParameterSet(-1, new Dictionary<string, string>());
|
||||
}
|
||||
}
|
||||
else if (reader.TokenType == JsonToken.StartObject)
|
||||
{
|
||||
var jObject = JObject.Load(reader);
|
||||
|
||||
var value = jObject["parameterSet"] ?? jObject;
|
||||
var value = jObject["parameterSet"] ?? jObject;
|
||||
|
||||
var parameterSet = new ParameterSet(-1, value.ToObject<Dictionary<string, string>>());
|
||||
var parameterSet = new ParameterSet(-1, value.ToObject<Dictionary<string, string>>());
|
||||
|
||||
return parameterSet;
|
||||
return parameterSet;
|
||||
}
|
||||
|
||||
throw new ArgumentException($"Unexpected Tokentype {reader.TokenType}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,6 @@ using QuantConnect.Orders;
|
||||
using QuantConnect.Orders.Fees;
|
||||
using QuantConnect.Securities;
|
||||
using QuantConnect.Util;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using static QuantConnect.StringExtensions;
|
||||
@@ -30,6 +29,8 @@ namespace QuantConnect.Brokerages
|
||||
/// </summary>
|
||||
public class BinanceBrokerageModel : DefaultBrokerageModel
|
||||
{
|
||||
private const decimal _defaultLeverage = 3;
|
||||
|
||||
/// <summary>
|
||||
/// Gets a map of the default markets to be used for each security type
|
||||
/// </summary>
|
||||
@@ -41,22 +42,20 @@ namespace QuantConnect.Brokerages
|
||||
/// <param name="accountType">The type of account to be modeled, defaults to <see cref="AccountType.Cash"/></param>
|
||||
public BinanceBrokerageModel(AccountType accountType = AccountType.Cash) : base(accountType)
|
||||
{
|
||||
if (accountType == AccountType.Margin)
|
||||
{
|
||||
throw new ArgumentException("The Binance brokerage does not currently support Margin trading.");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a new buying power model for the security, returning the default model with the security's configured leverage.
|
||||
/// For cash accounts, leverage = 1 is used.
|
||||
/// Margin trading is not currently supported
|
||||
/// For standard account margin trading the leverage is 3x, leverage 5x only supported in the master account
|
||||
/// </summary>
|
||||
/// <param name="security">The security to get a buying power model for</param>
|
||||
/// <returns>The buying power model for this brokerage/security</returns>
|
||||
public override IBuyingPowerModel GetBuyingPowerModel(Security security)
|
||||
{
|
||||
return new CashBuyingPowerModel();
|
||||
return AccountType == AccountType.Cash
|
||||
? new CashBuyingPowerModel()
|
||||
: new SecurityMarginModel(GetLeverage(security));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -66,8 +65,12 @@ namespace QuantConnect.Brokerages
|
||||
/// <returns></returns>
|
||||
public override decimal GetLeverage(Security security)
|
||||
{
|
||||
// margin trading is not currently supported by Binance
|
||||
return 1m;
|
||||
if (AccountType == AccountType.Cash || security.IsInternalFeed() || security.Type == SecurityType.Base)
|
||||
{
|
||||
return 1m;
|
||||
}
|
||||
|
||||
return _defaultLeverage;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -95,7 +95,7 @@ namespace QuantConnect.Brokerages
|
||||
/// Transaction and submit/execution rules will use TradingTechnologies models
|
||||
/// </summary>
|
||||
TradingTechnologies,
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Transaction and submit/execution rules will use Kraken models
|
||||
/// </summary>
|
||||
@@ -109,6 +109,11 @@ namespace QuantConnect.Brokerages
|
||||
/// <summary>
|
||||
/// Transaction and submit/execution rules will use ftx us models
|
||||
/// </summary>
|
||||
FTXUS
|
||||
FTXUS,
|
||||
|
||||
/// <summary>
|
||||
/// Transaction and submit/execution rules will use Exante models
|
||||
/// </summary>
|
||||
Exante,
|
||||
}
|
||||
}
|
||||
|
||||
132
Common/Brokerages/ExanteBrokerageModel.cs
Normal file
132
Common/Brokerages/ExanteBrokerageModel.cs
Normal file
@@ -0,0 +1,132 @@
|
||||
/*
|
||||
* 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.Reflection;
|
||||
using System.Reflection.Emit;
|
||||
using QuantConnect.Benchmarks;
|
||||
using QuantConnect.Orders;
|
||||
using QuantConnect.Orders.Fees;
|
||||
using QuantConnect.Securities;
|
||||
using static QuantConnect.StringExtensions;
|
||||
using static QuantConnect.Util.SecurityExtensions;
|
||||
|
||||
namespace QuantConnect.Brokerages
|
||||
{
|
||||
/// <summary>
|
||||
/// Exante Brokerage Model Implementation for Back Testing.
|
||||
/// </summary>
|
||||
public class ExanteBrokerageModel : DefaultBrokerageModel
|
||||
{
|
||||
private const decimal EquityLeverage = 1.2m;
|
||||
|
||||
/// <summary>
|
||||
/// Constructor for Exante brokerage model
|
||||
/// </summary>
|
||||
/// <param name="accountType">Cash or Margin</param>
|
||||
public ExanteBrokerageModel(AccountType accountType = AccountType.Cash)
|
||||
: base(accountType)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the benchmark for this model
|
||||
/// </summary>
|
||||
/// <param name="securities">SecurityService to create the security with if needed</param>
|
||||
/// <returns>The benchmark for this brokerage</returns>
|
||||
public override IBenchmark GetBenchmark(SecurityManager securities)
|
||||
{
|
||||
var symbol = Symbol.Create("SPY", SecurityType.Equity, Market.USA);
|
||||
return SecurityBenchmark.CreateInstance(securities, symbol);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the brokerage could accept this order. This takes into account
|
||||
/// order type, security type, and order size limits.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// For example, a brokerage may have no connectivity at certain times, or an order rate/size limit
|
||||
/// </remarks>
|
||||
/// <param name="security">The security being ordered</param>
|
||||
/// <param name="order">The order to be processed</param>
|
||||
/// <param name="message">If this function returns false, a brokerage message detailing why the order may not be submitted</param>
|
||||
/// <returns>True if the brokerage could process the order, false otherwise</returns>
|
||||
public override bool CanSubmitOrder(Security security, Order order, out BrokerageMessageEvent message)
|
||||
{
|
||||
message = null;
|
||||
|
||||
if (order == null)
|
||||
{
|
||||
message = new BrokerageMessageEvent(BrokerageMessageType.Warning, "NotSupported",
|
||||
Invariant($"Order is null.")
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (order.Price == 0m)
|
||||
{
|
||||
message = new BrokerageMessageEvent(BrokerageMessageType.Warning, "NotSupported",
|
||||
Invariant($"Price is not set.")
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (security.Type != SecurityType.Forex &&
|
||||
security.Type != SecurityType.Equity &&
|
||||
security.Type != SecurityType.Index &&
|
||||
security.Type != SecurityType.Option &&
|
||||
security.Type != SecurityType.Future &&
|
||||
security.Type != SecurityType.Cfd &&
|
||||
security.Type != SecurityType.Crypto &&
|
||||
security.Type != SecurityType.Index)
|
||||
{
|
||||
message = new BrokerageMessageEvent(BrokerageMessageType.Warning, "NotSupported",
|
||||
Invariant(
|
||||
$"The {nameof(ExanteBrokerageModel)} does not support {security.Type} security type.")
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a new fee model that represents this brokerage's fee structure
|
||||
/// </summary>
|
||||
/// <param name="security">The security to get a fee model for</param>
|
||||
/// <returns>The new fee model for this brokerage</returns>
|
||||
public override IFeeModel GetFeeModel(Security security) => new ExanteFeeModel();
|
||||
|
||||
/// <summary>
|
||||
/// Exante global leverage rule
|
||||
/// </summary>
|
||||
/// <param name="security">The security's whose leverage we seek</param>
|
||||
/// <returns>The leverage for the specified security</returns>
|
||||
public override decimal GetLeverage(Security security)
|
||||
{
|
||||
if (AccountType == AccountType.Cash || security.IsInternalFeed() || security.Type == SecurityType.Base)
|
||||
{
|
||||
return 1m;
|
||||
}
|
||||
|
||||
return security.Type switch
|
||||
{
|
||||
SecurityType.Forex => 1.05m,
|
||||
SecurityType.Equity => EquityLeverage,
|
||||
_ => 1.0m,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -227,6 +227,9 @@ namespace QuantConnect.Brokerages
|
||||
|
||||
case BrokerageName.Kraken:
|
||||
return new KrakenBrokerageModel(accountType);
|
||||
|
||||
case BrokerageName.Exante:
|
||||
return new ExanteBrokerageModel(accountType);
|
||||
|
||||
case BrokerageName.FTX:
|
||||
return new FTXBrokerageModel(accountType);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
|
||||
using System;
|
||||
using QuantConnect.Securities;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace QuantConnect.Data
|
||||
{
|
||||
@@ -51,6 +52,11 @@ namespace QuantConnect.Data
|
||||
/// </summary>
|
||||
public SecurityExchangeHours ExchangeHours { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the tradable days specified by this request, in the security's data time zone
|
||||
/// </summary>
|
||||
public abstract IEnumerable<DateTime> TradableDays { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the base data request
|
||||
/// </summary>
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
using System;
|
||||
using NodaTime;
|
||||
using QuantConnect.Securities;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace QuantConnect.Data
|
||||
{
|
||||
@@ -94,6 +95,15 @@ namespace QuantConnect.Data
|
||||
/// </summary>
|
||||
public uint ContractDepthOffset { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the tradable days specified by this request, in the security's data time zone
|
||||
/// </summary>
|
||||
public override IEnumerable<DateTime> TradableDays => Time.EachTradeableDayInTimeZone(ExchangeHours,
|
||||
StartTimeLocal,
|
||||
EndTimeLocal,
|
||||
DataTimeZone,
|
||||
IncludeExtendedMarketHours);
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="HistoryRequest"/> class from the specified parameters
|
||||
/// </summary>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -340,7 +340,7 @@ namespace QuantConnect.Data
|
||||
var requestedOpenInterest = type == typeof(OpenInterest);
|
||||
if (type == typeof(Tick) || requestedOpenInterest)
|
||||
{
|
||||
var dataDictionaryCache = GenericDataDictionary.Get(type);
|
||||
var dataDictionaryCache = GenericDataDictionary.Get(type, isPythonData: false);
|
||||
dictionary = Activator.CreateInstance(dataDictionaryCache.GenericType);
|
||||
|
||||
foreach (var data in instance.Ticks)
|
||||
@@ -390,10 +390,23 @@ namespace QuantConnect.Data
|
||||
}
|
||||
else
|
||||
{
|
||||
var dataDictionaryCache = GenericDataDictionary.Get(type);
|
||||
var isPythonData = type.IsAssignableTo(typeof(PythonData));
|
||||
|
||||
var dataDictionaryCache = GenericDataDictionary.Get(type, isPythonData);
|
||||
dictionary = Activator.CreateInstance(dataDictionaryCache.GenericType);
|
||||
|
||||
foreach (var data in instance._data.Value.Values.Select(x => x.Custom).Where(o => o != null && o.GetType() == type))
|
||||
foreach (var data in instance._data.Value.Values.Select(x => x.Custom).Where(o =>
|
||||
{
|
||||
if (o == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (isPythonData && o is PythonData data)
|
||||
{
|
||||
return data.IsOfType(type);
|
||||
}
|
||||
return o.GetType() == type;
|
||||
}))
|
||||
{
|
||||
dataDictionaryCache.MethodInfo.Invoke(dictionary, new object[] { data.Symbol, data });
|
||||
}
|
||||
@@ -653,15 +666,22 @@ namespace QuantConnect.Data
|
||||
/// <summary>
|
||||
/// Provides a <see cref="GenericDataDictionary"/> instance for a given <see cref="Type"/>
|
||||
/// </summary>
|
||||
/// <param name="type"></param>
|
||||
/// <param name="type">The requested data type</param>
|
||||
/// <param name="isPythonData">True if data is of <see cref="PythonData"/> type</param>
|
||||
/// <returns>A new instance or retrieved from the cache</returns>
|
||||
public static GenericDataDictionary Get(Type type)
|
||||
public static GenericDataDictionary Get(Type type, bool isPythonData)
|
||||
{
|
||||
GenericDataDictionary dataDictionaryCache;
|
||||
if (!_genericCache.TryGetValue(type, out dataDictionaryCache))
|
||||
{
|
||||
var generic = typeof(DataDictionary<>).MakeGenericType(type);
|
||||
var method = generic.GetMethod("Add", new[] { typeof(Symbol), type });
|
||||
var dictionaryType = type;
|
||||
if (isPythonData)
|
||||
{
|
||||
// let's create a python data dictionary because the data itself will be a PythonData type in C#
|
||||
dictionaryType = typeof(PythonData);
|
||||
}
|
||||
var generic = typeof(DataDictionary<>).MakeGenericType(dictionaryType);
|
||||
var method = generic.GetMethod("Add", new[] { typeof(Symbol), dictionaryType });
|
||||
_genericCache[type] = dataDictionaryCache = new GenericDataDictionary(generic, method);
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -47,18 +47,11 @@ namespace QuantConnect.Data.UniverseSelection
|
||||
/// <summary>
|
||||
/// Gets the tradable days specified by this request, in the security's data time zone
|
||||
/// </summary>
|
||||
public IEnumerable<DateTime> TradableDays
|
||||
{
|
||||
get
|
||||
{
|
||||
return Time.EachTradeableDayInTimeZone(Security.Exchange.Hours,
|
||||
StartTimeLocal,
|
||||
EndTimeLocal,
|
||||
Configuration.DataTimeZone,
|
||||
Configuration.ExtendedMarketHours
|
||||
);
|
||||
}
|
||||
}
|
||||
public override IEnumerable<DateTime> TradableDays => Time.EachTradeableDayInTimeZone(Security.Exchange.Hours,
|
||||
StartTimeLocal,
|
||||
EndTimeLocal,
|
||||
Configuration.DataTimeZone,
|
||||
Configuration.ExtendedMarketHours);
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="SubscriptionRequest"/> class
|
||||
@@ -105,4 +98,4 @@ namespace QuantConnect.Data.UniverseSelection
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -348,4 +348,4 @@ namespace QuantConnect
|
||||
return GetValues.ToPyList();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1634,6 +1634,45 @@ namespace QuantConnect
|
||||
return rounded;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper method to determine if a specific market is open
|
||||
/// </summary>
|
||||
/// <param name="security">The target security</param>
|
||||
/// <param name="extendedMarketHours">True if should consider extended market hours</param>
|
||||
/// <returns>True if the market is open</returns>
|
||||
public static bool IsMarketOpen(this Security security, bool extendedMarketHours)
|
||||
{
|
||||
if (!security.Exchange.Hours.IsOpen(security.LocalTime, extendedMarketHours))
|
||||
{
|
||||
// if we're not open at the current time exactly, check the bar size, this handle large sized bars (hours/days)
|
||||
var currentBar = security.GetLastData();
|
||||
if (currentBar == null
|
||||
|| security.LocalTime.Date != currentBar.EndTime.Date
|
||||
|| !security.Exchange.IsOpenDuringBar(currentBar.Time, currentBar.EndTime, extendedMarketHours))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper method to determine if a specific market is open
|
||||
/// </summary>
|
||||
/// <param name="symbol">The target symbol</param>
|
||||
/// <param name="utcTime">The current UTC time</param>
|
||||
/// <param name="extendedMarketHours">True if should consider extended market hours</param>
|
||||
/// <returns>True if the market is open</returns>
|
||||
public static bool IsMarketOpen(this Symbol symbol, DateTime utcTime, bool extendedMarketHours)
|
||||
{
|
||||
var exchangeHours = MarketHoursDatabase.FromDataFolder()
|
||||
.GetExchangeHours(symbol.ID.Market, symbol, symbol.SecurityType);
|
||||
|
||||
var time = utcTime.ConvertFromUtc(exchangeHours.TimeZone);
|
||||
|
||||
return exchangeHours.IsOpen(time, extendedMarketHours);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Extension method to round a datetime to the nearest unit timespan.
|
||||
/// </summary>
|
||||
@@ -2857,15 +2896,12 @@ namespace QuantConnect
|
||||
PythonActivator pythonType;
|
||||
if (!PythonActivators.TryGetValue(pyObject.Handle, out pythonType))
|
||||
{
|
||||
AssemblyName an;
|
||||
using (Py.GIL())
|
||||
{
|
||||
an = new AssemblyName(pyObject.Repr().Split('\'')[1]);
|
||||
}
|
||||
var assemblyName = pyObject.GetAssemblyName();
|
||||
var typeBuilder = AssemblyBuilder
|
||||
.DefineDynamicAssembly(an, AssemblyBuilderAccess.Run)
|
||||
.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run)
|
||||
.DefineDynamicModule("MainModule")
|
||||
.DefineType(an.Name, TypeAttributes.Class, type);
|
||||
// creating the type as public is required to allow 'dynamic' to be able to bind at runtime
|
||||
.DefineType(assemblyName.Name, TypeAttributes.Class | TypeAttributes.Public, type);
|
||||
|
||||
pythonType = new PythonActivator(typeBuilder.CreateType(), pyObject);
|
||||
|
||||
@@ -2877,6 +2913,19 @@ namespace QuantConnect
|
||||
return pythonType.Type;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper method to get the assembly name from a python type
|
||||
/// </summary>
|
||||
/// <param name="pyObject">Python object pointing to the python type. <see cref="PyObject.GetPythonType"/></param>
|
||||
/// <returns>The python type assembly name</returns>
|
||||
public static AssemblyName GetAssemblyName(this PyObject pyObject)
|
||||
{
|
||||
using (Py.GIL())
|
||||
{
|
||||
return new AssemblyName(pyObject.Repr().Split('\'')[1]);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs on-line batching of the specified enumerator, emitting chunks of the requested batch size
|
||||
/// </summary>
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
using QuantConnect.Util;
|
||||
using QuantConnect.Securities;
|
||||
|
||||
namespace QuantConnect.Orders.Fees
|
||||
@@ -58,7 +59,8 @@ namespace QuantConnect.Orders.Fees
|
||||
var security = parameters.Security;
|
||||
var order = parameters.Order;
|
||||
|
||||
decimal fee = _takerFee;
|
||||
// apply fee factor, currently we do not model 30-day volume, so we use the first tier
|
||||
var fee = _takerFee;
|
||||
var props = order.Properties as BinanceOrderProperties;
|
||||
|
||||
if (order.Type == OrderType.Limit &&
|
||||
@@ -68,6 +70,13 @@ namespace QuantConnect.Orders.Fees
|
||||
fee = _makerFee;
|
||||
}
|
||||
|
||||
if (order.Direction == OrderDirection.Buy)
|
||||
{
|
||||
// fees taken in the received currency
|
||||
CurrencyPairUtil.DecomposeCurrencyPair(order.Symbol, out var baseCurrency, out _);
|
||||
return new OrderFee(new CashAmount(order.AbsoluteQuantity * fee, baseCurrency));
|
||||
}
|
||||
|
||||
// get order value in quote currency
|
||||
var unitPrice = order.Direction == OrderDirection.Buy ? security.AskPrice : security.BidPrice;
|
||||
if (order.Type == OrderType.Limit)
|
||||
@@ -78,7 +87,6 @@ namespace QuantConnect.Orders.Fees
|
||||
|
||||
unitPrice *= security.SymbolProperties.ContractMultiplier;
|
||||
|
||||
// apply fee factor, currently we do not model 30-day volume, so we use the first tier
|
||||
return new OrderFee(new CashAmount(
|
||||
unitPrice * order.AbsoluteQuantity * fee,
|
||||
security.QuoteCurrency.Symbol));
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
using QuantConnect.Util;
|
||||
using QuantConnect.Securities;
|
||||
|
||||
namespace QuantConnect.Orders.Fees
|
||||
@@ -46,7 +47,8 @@ namespace QuantConnect.Orders.Fees
|
||||
{
|
||||
var order = parameters.Order;
|
||||
var security = parameters.Security;
|
||||
decimal fee = TakerFee;
|
||||
// apply fee factor, currently we do not model 30-day volume, so we use the first tier
|
||||
var fee = TakerFee;
|
||||
var props = order.Properties as BitfinexOrderProperties;
|
||||
|
||||
if (order.Type == OrderType.Limit &&
|
||||
@@ -57,6 +59,13 @@ namespace QuantConnect.Orders.Fees
|
||||
fee = MakerFee;
|
||||
}
|
||||
|
||||
if (order.Direction == OrderDirection.Buy)
|
||||
{
|
||||
// fees taken in the received currency
|
||||
CurrencyPairUtil.DecomposeCurrencyPair(order.Symbol, out var baseCurrency, out _);
|
||||
return new OrderFee(new CashAmount(order.AbsoluteQuantity * fee, baseCurrency));
|
||||
}
|
||||
|
||||
// get order value in quote currency
|
||||
var unitPrice = order.Direction == OrderDirection.Buy ? security.AskPrice : security.BidPrice;
|
||||
if (order.Type == OrderType.Limit)
|
||||
@@ -67,7 +76,6 @@ namespace QuantConnect.Orders.Fees
|
||||
|
||||
unitPrice *= security.SymbolProperties.ContractMultiplier;
|
||||
|
||||
// apply fee factor, currently we do not model 30-day volume, so we use the first tier
|
||||
return new OrderFee(new CashAmount(
|
||||
unitPrice * order.AbsoluteQuantity * fee,
|
||||
security.QuoteCurrency.Symbol));
|
||||
|
||||
124
Common/Orders/Fees/ExanteFeeModel.cs
Normal file
124
Common/Orders/Fees/ExanteFeeModel.cs
Normal file
@@ -0,0 +1,124 @@
|
||||
/*
|
||||
* 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.Securities;
|
||||
using static QuantConnect.StringExtensions;
|
||||
|
||||
namespace QuantConnect.Orders.Fees
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides an implementation of <see cref="FeeModel"/> that models Exante order fees.
|
||||
/// According to:
|
||||
/// <list type="bullet">
|
||||
/// <item>https://support.exante.eu/hc/en-us/articles/115005873143-Fees-overview-exchange-imposed-fees?source=search</item>
|
||||
/// <item>https://exante.eu/markets/</item>
|
||||
/// </list>
|
||||
/// </summary>
|
||||
public class ExanteFeeModel : FeeModel
|
||||
{
|
||||
public const decimal MarketUsaRate = 0.02m;
|
||||
public const decimal DefaultRate = 0.02m;
|
||||
|
||||
private readonly decimal _forexCommissionRate;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance
|
||||
/// </summary>
|
||||
/// <param name="forexCommissionRate">Commission rate for FX operations</param>
|
||||
public ExanteFeeModel(decimal forexCommissionRate = 0.25m)
|
||||
{
|
||||
_forexCommissionRate = forexCommissionRate;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the order fee associated with the specified order.
|
||||
/// </summary>
|
||||
/// <param name="parameters">A <see cref="OrderFeeParameters"/> object
|
||||
/// containing the security and order</param>
|
||||
/// <returns>The cost of the order in a <see cref="CashAmount"/> instance</returns>
|
||||
public override OrderFee GetOrderFee(OrderFeeParameters parameters)
|
||||
{
|
||||
var order = parameters.Order;
|
||||
var security = parameters.Security;
|
||||
|
||||
decimal feeResult;
|
||||
string feeCurrency;
|
||||
switch (security.Type)
|
||||
{
|
||||
case SecurityType.Forex:
|
||||
var totalOrderValue = order.GetValue(security);
|
||||
feeResult = Math.Abs(_forexCommissionRate * totalOrderValue);
|
||||
feeCurrency = Currencies.USD;
|
||||
break;
|
||||
|
||||
case SecurityType.Equity:
|
||||
var equityFee = ComputeEquityFee(order);
|
||||
feeResult = equityFee.Amount;
|
||||
feeCurrency = equityFee.Currency;
|
||||
break;
|
||||
|
||||
case SecurityType.Option:
|
||||
case SecurityType.IndexOption:
|
||||
var optionsFee = ComputeOptionFee(order);
|
||||
feeResult = optionsFee.Amount;
|
||||
feeCurrency = optionsFee.Currency;
|
||||
break;
|
||||
|
||||
case SecurityType.Future:
|
||||
case SecurityType.FutureOption:
|
||||
feeResult = 1.5m;
|
||||
feeCurrency = Currencies.USD;
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new ArgumentException(Invariant($"Unsupported security type: {security.Type}"));
|
||||
}
|
||||
|
||||
return new OrderFee(new CashAmount(feeResult, feeCurrency));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Computes fee for equity order
|
||||
/// </summary>
|
||||
/// <param name="order">LEAN order</param>
|
||||
private static CashAmount ComputeEquityFee(Order order)
|
||||
{
|
||||
switch (order.Symbol.ID.Market)
|
||||
{
|
||||
case Market.USA:
|
||||
return new CashAmount(order.AbsoluteQuantity * MarketUsaRate, Currencies.USD);
|
||||
|
||||
default:
|
||||
return new CashAmount(order.AbsoluteQuantity * order.Price * DefaultRate, Currencies.USD);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Computes fee for option order
|
||||
/// </summary>
|
||||
/// <param name="order">LEAN order</param>
|
||||
private static CashAmount ComputeOptionFee(Order order)
|
||||
{
|
||||
return order.Symbol.ID.Market switch
|
||||
{
|
||||
Market.USA => new CashAmount(order.AbsoluteQuantity * 1.5m, Currencies.USD),
|
||||
_ =>
|
||||
// ToDo: clarify the value for different exchanges
|
||||
throw new ArgumentException(Invariant($"Unsupported exchange: ${order.Symbol.ID.Market}"))
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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}");
|
||||
}
|
||||
|
||||
@@ -18,7 +18,8 @@ using QuantConnect.Securities;
|
||||
namespace QuantConnect.Orders.Fees
|
||||
{
|
||||
/// <summary>
|
||||
/// An order fee where the fee quantity has already been subtracted from the filled quantity
|
||||
/// An order fee where the fee quantity has already been subtracted from the filled quantity so instead we subtracted
|
||||
/// from the quote currency when applied to the portfolio
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This type of order fee is returned by some crypto brokerages (e.g. Bitfinex and Binance)
|
||||
@@ -26,13 +27,20 @@ namespace QuantConnect.Orders.Fees
|
||||
/// </remarks>
|
||||
public class ModifiedFillQuantityOrderFee : OrderFee
|
||||
{
|
||||
private readonly string _quoteCurrency;
|
||||
private readonly decimal _contractMultiplier;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ModifiedFillQuantityOrderFee"/> class
|
||||
/// </summary>
|
||||
/// <param name="orderFee">The order fee</param>
|
||||
public ModifiedFillQuantityOrderFee(CashAmount orderFee)
|
||||
/// <param name="quoteCurrency">The associated security quote currency</param>
|
||||
/// <param name="contractMultiplier">The associated security contract multiplier</param>
|
||||
public ModifiedFillQuantityOrderFee(CashAmount orderFee, string quoteCurrency, decimal contractMultiplier)
|
||||
: base(orderFee)
|
||||
{
|
||||
_quoteCurrency = quoteCurrency;
|
||||
_contractMultiplier = contractMultiplier;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -42,7 +50,7 @@ namespace QuantConnect.Orders.Fees
|
||||
/// <param name="fill">The order fill event</param>
|
||||
public override void ApplyToPortfolio(SecurityPortfolioManager portfolio, OrderEvent fill)
|
||||
{
|
||||
// do not apply the fee twice
|
||||
portfolio.CashBook[_quoteCurrency].AddAmount(-Value.Amount * fill.FillPrice * _contractMultiplier);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -790,17 +790,7 @@ namespace QuantConnect.Orders.Fills
|
||||
/// </summary>
|
||||
protected static bool IsExchangeOpen(Security asset, bool isExtendedMarketHours)
|
||||
{
|
||||
if (!asset.Exchange.DateTimeIsOpen(asset.LocalTime))
|
||||
{
|
||||
// if we're not open at the current time exactly, check the bar size, this handle large sized bars (hours/days)
|
||||
var currentBar = asset.GetLastData();
|
||||
if (asset.LocalTime.Date != currentBar.EndTime.Date
|
||||
|| !asset.Exchange.IsOpenDuringBar(currentBar.Time, currentBar.EndTime, isExtendedMarketHours))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
return asset.IsMarketOpen(isExtendedMarketHours);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -202,14 +202,11 @@ namespace QuantConnect.Orders
|
||||
protected Order()
|
||||
{
|
||||
Time = new DateTime();
|
||||
Price = 0;
|
||||
PriceCurrency = string.Empty;
|
||||
Quantity = 0;
|
||||
Symbol = Symbol.Empty;
|
||||
Status = OrderStatus.None;
|
||||
Tag = "";
|
||||
Tag = string.Empty;
|
||||
BrokerId = new List<string>();
|
||||
ContingentId = 0;
|
||||
Properties = new OrderProperties();
|
||||
}
|
||||
|
||||
@@ -224,14 +221,12 @@ namespace QuantConnect.Orders
|
||||
protected Order(Symbol symbol, decimal quantity, DateTime time, string tag = "", IOrderProperties properties = null)
|
||||
{
|
||||
Time = time;
|
||||
Price = 0;
|
||||
PriceCurrency = string.Empty;
|
||||
Quantity = quantity;
|
||||
Symbol = symbol;
|
||||
Status = OrderStatus.None;
|
||||
Tag = tag;
|
||||
BrokerId = new List<string>();
|
||||
ContingentId = 0;
|
||||
Properties = properties ?? new OrderProperties();
|
||||
}
|
||||
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using Newtonsoft.Json;
|
||||
using QuantConnect.Securities;
|
||||
|
||||
@@ -68,22 +67,11 @@ namespace QuantConnect.Packets
|
||||
[JsonProperty(PropertyName = "iTradeableDates")]
|
||||
public int TradeableDates = 0;
|
||||
|
||||
/// <summary>
|
||||
/// The initial breakpoints for debugging, if any
|
||||
/// </summary>
|
||||
[JsonProperty(PropertyName = "aBreakpoints")]
|
||||
public List<Breakpoint> Breakpoints = new List<Breakpoint>();
|
||||
|
||||
/// <summary>
|
||||
/// The initial Watchlist for debugging, if any
|
||||
/// </summary>
|
||||
[JsonProperty(PropertyName = "aWatchlist")]
|
||||
public List<string> Watchlist = new List<string>();
|
||||
|
||||
/// <summary>
|
||||
/// True, if this is a debugging backtest
|
||||
/// </summary>
|
||||
public bool IsDebugging => Breakpoints.Any();
|
||||
[JsonProperty(PropertyName = "bDebugging")]
|
||||
public bool IsDebugging;
|
||||
|
||||
/// <summary>
|
||||
/// Optional initial cash amount if set
|
||||
|
||||
@@ -26,6 +26,7 @@ namespace QuantConnect.Python
|
||||
/// </summary>
|
||||
public class PythonData : DynamicData
|
||||
{
|
||||
private readonly string _pythonTypeName;
|
||||
private readonly dynamic _pythonData;
|
||||
private readonly dynamic _defaultResolution;
|
||||
private readonly dynamic _supportedResolutions;
|
||||
@@ -54,6 +55,7 @@ namespace QuantConnect.Python
|
||||
_isSparseData = pythonData.GetPythonMethod("IsSparseData");
|
||||
_defaultResolution = pythonData.GetPythonMethod("DefaultResolution");
|
||||
_supportedResolutions = pythonData.GetPythonMethod("SupportedResolutions");
|
||||
_pythonTypeName = pythonData.GetPythonType().GetAssemblyName().Name;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,7 +88,11 @@ namespace QuantConnect.Python
|
||||
using (Py.GIL())
|
||||
{
|
||||
var data = _pythonData.Reader(config, line, date, isLiveMode);
|
||||
return (data as PyObject).GetAndDispose<BaseData>();
|
||||
var result = (data as PyObject).GetAndDispose<BaseData>();
|
||||
|
||||
(result as PythonData)?.SetProperty("__typename", _pythonTypeName);
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -174,5 +180,19 @@ namespace QuantConnect.Python
|
||||
SetProperty(index, value is double ? value.ConvertInvariant<decimal>() : value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper method to determine if the current instance is of the provided type
|
||||
/// </summary>
|
||||
/// <param name="type">Target type to check against</param>
|
||||
/// <returns>True if this instance is of the provided type</returns>
|
||||
public bool IsOfType(Type type)
|
||||
{
|
||||
if (HasProperty("__typename"))
|
||||
{
|
||||
return (string)GetProperty("__typename") == type.FullName;
|
||||
}
|
||||
return GetType() == type;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/*
|
||||
/*
|
||||
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
|
||||
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
|
||||
*
|
||||
@@ -229,6 +229,96 @@ namespace QuantConnect.Securities
|
||||
/// </summary>
|
||||
/// <returns>The symbol</returns>
|
||||
public const string JapaneseYenEmini = "J7";
|
||||
|
||||
/// <summary>
|
||||
/// Micro EUR/USD Futures
|
||||
/// </summary>
|
||||
/// <returns>The symbol</returns>
|
||||
public const string MicroEUR = "M6E";
|
||||
|
||||
/// <summary>
|
||||
/// Micro AUD/USD Futures
|
||||
/// </summary>
|
||||
/// <returns>The symbol</returns>
|
||||
public const string MicroAUD = "M6A";
|
||||
|
||||
/// <summary>
|
||||
/// Micro GBP/USD Futures
|
||||
/// </summary>
|
||||
/// <returns>The symbol</returns>
|
||||
public const string MicroGBP = "M6B";
|
||||
|
||||
/// <summary>
|
||||
/// Micro CAD/USD Futures
|
||||
/// </summary>
|
||||
/// <returns>The symbol</returns>
|
||||
public const string MicroCADUSD = "MCD";
|
||||
|
||||
/// <summary>
|
||||
/// Micro JPY/USD Futures
|
||||
/// </summary>
|
||||
/// <returns>The symbol</returns>
|
||||
public const string MicroJPY = "MJY";
|
||||
|
||||
/// <summary>
|
||||
/// Micro CHF/USD Futures
|
||||
/// </summary>
|
||||
/// <returns>The symbol</returns>
|
||||
public const string MicroCHF = "MSF";
|
||||
|
||||
/// <summary>
|
||||
/// Micro USD/JPY Futures
|
||||
/// </summary>
|
||||
/// <returns>The symbol</returns>
|
||||
public const string MicroUSDJPY = "M6J";
|
||||
|
||||
/// <summary>
|
||||
/// Micro INR/USD Futures
|
||||
/// </summary>
|
||||
/// <returns>The symbol</returns>
|
||||
public const string MicroINRUSD = "MIR";
|
||||
|
||||
/// <summary>
|
||||
/// Micro USD/CAD Futures
|
||||
/// </summary>
|
||||
/// <returns>The symbol</returns>
|
||||
public const string MicroCAD = "M6C";
|
||||
|
||||
/// <summary>
|
||||
/// Micro USD/CHF Futures
|
||||
/// </summary>
|
||||
/// <returns>The symbol</returns>
|
||||
public const string MicroUSDCHF = "M6S";
|
||||
|
||||
/// <summary>
|
||||
/// Micro USD/CNH Futures
|
||||
/// </summary>
|
||||
/// <returns>The symbol</returns>
|
||||
public const string MicroUSDCNH = "MNH";
|
||||
|
||||
/// <summary>
|
||||
/// Micro Ether Futures
|
||||
/// </summary>
|
||||
/// <returns>The symbol</returns>
|
||||
public const string MicroEther = "MET";
|
||||
|
||||
/// <summary>
|
||||
/// Micro Bitcoin Futures
|
||||
/// </summary>
|
||||
/// <returns>The symbol</returns>
|
||||
public const string MicroBTC = "MBT";
|
||||
|
||||
/// <summary>
|
||||
/// BTIC on Micro Ether Futures
|
||||
/// </summary>
|
||||
/// <returns>The symbol</returns>
|
||||
public const string BTICMicroEther = "MRB";
|
||||
|
||||
/// <summary>
|
||||
/// BTIC on Micro Bitcoin Futures
|
||||
/// </summary>
|
||||
/// <returns>The symbol</returns>
|
||||
public const string BTICMicroBTC = "MIB";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -660,6 +750,54 @@ namespace QuantConnect.Securities
|
||||
/// </summary>
|
||||
/// <returns>The symbol</returns>
|
||||
public const string LowSulfurGasoil = "G";
|
||||
|
||||
/// <summary>
|
||||
/// Micro WTI Crude Oil Futures
|
||||
/// </summary>
|
||||
/// <returns>The symbol</returns>
|
||||
public const string MicroCrudeOilWTI = "MCL";
|
||||
|
||||
/// <summary>
|
||||
/// Micro Singapore FOB Marine Fuel 0.5% (Platts) Futures
|
||||
/// </summary>
|
||||
/// <returns>The symbol</returns>
|
||||
public const string MicroSingaporeFOBMarineFuelZeroPointFivePercetPlatts = "S5O";
|
||||
|
||||
/// <summary>
|
||||
/// Micro Gasoil 0.1% Barges FOB ARA (Platts) Futures
|
||||
/// </summary>
|
||||
/// <returns>The symbol</returns>
|
||||
public const string MicroGasoilZeroPointOnePercentBargesFOBARAPlatts = "M1B";
|
||||
|
||||
/// <summary>
|
||||
/// Micro European FOB Rdam Marine Fuel 0.5% Barges (Platts) Futures
|
||||
/// </summary>
|
||||
/// <returns>The symbol</returns>
|
||||
public const string MicroEuropeanFOBRdamMarineFuelZeroPointFivePercentBargesPlatts = "R5O";
|
||||
|
||||
/// <summary>
|
||||
/// Micro European 3.5% Fuel Oil Barges FOB Rdam (Platts) Futures
|
||||
/// </summary>
|
||||
/// <returns>The symbol</returns>
|
||||
public const string MicroEuropeanThreePointFivePercentOilBargesFOBRdamPlatts = "MEF";
|
||||
|
||||
/// <summary>
|
||||
/// Micro Singapore Fuel Oil 380CST (Platts) Futures
|
||||
/// </summary>
|
||||
/// <returns>The symbol</returns>
|
||||
public const string MicroSingaporeFuelOil380CSTPlatts = "MAF";
|
||||
|
||||
/// <summary>
|
||||
/// Micro Coal (API 5) fob Newcastle (Argus/McCloskey) Futures
|
||||
/// </summary>
|
||||
/// <returns>The symbol</returns>
|
||||
public const string MicroCoalAPIFivefobNewcastleArgusMcCloskey = "M5F";
|
||||
|
||||
/// <summary>
|
||||
/// Micro European 3.5% Fuel Oil Cargoes FOB Med (Platts) Futures
|
||||
/// </summary>
|
||||
/// <returns>The symbol</returns>
|
||||
public const string MicroEuropeanThreePointFivePercentFuelOilCargoesFOBMedPlatts = "M35";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -712,6 +850,30 @@ namespace QuantConnect.Securities
|
||||
/// Ultra 10-Year U.S. Treasury Note Futures
|
||||
/// </summary>
|
||||
public const string UltraTenYearUSTreasuryNote = "TN";
|
||||
|
||||
/// <summary>
|
||||
/// Micro 10-Year Yield Futures
|
||||
/// </summary>
|
||||
/// <returns>The symbol</returns>
|
||||
public const string MicroY10TreasuryNote = "10Y";
|
||||
|
||||
/// <summary>
|
||||
/// Micro 30-Year Yield Futures
|
||||
/// </summary>
|
||||
/// <returns>The symbol</returns>
|
||||
public const string MicroY30TreasuryBond = "30Y";
|
||||
|
||||
/// <summary>
|
||||
/// Micro 2-Year Yield Futures
|
||||
/// </summary>
|
||||
/// <returns>The symbol</returns>
|
||||
public const string MicroY2TreasuryBond = "2YY";
|
||||
|
||||
/// <summary>
|
||||
/// Micro 5-Year Yield Futures
|
||||
/// </summary>
|
||||
/// <returns>The symbol</returns>
|
||||
public const string MicroY5TreasuryBond = "5YY";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -824,7 +986,32 @@ namespace QuantConnect.Securities
|
||||
/// <summary>
|
||||
/// Hang Seng Index
|
||||
/// </summary>
|
||||
/// <returns>The symbol</returns>
|
||||
public const string HangSeng = "HSI";
|
||||
|
||||
/// <summary>
|
||||
/// Micro E-mini S&P 500 Index Futures
|
||||
/// </summary>
|
||||
/// <returns>The symbol</returns>
|
||||
public const string MicroSP500EMini = "MES";
|
||||
|
||||
/// <summary>
|
||||
/// Micro E-mini Nasdaq-100 Index Futures
|
||||
/// </summary>
|
||||
/// <returns>The symbol</returns>
|
||||
public const string MicroNASDAQ100EMini = "MNQ";
|
||||
|
||||
/// <summary>
|
||||
/// Micro E-mini Russell 2000 Index Futures
|
||||
/// </summary>
|
||||
/// <returns>The symbol</returns>
|
||||
public const string MicroRussell2000EMini = "M2K";
|
||||
|
||||
/// <summary>
|
||||
/// Micro E-mini Dow Jones Industrial Average Index Futures
|
||||
/// </summary>
|
||||
/// <returns>The symbol</returns>
|
||||
public const string MicroDow30EMini = "MYM";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -915,6 +1102,30 @@ namespace QuantConnect.Securities
|
||||
/// </summary>
|
||||
/// <returns>The symbol</returns>
|
||||
public const string USMidwestDomesticHotRolledCoilSteelCRUIndex = "HRC";
|
||||
|
||||
/// <summary>
|
||||
/// Micro Gold Futures
|
||||
/// </summary>
|
||||
/// <returns>The symbol</returns>
|
||||
public const string MicroGold = "MGC";
|
||||
|
||||
/// <summary>
|
||||
/// Micro Silver Futures
|
||||
/// </summary>
|
||||
/// <returns>The symbol</returns>
|
||||
public const string MicroSilver = "SIL";
|
||||
|
||||
/// <summary>
|
||||
/// Micro Gold TAS Futures
|
||||
/// </summary>
|
||||
/// <returns>The symbol</returns>
|
||||
public const string MicroGoldTAS = "MGT";
|
||||
|
||||
/// <summary>
|
||||
/// Micro Palladium Futures
|
||||
/// </summary>
|
||||
/// <returns>The symbol</returns>
|
||||
public const string MicroPalladium = "PAM";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1001,4 +1212,4 @@ namespace QuantConnect.Securities
|
||||
public const string NonfatDryMilk = "GNF";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1073,12 +1073,10 @@ namespace QuantConnect.Securities.Future
|
||||
{
|
||||
// Monthly contracts listed for 6 consecutive months and 2 additional Dec contract months. If the 6 consecutive months includes Dec, list only 1 additional Dec contract month.
|
||||
// Trading terminates at 4:00 p.m. London time on the last Friday of the contract month. If that day is not a business day in both the U.K. and the US, trading terminates on the preceding day that is a business day for both the U.K. and the U.S..
|
||||
var lastFriday = (from day in Enumerable.Range(1, DateTime.DaysInMonth(time.Year, time.Month))
|
||||
where new DateTime(time.Year, time.Month, day).DayOfWeek == DayOfWeek.Friday
|
||||
select new DateTime(time.Year, time.Month, day)).Last();
|
||||
var lastFriday =FuturesExpiryUtilityFunctions.LastFriday(time);
|
||||
|
||||
var holidays = MarketHoursDatabase.FromDataFolder()
|
||||
.GetEntry(Market.CME, Futures.Currencies.AUDNZD, SecurityType.Future)
|
||||
.GetEntry(Market.CME, Futures.Currencies.BTC, SecurityType.Future)
|
||||
.ExchangeHours
|
||||
.Holidays;
|
||||
|
||||
@@ -1940,8 +1938,8 @@ namespace QuantConnect.Securities.Future
|
||||
}
|
||||
else
|
||||
{
|
||||
var lastBuisnessDay = FuturesExpiryUtilityFunctions.AddBusinessDays(twentyFifth,-1);
|
||||
return FuturesExpiryUtilityFunctions.AddBusinessDays(lastBuisnessDay,-3);
|
||||
var lastBusinessDay = FuturesExpiryUtilityFunctions.AddBusinessDays(twentyFifth,-1);
|
||||
return FuturesExpiryUtilityFunctions.AddBusinessDays(lastBusinessDay,-3);
|
||||
}
|
||||
})
|
||||
},
|
||||
@@ -2606,6 +2604,762 @@ namespace QuantConnect.Securities.Future
|
||||
return FuturesExpiryUtilityFunctions.DairyLastTradeDate(time);
|
||||
})
|
||||
},
|
||||
// Micro Gold Futures (MGC): https://www.cmegroup.com/markets/metals/precious/e-micro-gold.contractSpecs.html
|
||||
{Symbol.Create(Futures.Metals.MicroGold, SecurityType.Future, Market.COMEX), (time =>
|
||||
{
|
||||
// Monthly contracts
|
||||
// Trading terminates on the third last business day of the contract month.
|
||||
var lastBusinessDay = FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 3);
|
||||
var holidays = MarketHoursDatabase.FromDataFolder()
|
||||
.GetEntry(Market.COMEX, Futures.Metals.MicroGold, SecurityType.Future)
|
||||
.ExchangeHours
|
||||
.Holidays;
|
||||
|
||||
while (holidays.Contains(lastBusinessDay))
|
||||
{
|
||||
lastBusinessDay = FuturesExpiryUtilityFunctions.AddBusinessDays(lastBusinessDay, -1);
|
||||
}
|
||||
|
||||
return lastBusinessDay;
|
||||
})
|
||||
},
|
||||
// Micro Silver Futures (SIL): https://www.cmegroup.com/markets/metals/precious/1000-oz-silver.contractSpecs.html
|
||||
{Symbol.Create(Futures.Metals.MicroSilver, SecurityType.Future, Market.COMEX), (time =>
|
||||
{
|
||||
// Monthly contracts
|
||||
// Trading terminates on the third last business day of the contract month.
|
||||
var lastBusinessDay = FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 3);
|
||||
var holidays = MarketHoursDatabase.FromDataFolder()
|
||||
.GetEntry(Market.COMEX, Futures.Metals.MicroSilver, SecurityType.Future)
|
||||
.ExchangeHours
|
||||
.Holidays;
|
||||
|
||||
while (holidays.Contains(lastBusinessDay))
|
||||
{
|
||||
lastBusinessDay = FuturesExpiryUtilityFunctions.AddBusinessDays(lastBusinessDay, -1);
|
||||
}
|
||||
|
||||
return lastBusinessDay;
|
||||
})
|
||||
},
|
||||
// Micro Gold TAS Futures (MGT): https://www.cmegroup.com/markets/metals/precious/e-micro-gold.contractSpecs.html
|
||||
{Symbol.Create(Futures.Metals.MicroGoldTAS, SecurityType.Future, Market.COMEX), (time =>
|
||||
{
|
||||
// Monthly contracts
|
||||
// Trading terminates on the third last business day of the contract month.
|
||||
var lastBusinessDay = FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 3);
|
||||
var holidays = MarketHoursDatabase.FromDataFolder()
|
||||
.GetEntry(Market.COMEX, Futures.Metals.MicroGoldTAS, SecurityType.Future)
|
||||
.ExchangeHours
|
||||
.Holidays;
|
||||
|
||||
while (holidays.Contains(lastBusinessDay))
|
||||
{
|
||||
lastBusinessDay = FuturesExpiryUtilityFunctions.AddBusinessDays(lastBusinessDay, -1);
|
||||
}
|
||||
|
||||
return lastBusinessDay;
|
||||
})
|
||||
},
|
||||
// Micro Palladium Futures (PAM): https://www.cmegroup.com/markets/metals/precious/e-micro-palladium.contractSpecs.html
|
||||
{Symbol.Create(Futures.Metals.MicroPalladium, SecurityType.Future, Market.NYMEX), (time =>
|
||||
{
|
||||
// Monthly contracts
|
||||
// Trading terminates on the third last business day of the contract month.
|
||||
var lastBusinessDay = FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 3);
|
||||
var holidays = MarketHoursDatabase.FromDataFolder()
|
||||
.GetEntry(Market.NYMEX, Futures.Metals.MicroPalladium, SecurityType.Future)
|
||||
.ExchangeHours
|
||||
.Holidays;
|
||||
|
||||
while (holidays.Contains(lastBusinessDay))
|
||||
{
|
||||
lastBusinessDay = FuturesExpiryUtilityFunctions.AddBusinessDays(lastBusinessDay, -1);
|
||||
}
|
||||
|
||||
return lastBusinessDay;
|
||||
})
|
||||
},
|
||||
// Micro 10-Year Yield Futures (10Y): https://www.cmegroup.com/markets/interest-rates/us-treasury/micro-10-year-yield.contractSpecs.html
|
||||
{Symbol.Create(Futures.Financials.MicroY10TreasuryNote, SecurityType.Future, Market.CBOT), (time =>
|
||||
{
|
||||
// Monthly contracts
|
||||
// Trading terminates on the last business day of the contract month.
|
||||
var lastBusinessDay = FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1);
|
||||
var holidays = MarketHoursDatabase.FromDataFolder()
|
||||
.GetEntry(Market.CBOT, Futures.Financials.MicroY10TreasuryNote, SecurityType.Future)
|
||||
.ExchangeHours
|
||||
.Holidays;
|
||||
|
||||
while (holidays.Contains(lastBusinessDay))
|
||||
{
|
||||
lastBusinessDay = FuturesExpiryUtilityFunctions.AddBusinessDays(lastBusinessDay, -1);
|
||||
}
|
||||
|
||||
return lastBusinessDay;
|
||||
})
|
||||
},
|
||||
// Micro 30-Year Yield Futures (30Y): https://www.cmegroup.com/markets/interest-rates/us-treasury/micro-30-year-yield_contract_specifications.html
|
||||
{Symbol.Create(Futures.Financials.MicroY30TreasuryBond, SecurityType.Future, Market.CBOT), (time =>
|
||||
{
|
||||
// Monthly contracts
|
||||
// Trading terminates on the last business day of the contract month.
|
||||
var lastBusinessDay = FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1);
|
||||
var holidays = MarketHoursDatabase.FromDataFolder()
|
||||
.GetEntry(Market.CBOT, Futures.Financials.MicroY30TreasuryBond, SecurityType.Future)
|
||||
.ExchangeHours
|
||||
.Holidays;
|
||||
|
||||
while (holidays.Contains(lastBusinessDay))
|
||||
{
|
||||
lastBusinessDay = FuturesExpiryUtilityFunctions.AddBusinessDays(lastBusinessDay, -1);
|
||||
}
|
||||
|
||||
return lastBusinessDay;
|
||||
})
|
||||
},
|
||||
// Micro 2-Year Yield Futures (2YY): https://www.cmegroup.com/markets/interest-rates/us-treasury/micro-2-year-yield.contractSpecs.html
|
||||
{Symbol.Create(Futures.Financials.MicroY2TreasuryBond, SecurityType.Future, Market.CBOT), (time =>
|
||||
{
|
||||
// Monthly contracts
|
||||
// Trading terminates on the last business day of the contract month.
|
||||
var lastBusinessDay = FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1);
|
||||
var holidays = MarketHoursDatabase.FromDataFolder()
|
||||
.GetEntry(Market.CBOT, Futures.Financials.MicroY2TreasuryBond, SecurityType.Future)
|
||||
.ExchangeHours
|
||||
.Holidays;
|
||||
|
||||
while (holidays.Contains(lastBusinessDay))
|
||||
{
|
||||
lastBusinessDay = FuturesExpiryUtilityFunctions.AddBusinessDays(lastBusinessDay, -1);
|
||||
}
|
||||
|
||||
return lastBusinessDay;
|
||||
})
|
||||
},
|
||||
// Micro 5-Year Yield Futures (5YY): https://www.cmegroup.com/markets/interest-rates/us-treasury/micro-5-year-yield.contractSpecs.html
|
||||
{Symbol.Create(Futures.Financials.MicroY5TreasuryBond, SecurityType.Future, Market.CBOT), (time =>
|
||||
{
|
||||
// Monthly contracts
|
||||
// Trading terminates on the last business day of the contract month.
|
||||
var lastBusinessDay = FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1);
|
||||
var holidays = MarketHoursDatabase.FromDataFolder()
|
||||
.GetEntry(Market.CBOT, Futures.Financials.MicroY5TreasuryBond, SecurityType.Future)
|
||||
.ExchangeHours
|
||||
.Holidays;
|
||||
|
||||
while (holidays.Contains(lastBusinessDay))
|
||||
{
|
||||
lastBusinessDay = FuturesExpiryUtilityFunctions.AddBusinessDays(lastBusinessDay, -1);
|
||||
}
|
||||
|
||||
return lastBusinessDay;
|
||||
})
|
||||
},
|
||||
// Micro EUR/USD Futures (M6E): https://www.cmegroup.com/markets/fx/g10/e-micro-euro.contractSpecs.html
|
||||
{Symbol.Create(Futures.Currencies.MicroEUR, SecurityType.Future, Market.CME), (time =>
|
||||
{
|
||||
// Quarterly contracts (Mar, Jun, Sep, Dec) listed for 2 consecutive quarters
|
||||
while (!FutureExpirationCycles.HMUZ.Contains(time.Month))
|
||||
{
|
||||
time = time.AddMonths(1);
|
||||
}
|
||||
|
||||
// Trading terminates at 9:16 a.m. CT 2 business day prior to the 3rd Wednesday of the contract quqrter.
|
||||
var thirdWednesday = FuturesExpiryUtilityFunctions.ThirdWednesday(time);
|
||||
var secondBusinessDayPrecedingThirdWednesday = FuturesExpiryUtilityFunctions.AddBusinessDays(thirdWednesday, -2);
|
||||
var holidays = MarketHoursDatabase.FromDataFolder()
|
||||
.GetEntry(Market.CME, Futures.Currencies.MicroEUR, SecurityType.Future)
|
||||
.ExchangeHours
|
||||
.Holidays;
|
||||
|
||||
while (holidays.Contains(secondBusinessDayPrecedingThirdWednesday))
|
||||
{
|
||||
secondBusinessDayPrecedingThirdWednesday = FuturesExpiryUtilityFunctions.AddBusinessDays(secondBusinessDayPrecedingThirdWednesday, -1);
|
||||
}
|
||||
|
||||
return secondBusinessDayPrecedingThirdWednesday.Add(new TimeSpan(14, 16, 0));
|
||||
})
|
||||
},
|
||||
// Micro AUD/USD Futures (M6A): https://www.cmegroup.com/markets/fx/g10/e-micro-australian-dollar.contractSpecs.html
|
||||
{Symbol.Create(Futures.Currencies.MicroAUD, SecurityType.Future, Market.CME), (time =>
|
||||
{
|
||||
// Quarterly contracts (Mar, Jun, Sep, Dec) listed for 2 consecutive quarters
|
||||
while (!FutureExpirationCycles.HMUZ.Contains(time.Month))
|
||||
{
|
||||
time = time.AddMonths(1);
|
||||
}
|
||||
|
||||
// On the second business day immediately preceding the third Wednesday of the contract month (usually Monday).
|
||||
var thirdWednesday = FuturesExpiryUtilityFunctions.ThirdWednesday(time);
|
||||
var secondBusinessDayPrecedingThirdWednesday = FuturesExpiryUtilityFunctions.AddBusinessDays(thirdWednesday, -2);
|
||||
var holidays = MarketHoursDatabase.FromDataFolder()
|
||||
.GetEntry(Market.CME, Futures.Currencies.MicroAUD, SecurityType.Future)
|
||||
.ExchangeHours
|
||||
.Holidays;
|
||||
|
||||
while (holidays.Contains(secondBusinessDayPrecedingThirdWednesday))
|
||||
{
|
||||
secondBusinessDayPrecedingThirdWednesday = FuturesExpiryUtilityFunctions.AddBusinessDays(secondBusinessDayPrecedingThirdWednesday, -1);
|
||||
}
|
||||
|
||||
return secondBusinessDayPrecedingThirdWednesday;
|
||||
})
|
||||
},
|
||||
// Micro GBP/USD Futures (M6B): https://www.cmegroup.com/markets/fx/g10/e-micro-british-pound.contractSpecs.html
|
||||
{Symbol.Create(Futures.Currencies.MicroGBP, SecurityType.Future, Market.CME), (time =>
|
||||
{
|
||||
// Quarterly contracts (Mar, Jun, Sep, Dec) listed for 2 consecutive quarters
|
||||
while (!FutureExpirationCycles.HMUZ.Contains(time.Month))
|
||||
{
|
||||
time = time.AddMonths(1);
|
||||
}
|
||||
|
||||
// 9:16 a.m. Central Time (CT) on the second business day immediately preceding the third Wednesday of the contract month (usually Monday).
|
||||
var thirdWednesday = FuturesExpiryUtilityFunctions.ThirdWednesday(time);
|
||||
var secondBusinessDayPrecedingThirdWednesday = FuturesExpiryUtilityFunctions.AddBusinessDays(thirdWednesday, -2);
|
||||
var holidays = MarketHoursDatabase.FromDataFolder()
|
||||
.GetEntry(Market.CME, Futures.Currencies.MicroGBP, SecurityType.Future)
|
||||
.ExchangeHours
|
||||
.Holidays;
|
||||
|
||||
while (holidays.Contains(secondBusinessDayPrecedingThirdWednesday))
|
||||
{
|
||||
secondBusinessDayPrecedingThirdWednesday = FuturesExpiryUtilityFunctions.AddBusinessDays(secondBusinessDayPrecedingThirdWednesday, -1);
|
||||
}
|
||||
|
||||
return secondBusinessDayPrecedingThirdWednesday.Add(new TimeSpan(14, 16, 0));
|
||||
})
|
||||
},
|
||||
// Micro CAD/USD Futures (MCD): https://www.cmegroup.com/markets/fx/g10/e-micro-canadian-dollar-us-dollar.contractSpecs.html
|
||||
{Symbol.Create(Futures.Currencies.MicroCADUSD, SecurityType.Future, Market.CME), (time =>
|
||||
{
|
||||
// Quarterly contracts (Mar, Jun, Sep, Dec) listed for 2 consecutive quarters
|
||||
while (!FutureExpirationCycles.HMUZ.Contains(time.Month))
|
||||
{
|
||||
time = time.AddMonths(1);
|
||||
}
|
||||
|
||||
// Trading terminates 1 business day prior to the 3rd Wednesday of the contract quarter.
|
||||
var thirdWednesday = FuturesExpiryUtilityFunctions.ThirdWednesday(time);
|
||||
var firstBusinessDayPrecedingThirdWednesday = FuturesExpiryUtilityFunctions.AddBusinessDays(thirdWednesday, -1);
|
||||
var holidays = MarketHoursDatabase.FromDataFolder()
|
||||
.GetEntry(Market.CME, Futures.Currencies.MicroCADUSD, SecurityType.Future)
|
||||
.ExchangeHours
|
||||
.Holidays;
|
||||
|
||||
while (holidays.Contains(firstBusinessDayPrecedingThirdWednesday))
|
||||
{
|
||||
firstBusinessDayPrecedingThirdWednesday = FuturesExpiryUtilityFunctions.AddBusinessDays(firstBusinessDayPrecedingThirdWednesday, -1);
|
||||
}
|
||||
|
||||
return firstBusinessDayPrecedingThirdWednesday;
|
||||
})
|
||||
},
|
||||
// Micro JPY/USD Futures (MJY): https://www.cmegroup.com/markets/fx/g10/e-micro-japanese-yen-us-dollar.contractSpecs.html
|
||||
{Symbol.Create(Futures.Currencies.MicroJPY, SecurityType.Future, Market.CME), (time =>
|
||||
{
|
||||
// Quarterly contracts (Mar, Jun, Sep, Dec) listed for 2 consecutive quarters
|
||||
while (!FutureExpirationCycles.HMUZ.Contains(time.Month))
|
||||
{
|
||||
time = time.AddMonths(1);
|
||||
}
|
||||
|
||||
// 9:16 a.m. Central Time (CT) on the second business day immediately preceding the third Wednesday of the contract month (usually Monday).
|
||||
var thirdWednesday = FuturesExpiryUtilityFunctions.ThirdWednesday(time);
|
||||
var secondBusinessDayPrecedingThirdWednesday = FuturesExpiryUtilityFunctions.AddBusinessDays(thirdWednesday, -2);
|
||||
var holidays = MarketHoursDatabase.FromDataFolder()
|
||||
.GetEntry(Market.CME, Futures.Currencies.MicroJPY, SecurityType.Future)
|
||||
.ExchangeHours
|
||||
.Holidays;
|
||||
|
||||
while (holidays.Contains(secondBusinessDayPrecedingThirdWednesday))
|
||||
{
|
||||
secondBusinessDayPrecedingThirdWednesday = FuturesExpiryUtilityFunctions.AddBusinessDays(secondBusinessDayPrecedingThirdWednesday, -1);
|
||||
}
|
||||
|
||||
return secondBusinessDayPrecedingThirdWednesday.Add(new TimeSpan(14, 16, 0));
|
||||
})
|
||||
},
|
||||
// Micro CHF/USD Futures (MSF): https://www.cmegroup.com/markets/fx/g10/e-micro-swiss-franc-us-dollar.contractSpecs.html
|
||||
{Symbol.Create(Futures.Currencies.MicroCHF, SecurityType.Future, Market.CME), (time =>
|
||||
{
|
||||
// Quarterly contracts (Mar, Jun, Sep, Dec) listed for 2 consecutive quarters
|
||||
while (!FutureExpirationCycles.HMUZ.Contains(time.Month))
|
||||
{
|
||||
time = time.AddMonths(1);
|
||||
}
|
||||
|
||||
// 9:16 a.m. Central Time (CT) on the second business day immediately preceding the third Wednesday of the contract month (usually Monday).
|
||||
var thirdWednesday = FuturesExpiryUtilityFunctions.ThirdWednesday(time);
|
||||
var secondBusinessDayPrecedingThirdWednesday = FuturesExpiryUtilityFunctions.AddBusinessDays(thirdWednesday, -2);
|
||||
var holidays = MarketHoursDatabase.FromDataFolder()
|
||||
.GetEntry(Market.CME, Futures.Currencies.MicroCHF, SecurityType.Future)
|
||||
.ExchangeHours
|
||||
.Holidays;
|
||||
|
||||
while (holidays.Contains(secondBusinessDayPrecedingThirdWednesday))
|
||||
{
|
||||
secondBusinessDayPrecedingThirdWednesday = FuturesExpiryUtilityFunctions.AddBusinessDays(secondBusinessDayPrecedingThirdWednesday, -1);
|
||||
}
|
||||
|
||||
return secondBusinessDayPrecedingThirdWednesday.Add(new TimeSpan(14, 16, 0));
|
||||
})
|
||||
},
|
||||
// Micro USD/JPY Futures (M6J): https://www.cmegroup.com/markets/fx/g10/micro-usd-jpy.contractSpecs.html
|
||||
{Symbol.Create(Futures.Currencies.MicroUSDJPY, SecurityType.Future, Market.CME), (time =>
|
||||
{
|
||||
// Quarterly contracts (Mar, Jun, Sep, Dec) listed for 2 consecutive quarters
|
||||
while (!FutureExpirationCycles.HMUZ.Contains(time.Month))
|
||||
{
|
||||
time = time.AddMonths(1);
|
||||
}
|
||||
|
||||
// 9:16 a.m. Central Time (CT) on the second business day immediately preceding the third Wednesday of the contract month (usually Monday).
|
||||
var thirdWednesday = FuturesExpiryUtilityFunctions.ThirdWednesday(time);
|
||||
var secondBusinessDayPrecedingThirdWednesday = FuturesExpiryUtilityFunctions.AddBusinessDays(thirdWednesday, -2);
|
||||
var holidays = MarketHoursDatabase.FromDataFolder()
|
||||
.GetEntry(Market.CME, Futures.Currencies.MicroUSDJPY, SecurityType.Future)
|
||||
.ExchangeHours
|
||||
.Holidays;
|
||||
|
||||
while (holidays.Contains(secondBusinessDayPrecedingThirdWednesday))
|
||||
{
|
||||
secondBusinessDayPrecedingThirdWednesday = FuturesExpiryUtilityFunctions.AddBusinessDays(secondBusinessDayPrecedingThirdWednesday, -1);
|
||||
}
|
||||
|
||||
return secondBusinessDayPrecedingThirdWednesday.Add(new TimeSpan(14, 16, 0));
|
||||
})
|
||||
},
|
||||
// Micro INR/USD Futures (MIR): https://www.cmegroup.com/markets/fx/g10/e-micro-indian-rupee.contractSpecs.html
|
||||
{Symbol.Create(Futures.Currencies.MicroINRUSD, SecurityType.Future, Market.CME), (time =>
|
||||
{
|
||||
// Monthly contracts listed for 12 consecutive months.
|
||||
|
||||
// Trading terminates at 12:00 noon Mumbai time two Indian business days immediately preceding the last Indian
|
||||
// business day of the contract month.
|
||||
|
||||
var lastBusinessDay = FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1);
|
||||
var holidays = MarketHoursDatabase.FromDataFolder()
|
||||
.GetEntry(Market.CME, Futures.Currencies.MicroINRUSD, SecurityType.Future)
|
||||
.ExchangeHours
|
||||
.Holidays;
|
||||
|
||||
while (holidays.Contains(lastBusinessDay))
|
||||
{
|
||||
lastBusinessDay = FuturesExpiryUtilityFunctions.AddBusinessDays(lastBusinessDay, -1);
|
||||
}
|
||||
|
||||
var secondBusinessDayPrecedingLastBusinessDay = FuturesExpiryUtilityFunctions.AddBusinessDays(lastBusinessDay,-2);
|
||||
return secondBusinessDayPrecedingLastBusinessDay.Add(new TimeSpan(6,30,0));
|
||||
})
|
||||
},
|
||||
// Micro USD/CAD Futures (M6C): https://www.cmegroup.com/markets/fx/g10/micro-usd-cad.contractSpecs.html
|
||||
{Symbol.Create(Futures.Currencies.MicroCAD, SecurityType.Future, Market.CME), (time =>
|
||||
{
|
||||
// Two months in the March quarterly cycle (Mar, Jun, Sep, Dec)
|
||||
while (!FutureExpirationCycles.HMUZ.Contains(time.Month))
|
||||
{
|
||||
time = time.AddMonths(1);
|
||||
}
|
||||
|
||||
// Trading terminates at 9:16 a.m. CT, 1 business day prior to the third Wednesday of the contract month.
|
||||
var thirdWednesday = FuturesExpiryUtilityFunctions.ThirdWednesday(time);
|
||||
var firstBusinessDayPrecedingThirdWednesday = FuturesExpiryUtilityFunctions.AddBusinessDays(thirdWednesday, -1);
|
||||
var holidays = MarketHoursDatabase.FromDataFolder()
|
||||
.GetEntry(Market.CME, Futures.Currencies.MicroCAD, SecurityType.Future)
|
||||
.ExchangeHours
|
||||
.Holidays;
|
||||
|
||||
while (holidays.Contains(firstBusinessDayPrecedingThirdWednesday))
|
||||
{
|
||||
firstBusinessDayPrecedingThirdWednesday = FuturesExpiryUtilityFunctions.AddBusinessDays(firstBusinessDayPrecedingThirdWednesday, -1);
|
||||
}
|
||||
|
||||
return firstBusinessDayPrecedingThirdWednesday.Add(new TimeSpan(14, 16, 0));
|
||||
})
|
||||
},
|
||||
// Micro USD/CHF Futures (M6S): https://www.cmegroup.com/markets/fx/g10/micro-usd-chf.contractSpecs.html
|
||||
{Symbol.Create(Futures.Currencies.MicroUSDCHF, SecurityType.Future, Market.CME), (time =>
|
||||
{
|
||||
// Two months in the March quarterly cycle (Mar, Jun, Sep, Dec)
|
||||
while (!FutureExpirationCycles.HMUZ.Contains(time.Month))
|
||||
{
|
||||
time = time.AddMonths(1);
|
||||
}
|
||||
|
||||
// Trading terminates at 9:16 a.m. CT, 2 business days prior to the third Wednesday of the contract month.
|
||||
var thirdWednesday = FuturesExpiryUtilityFunctions.ThirdWednesday(time);
|
||||
var secondBusinessDayPrecedingThirdWednesday = FuturesExpiryUtilityFunctions.AddBusinessDays(thirdWednesday, -2);
|
||||
var holidays = MarketHoursDatabase.FromDataFolder()
|
||||
.GetEntry(Market.CME, Futures.Currencies.MicroUSDCHF, SecurityType.Future)
|
||||
.ExchangeHours
|
||||
.Holidays;
|
||||
|
||||
while (holidays.Contains(secondBusinessDayPrecedingThirdWednesday))
|
||||
{
|
||||
secondBusinessDayPrecedingThirdWednesday = FuturesExpiryUtilityFunctions.AddBusinessDays(secondBusinessDayPrecedingThirdWednesday, -1);
|
||||
}
|
||||
|
||||
return secondBusinessDayPrecedingThirdWednesday.Add(new TimeSpan(14, 16, 0));
|
||||
})
|
||||
},
|
||||
// Micro USD/CNH Futures (MNH): https://www.cmegroup.com/markets/fx/g10/e-micro-cnh.contractSpecs.html
|
||||
{Symbol.Create(Futures.Currencies.MicroUSDCNH, SecurityType.Future, Market.CME), (time =>
|
||||
{
|
||||
// Monthly contracts listed for 12 consecutive months.
|
||||
|
||||
// Trading terminates at 11:00 a.m. Hong Kong time on the second Hong Kong business day prior
|
||||
// to the third Wednesday of the contract month.
|
||||
|
||||
var thirdWednesday = FuturesExpiryUtilityFunctions.ThirdWednesday(time);
|
||||
var secondBusinessDayPrecedingThirdWednesday = FuturesExpiryUtilityFunctions.AddBusinessDays(thirdWednesday,-2);
|
||||
return secondBusinessDayPrecedingThirdWednesday.Add(new TimeSpan(3,0,0));
|
||||
})
|
||||
},
|
||||
// Micro E-mini S&P 500 Index Futures (MES): https://www.cmegroup.com/markets/equities/sp/micro-e-mini-sandp-500.contractSpecs.html
|
||||
{Symbol.Create(Futures.Indices.MicroSP500EMini, SecurityType.Future, Market.CME), (time =>
|
||||
{
|
||||
// Quarterly contracts (Mar, Jun, Sep, Dec) listed for 5 consecutive quarters
|
||||
while (!FutureExpirationCycles.HMUZ.Contains(time.Month))
|
||||
{
|
||||
time = time.AddMonths(1);
|
||||
}
|
||||
|
||||
// Trading terminates at 9:30 a.m. ET on the 3rd Friday of the contract month.
|
||||
var thirdFriday = FuturesExpiryUtilityFunctions.ThirdFriday(time);
|
||||
return thirdFriday.Add(new TimeSpan(13,30,0));
|
||||
})
|
||||
},
|
||||
// Micro E-mini Nasdaq-100 Index Futures (MNQ): https://www.cmegroup.com/markets/equities/nasdaq/micro-e-mini-nasdaq-100.contractSpecs.html
|
||||
{Symbol.Create(Futures.Indices.MicroNASDAQ100EMini, SecurityType.Future, Market.CME), (time =>
|
||||
{
|
||||
// Quarterly contracts (Mar, Jun, Sep, Dec) listed for 5 consecutive quarters
|
||||
while (!FutureExpirationCycles.HMUZ.Contains(time.Month))
|
||||
{
|
||||
time = time.AddMonths(1);
|
||||
}
|
||||
|
||||
// Trading terminates at 9:30 a.m. ET on the 3rd Friday of the contract month.
|
||||
var thirdFriday = FuturesExpiryUtilityFunctions.ThirdFriday(time);
|
||||
return thirdFriday.Add(new TimeSpan(13,30,0));
|
||||
})
|
||||
},
|
||||
// Micro E-mini Russell 2000 Index Futures (M2K): https://www.cmegroup.com/markets/equities/russell/micro-e-mini-russell-2000.contractSpecs.html
|
||||
{Symbol.Create(Futures.Indices.MicroRussell2000EMini, SecurityType.Future, Market.CME), (time =>
|
||||
{
|
||||
// Quarterly contracts (Mar, Jun, Sep, Dec) listed for 5 consecutive quarters
|
||||
while (!FutureExpirationCycles.HMUZ.Contains(time.Month))
|
||||
{
|
||||
time = time.AddMonths(1);
|
||||
}
|
||||
|
||||
// Trading terminates at 9:30 a.m. ET on the 3rd Friday of the contract month.
|
||||
var thirdFriday = FuturesExpiryUtilityFunctions.ThirdFriday(time);
|
||||
return thirdFriday.Add(new TimeSpan(13,30,0));
|
||||
})
|
||||
},
|
||||
// Micro E-mini Dow Jones Industrial Average Index Futures (MYM): https://www.cmegroup.com/markets/equities/dow-jones/micro-e-mini-dow.contractSpecs.html
|
||||
{Symbol.Create(Futures.Indices.MicroDow30EMini, SecurityType.Future, Market.CBOT), (time =>
|
||||
{
|
||||
// Quarterly contracts (Mar, Jun, Sep, Dec) listed for 4 consecutive quarters
|
||||
while (!FutureExpirationCycles.HMUZ.Contains(time.Month))
|
||||
{
|
||||
time = time.AddMonths(1);
|
||||
}
|
||||
|
||||
// Trading can occur up to 9:30 a.m. Eastern Time (ET) on the 3rd Friday of the contract month
|
||||
var thirdFriday = FuturesExpiryUtilityFunctions.ThirdFriday(time);
|
||||
return thirdFriday.Add(new TimeSpan(13,30,0));
|
||||
})
|
||||
},
|
||||
// Micro WTI Crude Oil Futures (MCL): https://www.cmegroup.com/markets/energy/crude-oil/micro-wti-crude-oil.contractSpecs.html
|
||||
{Symbol.Create(Futures.Energies.MicroCrudeOilWTI, SecurityType.Future, Market.NYMEX), (time =>
|
||||
{
|
||||
// Monthly contracts listed for 12 consecutive months and additional Jun and Dec contract months
|
||||
|
||||
// Trading terminates 4 business days prior to the 25th calendar day of the month prior to the
|
||||
// contract month (1 business day prior to CL LTD)
|
||||
|
||||
var previousMonth = time.AddMonths(-1);
|
||||
var twentyFifthDay = new DateTime(previousMonth.Year, previousMonth.Month, 25);
|
||||
var twentyFifthDayLessFour = FuturesExpiryUtilityFunctions.AddBusinessDays(twentyFifthDay, -4);
|
||||
return twentyFifthDayLessFour;
|
||||
})
|
||||
},
|
||||
// Micro Singapore FOB Marine Fuel 0.5% (Platts) Futures (S50): https://www.cmegroup.com/markets/energy/refined-products/micro-singapore-fob-marine-fuel-05-platts.contractSpecs.html
|
||||
{Symbol.Create(Futures.Energies.MicroSingaporeFOBMarineFuelZeroPointFivePercetPlatts, SecurityType.Future, Market.NYMEX), (time =>
|
||||
{
|
||||
// Monthly contracts listed for the current year and next 3 calendar years
|
||||
// Add monthly contracts for a new calendar year following the termination of trading in the
|
||||
// December contract of the current year.
|
||||
|
||||
// Trading terminates on the last business day of the contract month.
|
||||
var lastBusinessDay = FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1);
|
||||
var holidays = MarketHoursDatabase.FromDataFolder()
|
||||
.GetEntry(Market.NYMEX, Futures.Energies.MicroSingaporeFOBMarineFuelZeroPointFivePercetPlatts, SecurityType.Future)
|
||||
.ExchangeHours
|
||||
.Holidays;
|
||||
|
||||
while (holidays.Contains(lastBusinessDay))
|
||||
{
|
||||
lastBusinessDay = FuturesExpiryUtilityFunctions.AddBusinessDays(lastBusinessDay, -1);
|
||||
}
|
||||
|
||||
return lastBusinessDay;
|
||||
})
|
||||
},
|
||||
// Micro Gasoil 0.1% Barges FOB ARA (Platts) Futures (M1B): https://www.cmegroup.com/markets/energy/refined-products/micro-gasoil-01-barges-fob-rdam-platts.contractSpecs.html
|
||||
{Symbol.Create(Futures.Energies.MicroGasoilZeroPointOnePercentBargesFOBARAPlatts, SecurityType.Future, Market.NYMEX), (time =>
|
||||
{
|
||||
// Monthly contracts listed for 36 consecutive months
|
||||
|
||||
// Trading terminates on the last London business day of the contract month.
|
||||
var lastBusinessDay = FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1);
|
||||
var holidays = MarketHoursDatabase.FromDataFolder()
|
||||
.GetEntry(Market.NYMEX, Futures.Energies.MicroGasoilZeroPointOnePercentBargesFOBARAPlatts, SecurityType.Future)
|
||||
.ExchangeHours
|
||||
.Holidays;
|
||||
|
||||
while (holidays.Contains(lastBusinessDay))
|
||||
{
|
||||
lastBusinessDay = FuturesExpiryUtilityFunctions.AddBusinessDays(lastBusinessDay, -1);
|
||||
}
|
||||
|
||||
return lastBusinessDay;
|
||||
})
|
||||
},
|
||||
// Micro European FOB Rdam Marine Fuel 0.5% Barges (Platts) Futures (R50): https://www.cmegroup.com/markets/energy/refined-products/micro-european-fob-rdam-marine-fuel-05-barges-platts.contractSpecs.html
|
||||
{Symbol.Create(Futures.Energies.MicroEuropeanFOBRdamMarineFuelZeroPointFivePercentBargesPlatts, SecurityType.Future, Market.NYMEX), (time =>
|
||||
{
|
||||
// Monthly contracts listed for the current year and next 3 calendar years.
|
||||
// Add monthly contracts for a new calendar year following the termination of trading
|
||||
// in the December contract of the current year.
|
||||
|
||||
// Trading terminates on the last London business day of the contract month.
|
||||
var lastBusinessDay = FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1);
|
||||
var holidays = MarketHoursDatabase.FromDataFolder()
|
||||
.GetEntry(Market.NYMEX, Futures.Energies.MicroEuropeanFOBRdamMarineFuelZeroPointFivePercentBargesPlatts, SecurityType.Future)
|
||||
.ExchangeHours
|
||||
.Holidays;
|
||||
|
||||
while (holidays.Contains(lastBusinessDay))
|
||||
{
|
||||
lastBusinessDay = FuturesExpiryUtilityFunctions.AddBusinessDays(lastBusinessDay, -1);
|
||||
}
|
||||
|
||||
return lastBusinessDay;
|
||||
})
|
||||
},
|
||||
// Micro European 3.5% Fuel Oil Barges FOB Rdam (Platts) Futures (MEF): https://www.cmegroup.com/markets/energy/refined-products/micro-european-35-fuel-oil-barges-fob-rdam-platts.contractSpecs.html
|
||||
{Symbol.Create(Futures.Energies.MicroEuropeanThreePointFivePercentOilBargesFOBRdamPlatts, SecurityType.Future, Market.NYMEX), (time =>
|
||||
{
|
||||
// Monthly contracts listed for the current year and 5 calendar years.Monthly contracts for a new calendar
|
||||
// year will be added following the termination of trading in the December contract of the current year.
|
||||
|
||||
// Trading terminates on the last business day of the contract month.
|
||||
var lastBusinessDay = FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1);
|
||||
var holidays = MarketHoursDatabase.FromDataFolder()
|
||||
.GetEntry(Market.NYMEX, Futures.Energies.MicroEuropeanThreePointFivePercentOilBargesFOBRdamPlatts, SecurityType.Future)
|
||||
.ExchangeHours
|
||||
.Holidays;
|
||||
|
||||
while (holidays.Contains(lastBusinessDay))
|
||||
{
|
||||
lastBusinessDay = FuturesExpiryUtilityFunctions.AddBusinessDays(lastBusinessDay, -1);
|
||||
}
|
||||
|
||||
return lastBusinessDay;
|
||||
})
|
||||
},
|
||||
// Micro Singapore Fuel Oil 380CST (Platts) Futures (MAF): https://www.cmegroup.com/markets/energy/refined-products/micro-singapore-fuel-oil-380cst-platts.contractSpecs.html
|
||||
{Symbol.Create(Futures.Energies.MicroSingaporeFuelOil380CSTPlatts, SecurityType.Future, Market.NYMEX), (time =>
|
||||
{
|
||||
// Monthly contracts listed for the current year and 5 calendar years.Monthly contracts for a new calendar
|
||||
// year will be added following the termination of trading in the December contract of the current year.
|
||||
|
||||
// Trading terminates on the last business day of the contract month.
|
||||
var lastBusinessDay = FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1);
|
||||
var holidays = MarketHoursDatabase.FromDataFolder()
|
||||
.GetEntry(Market.NYMEX, Futures.Energies.MicroSingaporeFuelOil380CSTPlatts, SecurityType.Future)
|
||||
.ExchangeHours
|
||||
.Holidays;
|
||||
|
||||
while (holidays.Contains(lastBusinessDay))
|
||||
{
|
||||
lastBusinessDay = FuturesExpiryUtilityFunctions.AddBusinessDays(lastBusinessDay, -1);
|
||||
}
|
||||
|
||||
return lastBusinessDay;
|
||||
})
|
||||
},
|
||||
// Micro Coal (API 5) fob Newcastle (Argus/McCloskey) Futures (M5F): https://www.cmegroup.com/markets/energy/coal/micro-coal-api-5-fob-newcastle-argus-mccloskey.contractSpecs.html
|
||||
{Symbol.Create(Futures.Energies.MicroCoalAPIFivefobNewcastleArgusMcCloskey, SecurityType.Future, Market.NYMEX), (time =>
|
||||
{
|
||||
// Monthly contracts listed for the current year and the next calendar year. Monthly contracts
|
||||
// for a new calendar year will be added following the termination of trading in the December
|
||||
// contract of the current year.
|
||||
|
||||
// Trading terminates on the last Friday of the contract month. If such Friday is a UK holiday,
|
||||
// trading terminates on the UK business day immediately prior to the last Friday of the contract
|
||||
// month unless such day is not an Exchange business day, in which case trading terminates on the
|
||||
// Exchange business day immediately prior.
|
||||
|
||||
var lastFriday = FuturesExpiryUtilityFunctions.LastFriday(time);
|
||||
|
||||
var holidays = MarketHoursDatabase.FromDataFolder()
|
||||
.GetEntry(Market.NYMEX, Futures.Energies.MicroCoalAPIFivefobNewcastleArgusMcCloskey, SecurityType.Future)
|
||||
.ExchangeHours
|
||||
.Holidays;
|
||||
|
||||
while (holidays.Contains(lastFriday))
|
||||
{
|
||||
lastFriday = FuturesExpiryUtilityFunctions.AddBusinessDays(lastFriday, -1);
|
||||
while (holidays.Contains(lastFriday))
|
||||
{
|
||||
lastFriday = FuturesExpiryUtilityFunctions.AddBusinessDays(lastFriday, -1);
|
||||
}
|
||||
}
|
||||
|
||||
return lastFriday;
|
||||
})
|
||||
},
|
||||
// Micro European 3.5% Fuel Oil Cargoes FOB Med (Platts) Futures (M35): https://www.cmegroup.com/markets/energy/refined-products/micro-european-35-fuel-oil-cargoes-fob-med-platts.contractSpecs.html
|
||||
{Symbol.Create(Futures.Energies.MicroEuropeanThreePointFivePercentFuelOilCargoesFOBMedPlatts, SecurityType.Future, Market.NYMEX), (time =>
|
||||
{
|
||||
// Monthly contracts listed for 36 consecutive months
|
||||
|
||||
// Trading terminates on the last business day of the contract month.
|
||||
var lastBusinessDay = FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1);
|
||||
var holidays = MarketHoursDatabase.FromDataFolder()
|
||||
.GetEntry(Market.NYMEX, Futures.Energies.MicroEuropeanThreePointFivePercentFuelOilCargoesFOBMedPlatts, SecurityType.Future)
|
||||
.ExchangeHours
|
||||
.Holidays;
|
||||
|
||||
while (holidays.Contains(lastBusinessDay))
|
||||
{
|
||||
lastBusinessDay = FuturesExpiryUtilityFunctions.AddBusinessDays(lastBusinessDay, -1);
|
||||
}
|
||||
|
||||
return lastBusinessDay;
|
||||
})
|
||||
},
|
||||
// Micro Ether Futures (MET): https://www.cmegroup.com/markets/cryptocurrencies/ether/micro-ether.contractSpecs.html
|
||||
{Symbol.Create(Futures.Currencies.MicroEther, SecurityType.Future, Market.CME), (time =>
|
||||
{
|
||||
// Monthly contracts listed for 6 consecutive months and 2 additional Dec contract months.
|
||||
|
||||
// Trading terminates at 4:00 p.m. London time on the last Friday of the contract month that
|
||||
// is either a London or U.S. business day. If the last Friday of the contract month day is
|
||||
// not a business day in both London and the U.S., trading terminates on the prior London or
|
||||
// U.S. business day.
|
||||
|
||||
// BTIC: Trading terminates at 4:00 p.m. London time on the last Thursday of the contract month
|
||||
// that is either a London or U.S. business day. If the last Thursday of the contract month day
|
||||
// is not a business day in both London and the U.S., trading terminates on the prior London or U.S.
|
||||
// business day.
|
||||
|
||||
var lastFriday = FuturesExpiryUtilityFunctions.LastFriday(time);
|
||||
|
||||
var holidays = MarketHoursDatabase.FromDataFolder()
|
||||
.GetEntry(Market.CME, Futures.Currencies.MicroEther, SecurityType.Future)
|
||||
.ExchangeHours
|
||||
.Holidays;
|
||||
|
||||
while (holidays.Contains(lastFriday))
|
||||
{
|
||||
lastFriday = FuturesExpiryUtilityFunctions.AddBusinessDays(lastFriday, -1);
|
||||
}
|
||||
|
||||
return lastFriday.Add(new TimeSpan(15, 0, 0));
|
||||
})
|
||||
},
|
||||
// Micro Bitcoin Futures (MBT): https://www.cmegroup.com/markets/cryptocurrencies/bitcoin/micro-bitcoin.contractSpecs.html
|
||||
{Symbol.Create(Futures.Currencies.MicroBTC, SecurityType.Future, Market.CME), (time =>
|
||||
{
|
||||
// Monthly contracts listed for 6 consecutive months and 2 additional Dec contract months.
|
||||
// If the 6 consecutive months includes Dec, list only 1 additional Dec contract month.
|
||||
|
||||
// Trading terminates at 4:00 p.m. London time on the last Friday of the contract month.
|
||||
// If this is not both a London and U.S. business day, trading terminates on the prior
|
||||
// London and the U.S. business day.
|
||||
|
||||
// BTIC: Trading terminates at 4:00 p.m. London time on the last Thursday of the contract
|
||||
// month.If this is not both a London and U.S. business day, trading terminates on the prior
|
||||
// London and the U.S. business day.
|
||||
|
||||
var lastFriday = FuturesExpiryUtilityFunctions.LastFriday(time);
|
||||
|
||||
var holidays = MarketHoursDatabase.FromDataFolder()
|
||||
.GetEntry(Market.CME, Futures.Currencies.MicroBTC, SecurityType.Future)
|
||||
.ExchangeHours
|
||||
.Holidays;
|
||||
|
||||
while (holidays.Contains(lastFriday))
|
||||
{
|
||||
lastFriday = FuturesExpiryUtilityFunctions.AddBusinessDays(lastFriday, -1);
|
||||
}
|
||||
|
||||
return lastFriday.Add(new TimeSpan(15, 0, 0));
|
||||
})
|
||||
},
|
||||
// BTIC on Micro Ether Futures (MRB): https://www.cmegroup.com/markets/cryptocurrencies/ether/micro-ether.contractSpecs.html
|
||||
{Symbol.Create(Futures.Currencies.BTICMicroEther, SecurityType.Future, Market.CME), (time =>
|
||||
{
|
||||
// Monthly contracts listed for 6 consecutive months and 2 additional Dec contract months.
|
||||
|
||||
// Trading terminates at 4:00 p.m. London time on the last Friday of the contract month.
|
||||
// If this is not both a London and U.S. business day, trading terminates on the prior
|
||||
// London and the U.S. business day.
|
||||
|
||||
// BTIC: Trading terminates at 4:00 p.m. London time on the last Thursday of the contract
|
||||
// month.If this is not both a London and U.S. business day, trading terminates on the prior
|
||||
// London and the U.S. business day.
|
||||
|
||||
var lastThursday = FuturesExpiryUtilityFunctions.LastThursday(time);
|
||||
|
||||
var holidays = MarketHoursDatabase.FromDataFolder()
|
||||
.GetEntry(Market.CME, Futures.Currencies.BTICMicroEther, SecurityType.Future)
|
||||
.ExchangeHours
|
||||
.Holidays;
|
||||
|
||||
while (holidays.Contains(lastThursday))
|
||||
{
|
||||
lastThursday = FuturesExpiryUtilityFunctions.AddBusinessDays(lastThursday, -1);
|
||||
}
|
||||
|
||||
return lastThursday.Add(new TimeSpan(15, 0, 0));
|
||||
})
|
||||
},
|
||||
// BTIC on Micro Bitcoin Futures (MIB): https://www.cmegroup.com/markets/cryptocurrencies/bitcoin/micro-bitcoin.contractSpecs.html
|
||||
{Symbol.Create(Futures.Currencies.BTICMicroBTC, SecurityType.Future, Market.CME), (time =>
|
||||
{
|
||||
// Monthly contracts listed for 6 consecutive months and 2 additional Dec contract months.
|
||||
// If the 6 consecutive months includes Dec, list only 1 additional Dec contract month.
|
||||
|
||||
// Trading terminates at 4:00 p.m. London time on the last Friday of the contract month.
|
||||
// If this is not both a London and U.S. business day, trading terminates on the prior
|
||||
// London and the U.S. business day.
|
||||
|
||||
// BTIC: Trading terminates at 4:00 p.m. London time on the last Thursday of the contract
|
||||
// month.If this is not both a London and U.S. business day, trading terminates on the prior
|
||||
// London and the U.S. business day.
|
||||
|
||||
var lastThursday = FuturesExpiryUtilityFunctions.LastThursday(time);
|
||||
|
||||
var holidays = MarketHoursDatabase.FromDataFolder()
|
||||
.GetEntry(Market.CME, Futures.Currencies.BTICMicroBTC, SecurityType.Future)
|
||||
.ExchangeHours
|
||||
.Holidays;
|
||||
|
||||
while (holidays.Contains(lastThursday))
|
||||
{
|
||||
lastThursday = FuturesExpiryUtilityFunctions.AddBusinessDays(lastThursday, -1);
|
||||
}
|
||||
|
||||
return lastThursday.Add(new TimeSpan(15, 0, 0));
|
||||
})
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/*
|
||||
/*
|
||||
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
|
||||
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
|
||||
*
|
||||
@@ -257,12 +257,19 @@ namespace QuantConnect.Securities.Future
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Method to retrieve the last weekday of any month
|
||||
/// Method to retrieve the last Thursday of any month
|
||||
/// </summary>
|
||||
/// <param name="time">Date from the given month</param>
|
||||
/// <returns>Last day of the we</returns>
|
||||
/// <returns>Last Thursday of the given month</returns>
|
||||
public static DateTime LastThursday(DateTime time) => LastWeekday(time, DayOfWeek.Thursday);
|
||||
|
||||
/// <summary>
|
||||
/// Method to retrieve the last Friday of any month
|
||||
/// </summary>
|
||||
/// <param name="time">Date from the given month</param>
|
||||
/// <returns>Last Friday of the given month</returns>
|
||||
public static DateTime LastFriday(DateTime time) => LastWeekday(time, DayOfWeek.Friday);
|
||||
|
||||
/// <summary>
|
||||
/// Method to check whether a given time is holiday or not
|
||||
/// </summary>
|
||||
|
||||
@@ -29,7 +29,7 @@ namespace QuantConnect.Securities.Option.StrategyMatcher
|
||||
/// <summary>
|
||||
/// Gets a new <see cref="OptionPosition"/> with zero <see cref="Quantity"/>
|
||||
/// </summary>
|
||||
public static OptionPosition None(Symbol symbol)
|
||||
public static OptionPosition Empty(Symbol symbol)
|
||||
=> new OptionPosition(symbol, 0);
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -247,14 +247,6 @@ namespace QuantConnect.Securities
|
||||
/// <param name="dataType">The data type</param>
|
||||
public void StoreData(IReadOnlyList<BaseData> data, Type dataType)
|
||||
{
|
||||
#if DEBUG // don't run this in release as we should never fail here, but it's also nice to have here as documentation of intent
|
||||
if (data.DistinctBy(d => d.GetType()).Skip(1).Any())
|
||||
{
|
||||
throw new ArgumentException(
|
||||
"SecurityCache.StoreData data list must contain elements of the same type."
|
||||
);
|
||||
}
|
||||
#endif
|
||||
if (dataType == typeof(Tick))
|
||||
{
|
||||
var tick = data[data.Count - 1] as Tick;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user