Compare commits

...

19 Commits
13556 ... 13680

Author SHA1 Message Date
C-SELLERS
c75b4a98b4 Update Research Images with Newer Jupyter 2022-02-11 15:45:51 -08:00
C-SELLERS
288501bd3b Install NetCoreDbg 2022-02-11 15:45:51 -08:00
C-SELLERS
9e7ead1a19 Deprecate breakpoints
Drop Watchlist

Remove breakpoints from lean

Prep install of NetCoreDbg

Cleanup
2022-02-11 15:45:51 -08:00
Colton Sellers
b80e274d4f Rename OptionsPositions.None -> Empty (#6204) 2022-02-11 19:11:30 -03:00
Martin-Molinero
9a355c9be5 Adjust INR/USD micro future scale to usd dollars (#6203) 2022-02-11 17:01:01 -03:00
Kieran Anderson
303b95ab50 Fix typo (#6201)
"buisness" --> "business"
2022-02-10 21:16:18 -03:00
Colton Sellers
d826d267f4 Update CI script with fixes for using env var (#6200) 2022-02-10 20:13:39 -03:00
Ricardo Andrés Marino Rojas
eb55311052 Feature 5157 micro futures update (#6190)
* Update MHDB and SPDB

Update MHDB and SPDB with micro futures

* Fix bugs

* Add more FutureExpiryFunctions

* Requested changes

* Nit changes

* Nit changes

- Fix some future values in SPDB
- Test LastFriday() method
- Apparently Micro CHF/USD Futures(MSF) refers to the micro of Swiss Franc Futures (6S). The same happens with Micro JPY/USD (MJY) Futures and Japanese Yen Futures (6J)

* Fix bugs

* Micro futures MultipleFactor

* Fix some futures MultipleFactor
2022-02-10 17:45:07 -03:00
Colton Sellers
27d18fa2e8 Include DataSource repos in stub generation (#6195)
* Include DataSource repos in stub generation

* Remove C# import from AlgorithmImports

* Directly import the Algorithm.CSharp namespace

* Update ci_build_stubs.sh

Case-sensitive typo

Co-authored-by: Jasper van Merle <jaspervmerle@gmail.com>

Co-authored-by: Jasper van Merle <jaspervmerle@gmail.com>
2022-02-10 15:09:08 -03:00
Adalyat Nazirov
bb0c671e7c Accept OrderSubmissionData in constructor (#6194)
* modify OrderTestParameters constructor

* add other types
2022-02-08 19:27:22 -03:00
Martin-Molinero
c8dc343c13 GetLastKnownPrices python data (#6191)
* Adding unit tests reproducing issue.

* Fix a couple of minor bugs

- IsMarketOpen will work correctly when used with daily and hourly
  resolution.
- slice.Get will work correctly with python custom data
- ExtendedDictionary will be able to dinamically access methods,
  required for python and private C# data types

* Refactor solution. Add more tests

* Remove unrequired import statement
2022-02-08 15:37:05 -03:00
Alexander Myltsev
b6815d22de Exante Brokerage initial setup (#6018)
* Exante Brokerage initial setup

* Minor exante adjustment. Address review

* Add comments to Exante config section

* Exante `GetLeverage`: handle `SecurityType.Forex`

* Exante `GetLeverage`: return 1.0 for the default case

* Cover Exante `BrokerageModel` and `FeeModel` with tests

* Add missing configurations at config.json

Fixes https://github.com/QuantConnect/Lean/pull/6018#discussion_r799527521

* Fix spaces typos

https://github.com/QuantConnect/Lean/pull/6018#discussion_r799528112

Co-authored-by: Martin-Molinero <martin@quantconnect.com>
2022-02-07 19:53:22 -03:00
Martin-Molinero
459f60603b Fees is base currency subtracted from quote currency (#6188)
* WIP

* Fix fees in base currency not being subtracted

- Fix fees in base currency not being subtracted from the quote currency
  for crypto cash accounts. Updating regression tests to assert
  portfolio, cashbook state and holdings state.

* Fix unit test race condition
2022-02-07 14:57:40 -03:00
Martin-Molinero
1aaaa20c61 Fix daily auxiliary data points emission time (#6186)
* Use GC server mode for tests

* Fix daily auxiliary data points emission time

- Due to fillforwarding, in some cases with daily resolution symbol
  change events (generically any auxiliary data) would arrive late.
  Updating regression test to reproduce the issue. Adding unit test
- Some refactoring and logging improvements

* Address reviews

* Remove old xml docs param
2022-02-04 21:06:45 -03:00
Adalyat Nazirov
07b6572bf9 Support Binance Margin trading (#6173)
* change BinanceBrokerageModel

* supply spot vs margin endpoint as parameter

* wip

* send margin order for margin account

* "NEW" means that the order has been accepted by the Binance engine.

* fix cash balance

* use JsonConverters for account parsing

* unit tests

* fixup

* lazy connect

* fix connection

* allow api client to be null if DQH only

* make method private

* more unit tests

* fix Dispose

* fix tests

* fix IsConnected condition

* run test as additional

* add some comments

* improve unit tests

* improve null checks

* tidy up the code
2022-02-04 17:30:39 -03:00
Ricardo Andrés Marino Rojas
a675aca7e5 Refactor GetFilePath() (#6164)
* Refactor `GetFilePath()`
Add also useful methods to use with this one

* Nit changes

* Requested changes

* Requested changes

* Restore SaveString()

* Nit changes

* Address self review

* Test improvements

* Adjust example KerasNeuralNetworkAlgorithm

* Minor tweak for KerasNeuralNetworkAlgorithm.py

Co-authored-by: Martin-Molinero <martin@quantconnect.com>
2022-02-04 16:58:25 -03:00
Martin-Molinero
87db3fe379 Performance improvements (#6182)
- User server mode for GC
- Remove SecurityType cache type check
2022-02-02 19:52:45 -03:00
Ricardo Andrés Marino Rojas
74321d1727 Update CME future holidays and early closes in MHDB (#6181)
* CME Futures update in MHDB

* Fix indent spaces nit errors

* Revert "Fix indent spaces nit errors"

This reverts commit 6ebb8614c0.

* Fix tabs errors

* Update MHDB with 2022 holidays

* Fix bugs

* Remove earlyOpens
2022-02-02 19:28:21 -03:00
Martin-Molinero
9fd50a302e Update or remove SharpZipLib dependency (#6180) 2022-02-02 13:28:24 -03:00
101 changed files with 15841 additions and 827 deletions

View File

@@ -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 }}

View File

@@ -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)

View File

@@ -76,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)

View File

@@ -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"}
};
}
}

View File

@@ -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"}
};
}
}

View File

@@ -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);

View File

@@ -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);

View File

@@ -64,7 +64,7 @@ namespace QuantConnect.Algorithm.CSharp
{"Kelly Criterion Estimate", "0"},
{"Kelly Criterion Probability Value", "0"},
{"Sortino Ratio", "79228162514264337593543950335"},
{"Return Over Maximum Drawdown", "79228162514264337593543950335"},
{"Return Over Maximum Drawdown", "26.189"},
{"Portfolio Turnover", "0.208"},
{"Total Insights Generated", "0"},
{"Total Insights Closed", "0"},

View File

@@ -13,7 +13,11 @@
* 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;
@@ -54,7 +58,28 @@ namespace QuantConnect.Algorithm.CSharp
{
if (!Portfolio.Invested)
{
Buy(_symbol, 0.1m);
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
{

View File

@@ -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"},

View File

@@ -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"}
};
}
}

View File

@@ -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()

View File

@@ -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()

View File

@@ -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)

View File

@@ -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)

View File

@@ -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'''

View File

@@ -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

View File

@@ -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)

View File

@@ -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)

View File

@@ -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" />

View File

@@ -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,

View File

@@ -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();

View File

@@ -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;
};
}
}

View File

@@ -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;

View File

@@ -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()
{
@@ -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();
}
}
}

View 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;
}
}
}

View File

@@ -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();
}
}

View File

@@ -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

View 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();
}
}
}

View 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();
}
}
}

View File

@@ -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

View File

@@ -61,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 *

View File

@@ -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>

View File

@@ -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,
}
}

View 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,
};
}
}
}

View File

@@ -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);

View File

@@ -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>

View File

@@ -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>

View File

@@ -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);
}

View File

@@ -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
{
}
}
}
}

View File

@@ -348,4 +348,4 @@ namespace QuantConnect
return GetValues.ToPyList();
}
}
}
}

View File

@@ -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>

View 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}"))
};
}
}
}

View File

@@ -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);
}
}
}

View File

@@ -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);
}
}
}

View File

@@ -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

View File

@@ -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;
}
}
}
}

View File

@@ -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&amp;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";
}
}
}
}

View File

@@ -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));
})
}
};
}
}

View File

@@ -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>

View File

@@ -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>

View File

@@ -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;

View File

@@ -1,4 +1,4 @@
/*
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
@@ -124,7 +124,8 @@ namespace QuantConnect.Storage
{
encoding = encoding ?? Encoding.UTF8;
return encoding.GetString(_store.ReadBytes(key));
var data = _store.ReadBytes(key);
return data != null ? encoding.GetString(data) : null;
}
/// <summary>
@@ -172,17 +173,35 @@ namespace QuantConnect.Storage
}
}
/// <summary>
/// Saves the data from a local file path associated with the specified key
/// </summary>
/// <remarks>If the file does not exist it will throw an exception</remarks>
/// <param name="key">The object key</param>
/// <returns>True if the object was saved successfully</returns>
public bool Save(string key)
{
// Check the file exists
var filePath = GetFilePath(key);
if (!File.Exists(filePath))
{
throw new ArgumentException($"There is no file associated with key {key} in '{filePath}'");
}
var bytes = File.ReadAllBytes(filePath);
return _store.SaveBytes(key, bytes);
}
/// <summary>
/// Saves the object data in text format for the specified key
/// </summary>
/// <param name="key">The object key</param>
/// <param name="text">The string object to be saved</param>
/// <param name="encoding">The string encoding used</param>
/// <param name="encoding">The string encoding used, <see cref="Encoding.UTF8"/> by default</param>
/// <returns>True if the object was saved successfully</returns>
public bool Save(string key, string text, Encoding encoding = null)
{
encoding = encoding ?? Encoding.UTF8;
encoding ??= Encoding.UTF8;
return _store.SaveBytes(key, encoding.GetBytes(text));
}

View File

@@ -15,7 +15,6 @@
using System;
using System.Collections.Generic;
using System.Data;
using System.Globalization;
using NodaTime;
using QuantConnect.Logging;
@@ -487,7 +486,7 @@ namespace QuantConnect
/// </summary>
/// <remarks>
/// This is mainly used to bridge the gap between exchange time zone and data time zone for file written to disk. The returned
/// enumerable of dates is gauranteed to be the same size or longer than those generated via <see cref="EachTradeableDay(ICollection{Security},DateTime,DateTime)"/>
/// enumerable of dates is guaranteed to be the same size or longer than those generated via <see cref="EachTradeableDay(ICollection{Security},DateTime,DateTime)"/>
/// </remarks>
/// <param name="exchange">The exchange hours</param>
/// <param name="from">The start time in the exchange time zone</param>

View File

@@ -35,7 +35,7 @@
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="SharpZipLib" Version="1.2.0" />
<PackageReference Include="SharpZipLib" Version="1.3.3" />
</ItemGroup>
<ItemGroup>
<Compile Include="..\Common\Properties\SharedAssemblyInfo.cs" Link="Properties\SharedAssemblyInfo.cs" />

File diff suppressed because it is too large Load Diff

View File

@@ -89,12 +89,17 @@ usa,[*],indexoption,,USD,100,0.05,1
# for backwards compatibility, order here is important for futures, since we could have the same symbol for more than 1 market in which case Lean will use the first
cfe,VX,future,VIX futures ,USD,1000.0,0.05,1.0
cbot,2YY,future,Micro 2-Year Yield Futures,USD,1000,0.001,1
cbot,5YY,future,Micro 5-Year Yield Futures,USD,1000,0.001,1
cbot,10Y,future,Micro 10-Year Yield Futures,USD,1000,0.001,1
cbot,30Y,future,Micro 30-Year Yield Futures,USD,1000,0.001,1
cbot,AW,future,Bloomberg Commodity Index Futures,USD,100.0,0.1,1.0
cbot,BCF,future,Black Sea Corn Financially Settled (Platts) Futures,USD,50.0,0.25,1.0
cbot,BWF,future,Black Sea Wheat Financially Settled (Platts) Futures,USD,50.0,0.25,1.0
cbot,EH,future,Ethanol Futures,USD,29000.0,0.001,1.0
cbot,F1U,future,5-Year USD MAC Swap Futures,USD,1000.0,0.0078125,1.0
cbot,KE,future,KC HRW Wheat Futures,USD,5000.0,0.0025,1.0,,1,100
cbot,MYM,future,Micro E-mini Dow Jones Industrial Average Index Futures,USD,0.5,1,1
cbot,TN,future,Ultra 10-Year U.S. Treasury Note Futures,USD,1000.0,0.015625,1.0
cbot,UB,future,Ultra U.S. Treasury Bond Futures,USD,1000.0,0.03125,1.0
cbot,YM,future,E-mini Dow ($5) Futures,USD,5.0,1.0,1.0
@@ -106,7 +111,7 @@ cbot,ZM,future,Soybean Meal Futures,USD,100.0,0.1,1.0
cbot,ZN,future,10-Year T-Note Futures,USD,1000.0,0.015625,1.0
cbot,ZO,future,Oats Futures,USD,5000.0,0.25,1.0,,1,100
cbot,ZS,future,Soybean Futures,USD,5000.0,0.0025,1.0,,1,100
cbot,ZT,future,2-Year T-Note Futures,USD,2000.0,0.00390625,1.0
cbot,ZT,future,2-Year T-Note Futures,USD,200000,0.00390625,1.0
cbot,ZW,future,Chicago SRW Wheat Futures,USD,5000.0,0.0025,1.0,,1,100
cme,6A,future,Australian Dollar Futures,USD,100000.0,0.0001,1.0
cme,6B,future,British Pound Futures,USD,62500.0,0.0001,1.0
@@ -147,6 +152,24 @@ cme,IBV,future,USD-Denominated Ibovespa Index Futures,USD,1.0,5.0,1.0
cme,J7,future,E-mini Japanese Yen Futures,USD,6250000.0,1e-06,1.0
cme,LBS,future,Random Length Lumber Futures,USD,110.0,0.1,1.0
cme,LE,future,Live Cattle Futures,USD,40000.0,0.025,1.0,,1,100
cme,M2K,future,Micro E-mini Russell 2000 Index Futures,USD,5.0,0.1,1,,1
cme,M6A,future,Micro Australian Dollar/U.S. Dollar (AUD/USD) Futures,USD,10000,0.0001,1,,1
cme,M6B,future,Micro British Pound Sterling/U.S. Dollar (GBP/USD) Futures,USD,6250,0.0001,1,,1
cme,M6C,future,Micro USD/CAD Futures,CAD,10000,0.0001,1
cme,M6E,future,Micro Euro/U.S. Dollar (EUR/USD) Futures,USD,12500,0.0001,1,,1
cme,M6J,future,Micro USD/JPY Futures,JPY,10000,0.01,1
cme,M6S,future,Micro USD/CHF Futures,CHF,10000,0.0001,1
cme,MBT,future,Micro Bitcoin Futures,USD,0.1,5,1,,1
cme,MCD,future,Micro Canadian Dollar/U.S.Dollar(CAD/USD) Futures,USD,10000,0.0001,1,,1
cme,MES,future,Micro E-mini Standard and Poor's 500 Stock Price Index Futures,USD,5,0.25,1,,1
cme,MET,future,Micro Ether Futures,USD,0.1,0.5,1,,1
cme,MIB,future,BTIC on Micro Bitcoin Futures,USD,0.1,5,1
cme,MIR,future,Micro INR/USD Futures,USD,1000000,0.01,100,,1,100
cme,MJY,future,Micro Japanese Yen/U.S. Dollar (JPY/USD) Futures,USD,1250000,1e-06,1,,1
cme,MNH,future,Micro USD/CNH Futures,USD,10000,0.0001,1
cme,MNQ,future,Micro E-mini Nasdaq-100 Index Futures,USD,2,0.25,1,,1
cme,MRB,future,BTIC on Micro Ether Futures,USD,0.1,0.5,1
cme,MSF,future,Micro Swiss Franc/U.S. Dollar (CHF/USD) Futures,USD,12500,0.0001,1,,1
cme,NKD,future,Nikkei/USD Futures,USD,5.0,5.0,1.0
cme,NQ,future,E-mini Nasdaq-100 Futures,USD,20.0,0.25,1.0
cme,RTY,future,E-mini Russell 2000 Index Futures,USD,50.0,0.1,1.0
@@ -154,7 +177,10 @@ comex,AUP,future,Aluminum MW U.S. Transaction Premium Platts (25MT) Futures,USD,
comex,EDP,future,Aluminium European Premium Duty-Paid (Metal Bulletin) Futures,USD,25.0,0.01,1.0
comex,GC,future,Gold Futures,USD,100.0,0.1,1.0
comex,HG,future,Copper Futures,USD,25000.0,0.0005,1.0
comex,MGC,future,Micro Gold Futures,USD,10,0.1,1,,1
comex,MGT,future,Micro Gold TAS Futures,USD,10,0.1,1
comex,SI,future,Silver Futures,USD,5000.0,0.005,1.0
comex,SIL,future,Micro Silver Futures,USD,1000,0.005,1,,1
ice,B,future,Brent Crude Futures,USD,1000.0,0.01,1.0
ice,CC,future,Cocoa Futures,USD,10.0,1.0,1.0
ice,CT,future,Cotton No. 2 Futures,USD,50000.0,0.0001,1.0
@@ -230,10 +256,19 @@ nymex,HO,future,NY Harbor ULSD Futures,USD,42000.0,0.0001,1.0
nymex,HP,future,Natural Gas (Henry Hub) Penultimate Financial Futures,USD,10000.0,0.001,1.0
nymex,HRC,future,U.S. Midwest Domestic Hot-Rolled Coil Steel (CRU) Index Futures,USD,20.0,1.0,1.0
nymex,HTT,future,WTI Houston (Argus) vs. WTI Trade Month Futures,USD,1000.0,0.01,1.0
nymex,M1B,future,Micro Gasoil 0.1% Barges FOB ARA (Platts) Futures,USD,10,0.001,1,,1
nymex,M35,future,Micro European 3.5% Fuel Oil Cargoes FOB Med (Platts) Futures,USD,10,0.001,1,,1
nymex,M5F,future,Micro Coal (API 5) fob Newcastle (Argus/McCloskey) Futures,USD,10,0.01,1,,1
nymex,MAF,future,Micro Singapore Fuel Oil 380CST (Platts) Futures ,USD,10,0.001,1,,1
nymex,MCL,future,Micro WTI Crude Oil Futures,USD,100,0.01,1,,1
nymex,MEF,future,Micro European 3.5% Fuel Oil Barges FOB Rdam (Platts) Futures,USD,10,0.001,1,,1
nymex,NG,future,Henry Hub Natural Gas Futures,USD,10000.0,0.001,1.0
nymex,PA,future,Palladium Futures,USD,100.0,0.05,1.0
nymex,PA,future,Palladium Futures,USD,100.0,0.5,1.0
nymex,PAM,future,Micro Palladium Futures,USD,10,0.5,1,,1
nymex,PL,future,Platinum Futures,USD,50.0,0.1,1.0
nymex,R5O,future,Micro European FOB Rdam Marine Fuel 0.5% Barges (Platts) Futures,USD,10,0.001,1,,1
nymex,RB,future,RBOB Gasoline Futures,USD,42000.0,0.0001,1.0
nymex,S5O,future,Micro Singapore FOB Marine Fuel 0.5% (Platts) Futures,USD,10,0.001,1,,1
nymex,YO,future,No. 11 Sugar Futures,USD,112000.0,0.0001,1.0
sgx,NK,future,SGX Nikkei 225 Index Futures,JPY,500,5,5.0
sgx,TW,future,MSCI Taiwan Index Futures,USD,100,0.1,50.0
1 market,symbol,type,description,quote_currency,contract_multiplier,minimum_price_variation,lot_size,market_ticker,minimum_order_size,price_magnifier
89 cbot,F1U,future,5-Year USD MAC Swap Futures,USD,1000.0,0.0078125,1.0 cbot,AW,future,Bloomberg Commodity Index Futures,USD,100.0,0.1,1.0
90 cbot,KE,future,KC HRW Wheat Futures,USD,5000.0,0.0025,1.0,,1,100 cbot,BCF,future,Black Sea Corn Financially Settled (Platts) Futures,USD,50.0,0.25,1.0
91 cbot,TN,future,Ultra 10-Year U.S. Treasury Note Futures,USD,1000.0,0.015625,1.0 cbot,BWF,future,Black Sea Wheat Financially Settled (Platts) Futures,USD,50.0,0.25,1.0
92 cbot,EH,future,Ethanol Futures,USD,29000.0,0.001,1.0
93 cbot,F1U,future,5-Year USD MAC Swap Futures,USD,1000.0,0.0078125,1.0
94 cbot,KE,future,KC HRW Wheat Futures,USD,5000.0,0.0025,1.0,,1,100
95 cbot,MYM,future,Micro E-mini Dow Jones Industrial Average Index Futures,USD,0.5,1,1
96 cbot,UB,future,Ultra U.S. Treasury Bond Futures,USD,1000.0,0.03125,1.0 cbot,TN,future,Ultra 10-Year U.S. Treasury Note Futures,USD,1000.0,0.015625,1.0
97 cbot,YM,future,E-mini Dow ($5) Futures,USD,5.0,1.0,1.0 cbot,UB,future,Ultra U.S. Treasury Bond Futures,USD,1000.0,0.03125,1.0
98 cbot,ZB,future,U.S. Treasury Bond Futures,USD,1000.0,0.03125,1.0 cbot,YM,future,E-mini Dow ($5) Futures,USD,5.0,1.0,1.0
99 cbot,ZC,future,Corn Futures,USD,5000.0,0.0025,1.0,,1,100 cbot,ZB,future,U.S. Treasury Bond Futures,USD,1000.0,0.03125,1.0
100 cbot,ZF,future,5-Year T-Note Futures,USD,1000.0,0.0078125,1.0 cbot,ZC,future,Corn Futures,USD,5000.0,0.0025,1.0,,1,100
101 cbot,ZL,future,Soybean Oil Futures,USD,60000.0,0.01,1.0,,1,100 cbot,ZF,future,5-Year T-Note Futures,USD,1000.0,0.0078125,1.0
102 cbot,ZL,future,Soybean Oil Futures,USD,60000.0,0.01,1.0,,1,100
103 cbot,ZM,future,Soybean Meal Futures,USD,100.0,0.1,1.0
104 cbot,ZN,future,10-Year T-Note Futures,USD,1000.0,0.015625,1.0
105 cbot,ZO,future,Oats Futures,USD,5000.0,0.25,1.0,,1,100
111 cme,6C,future,Canadian Dollar Futures,USD,100000.0,5e-05,1.0
112 cme,6E,future,Euro FX Futures,USD,125000.0,5e-05,1.0
113 cme,6J,future,Japanese Yen Futures,USD,12500000.0,5e-07,1.0
114 cme,6L,future,Brazilian Real Futures,USD,100000.0,5e-05,1.0
115 cme,6M,future,Mexican Peso Futures,USD,500000.0,1e-05,1.0
116 cme,6N,future,New Zealand Dollar Futures,USD,100000.0,0.0001,1.0
117 cme,6R,future,Russian Ruble Futures,USD,2500000.0,5e-06,1.0
152 comex,EDP,future,Aluminium European Premium Duty-Paid (Metal Bulletin) Futures,USD,25.0,0.01,1.0 cme,M6E,future,Micro Euro/U.S. Dollar (EUR/USD) Futures,USD,12500,0.0001,1,,1
153 comex,GC,future,Gold Futures,USD,100.0,0.1,1.0 cme,M6J,future,Micro USD/JPY Futures,JPY,10000,0.01,1
154 comex,HG,future,Copper Futures,USD,25000.0,0.0005,1.0 cme,M6S,future,Micro USD/CHF Futures,CHF,10000,0.0001,1
155 cme,MBT,future,Micro Bitcoin Futures,USD,0.1,5,1,,1
156 cme,MCD,future,Micro Canadian Dollar/U.S.Dollar(CAD/USD) Futures,USD,10000,0.0001,1,,1
157 cme,MES,future,Micro E-mini Standard and Poor's 500 Stock Price Index Futures,USD,5,0.25,1,,1
158 cme,MET,future,Micro Ether Futures,USD,0.1,0.5,1,,1
159 cme,MIB,future,BTIC on Micro Bitcoin Futures,USD,0.1,5,1
160 cme,MIR,future,Micro INR/USD Futures,USD,1000000,0.01,100,,1,100
161 cme,MJY,future,Micro Japanese Yen/U.S. Dollar (JPY/USD) Futures,USD,1250000,1e-06,1,,1
162 cme,MNH,future,Micro USD/CNH Futures,USD,10000,0.0001,1
163 cme,MNQ,future,Micro E-mini Nasdaq-100 Index Futures,USD,2,0.25,1,,1
164 cme,MRB,future,BTIC on Micro Ether Futures,USD,0.1,0.5,1
165 cme,MSF,future,Micro Swiss Franc/U.S. Dollar (CHF/USD) Futures,USD,12500,0.0001,1,,1
166 cme,NKD,future,Nikkei/USD Futures,USD,5.0,5.0,1.0
167 cme,NQ,future,E-mini Nasdaq-100 Futures,USD,20.0,0.25,1.0
168 cme,RTY,future,E-mini Russell 2000 Index Futures,USD,50.0,0.1,1.0
169 comex,AUP,future,Aluminum MW U.S. Transaction Premium Platts (25MT) Futures,USD,55116.0,1e-05,1.0
170 comex,EDP,future,Aluminium European Premium Duty-Paid (Metal Bulletin) Futures,USD,25.0,0.01,1.0
171 comex,GC,future,Gold Futures,USD,100.0,0.1,1.0
172 comex,HG,future,Copper Futures,USD,25000.0,0.0005,1.0
173 comex,SI,future,Silver Futures,USD,5000.0,0.005,1.0 comex,MGC,future,Micro Gold Futures,USD,10,0.1,1,,1
174 ice,B,future,Brent Crude Futures,USD,1000.0,0.01,1.0 comex,MGT,future,Micro Gold TAS Futures,USD,10,0.1,1
175 ice,CC,future,Cocoa Futures,USD,10.0,1.0,1.0 comex,SI,future,Silver Futures,USD,5000.0,0.005,1.0
177 ice,DX,future,US Dollar Index Futures,USD,1000.0,0.005,1.0 ice,B,future,Brent Crude Futures,USD,1000.0,0.01,1.0
178 ice,G,future,Low Sulfur Gasoil,USD,100.0,0.25,1.0 ice,CC,future,Cocoa Futures,USD,10.0,1.0,1.0
179 ice,KC,future,Coffee C Arabica Futures,USD,37500.0,0.0005,1.0 ice,CT,future,Cotton No. 2 Futures,USD,50000.0,0.0001,1.0
180 ice,DX,future,US Dollar Index Futures,USD,1000.0,0.005,1.0
181 ice,G,future,Low Sulfur Gasoil,USD,100.0,0.25,1.0
182 ice,OJ,future,Frozen Concentrated Orange Juice,USD,15000.0,0.0005,1.0 ice,KC,future,Coffee C Arabica Futures,USD,37500.0,0.0005,1.0
183 ice,OJ,future,Frozen Concentrated Orange Juice,USD,15000.0,0.0005,1.0
184 ice,SB,future,Sugar No. 11 Futures,USD,112000,0.0001,1
185 nymex,1S,future,Propane Non-LDH Mont Belvieu (OPIS) BALMO Futures,USD,42000.0,1e-05,1.0
186 nymex,22,future,Argus Propane Far East Index BALMO Futures,USD,1000.0,0.001,1.0
256 nymex,YO,future,No. 11 Sugar Futures,USD,112000.0,0.0001,1.0 nymex,MCL,future,Micro WTI Crude Oil Futures,USD,100,0.01,1,,1
257 sgx,NK,future,SGX Nikkei 225 Index Futures,JPY,500,5,5.0 nymex,MEF,future,Micro European 3.5% Fuel Oil Barges FOB Rdam (Platts) Futures,USD,10,0.001,1,,1
258 sgx,TW,future,MSCI Taiwan Index Futures,USD,100,0.1,50.0 nymex,NG,future,Henry Hub Natural Gas Futures,USD,10000.0,0.001,1.0
259 nymex,PA,future,Palladium Futures,USD,100.0,0.5,1.0
260 nymex,PAM,future,Micro Palladium Futures,USD,10,0.5,1,,1
261 nymex,PL,future,Platinum Futures,USD,50.0,0.1,1.0
262 nymex,R5O,future,Micro European FOB Rdam Marine Fuel 0.5% Barges (Platts) Futures,USD,10,0.001,1,,1
263 nymex,RB,future,RBOB Gasoline Futures,USD,42000.0,0.0001,1.0
264 nymex,S5O,future,Micro Singapore FOB Marine Fuel 0.5% (Platts) Futures,USD,10,0.001,1,,1
265 sgx,IN,future,Nifty Indices Futures,USD,2,0.5,50.0 nymex,YO,future,No. 11 Sugar Futures,USD,112000.0,0.0001,1.0
266 india,NIFTY,future,Nifty50 Index,INR,0.05,75,1 sgx,NK,future,SGX Nikkei 225 Index Futures,JPY,500,5,5.0
267 sgx,TW,future,MSCI Taiwan Index Futures,USD,100,0.1,50.0
268 india,BANKNIFTY,future,BankNifty Index,INR,0.05,25,1.0 sgx,IN,future,Nifty Indices Futures,USD,2,0.5,50.0
269 india,NIFTY,future,Nifty50 Index,INR,0.05,75,1
270 india,SENSEX,future,BSE S&P Sensex Index,INR,0.05,25,1.0 india,BANKNIFTY,future,BankNifty Index,INR,0.05,25,1.0
271 india,SENSEX,future,BSE S&P Sensex Index,INR,0.05,25,1.0
272 hkfe,HSI,future,Hang Seng Index,HKD,50,1,1.0
273 # Futures options -- will default to Futures contract specs in case no entry exists
274 cbot,OZB,futureoption,U.S. Treasury Bond American Futures Options,USD,1000.0,0.015625,1.0

View File

@@ -14,6 +14,10 @@ RUN pip install --no-cache-dir debugpy~=1.5.1 pydevd-pycharm~=201.8538.36
# Install vsdbg for remote C# debugging in Visual Studio and Visual Studio Code
RUN wget https://aka.ms/getvsdbgsh -O - 2>/dev/null | /bin/sh /dev/stdin -v 16.9.20122.2 -l /root/vsdbg
# Install NetCoreDbg
RUN wget https://github.com/Samsung/netcoredbg/releases/download/2.0.0-880/netcoredbg-linux-amd64.tar.gz \
&& tar xvzf netcoredbg-linux-amd64.tar.gz && rm netcoredbg-linux-amd64.tar.gz
COPY ./DataLibraries /Lean/Launcher/bin/Debug/
COPY ./AlphaStreams/QuantConnect.AlphaStream/bin/Debug/ /Lean/Launcher/bin/Debug/
COPY ./Lean/Launcher/bin/Debug/ /Lean/Launcher/bin/Debug/

View File

@@ -21,8 +21,6 @@ RUN if [ "$(uname -m)" = "aarch64" ]; then \
mv tini /usr/local/bin/tini && \
chmod +x /usr/local/bin/tini
RUN conda install -y -c conda-forge notebook=6.0.3 && conda clean -y --all
# Install clr-loader for PythonNet
RUN pip install --no-cache-dir clr-loader==0.1.6

View File

@@ -83,7 +83,7 @@ RUN pip install --no-cache-dir \
setuptools-git==1.2 \
xarray==0.15.1 \
plotly==4.7.1 \
jupyterlab==2.1.2 \
jupyterlab==3.2.6 \
tensorflow==1.15.2 \
docutils==0.14 \
cvxopt==1.2.0 \

View File

@@ -69,7 +69,7 @@ RUN conda install -y \
pandas=0.25.3 \
numpy=1.18.1 \
wrapt=1.12.1 \
jupyterlab=2.1.2 \
jupyterlab=3.2.6 \
matplotlib=3.2.1 \
scipy=1.4.1 \
&& conda clean -y --all

View File

@@ -32,7 +32,6 @@ namespace QuantConnect.Lean.Engine.DataFeeds.Enumerators.Factories
/// <remarks>Only used on backtesting by the <see cref="FileSystemDataFeed"/></remarks>
public class SubscriptionDataReaderSubscriptionEnumeratorFactory : ISubscriptionEnumeratorFactory, IDisposable
{
private readonly bool _isLiveMode;
private readonly IResultHandler _resultHandler;
private readonly IFactorFileProvider _factorFileProvider;
private readonly IDataCacheProvider _dataCacheProvider;
@@ -40,7 +39,6 @@ namespace QuantConnect.Lean.Engine.DataFeeds.Enumerators.Factories
private readonly int _numericalPrecisionLimitedWarningsMaxCount = 10;
private readonly ConcurrentDictionary<Symbol, string> _startDateLimitedWarnings;
private readonly int _startDateLimitedWarningsMaxCount = 10;
private readonly Func<SubscriptionRequest, IEnumerable<DateTime>> _tradableDaysProvider;
private readonly IMapFileProvider _mapFileProvider;
private readonly bool _enablePriceScaling;
@@ -58,7 +56,6 @@ namespace QuantConnect.Lean.Engine.DataFeeds.Enumerators.Factories
IMapFileProvider mapFileProvider,
IFactorFileProvider factorFileProvider,
IDataCacheProvider cacheProvider,
Func<SubscriptionRequest, IEnumerable<DateTime>> tradableDaysProvider = null,
bool enablePriceScaling = true
)
{
@@ -68,8 +65,6 @@ namespace QuantConnect.Lean.Engine.DataFeeds.Enumerators.Factories
_dataCacheProvider = cacheProvider;
_numericalPrecisionLimitedWarnings = new ConcurrentDictionary<Symbol, string>();
_startDateLimitedWarnings = new ConcurrentDictionary<Symbol, string>();
_isLiveMode = false;
_tradableDaysProvider = tradableDaysProvider ?? (request => request.TradableDays);
_enablePriceScaling = enablePriceScaling;
}
@@ -82,12 +77,9 @@ namespace QuantConnect.Lean.Engine.DataFeeds.Enumerators.Factories
public IEnumerator<BaseData> CreateEnumerator(SubscriptionRequest request, IDataProvider dataProvider)
{
var dataReader = new SubscriptionDataReader(request.Configuration,
request.StartTimeLocal,
request.EndTimeLocal,
request,
_mapFileProvider,
_factorFileProvider,
_tradableDaysProvider(request),
_isLiveMode,
_dataCacheProvider,
dataProvider
);

View File

@@ -306,11 +306,22 @@ namespace QuantConnect.Lean.Engine.DataFeeds.Enumerators
// potentialBarEndTime should be calculated in the same way as bar.EndTime, i.e. Time + resolution
var potentialBarEndTime = RoundDown(item.ReferenceDateTime, item.Interval).ConvertToUtc(Exchange.TimeZone) + item.Interval;
var period = _dataResolution;
if (next.Time == next.EndTime)
{
// we merge corporate event data points (mapping, delisting, splits, dividend) which do not have
// a period or resolution
period = TimeSpan.Zero;
}
// to avoid duality it's necessary to compare potentialBarEndTime with
// next.EndTime calculated as Time + resolution,
// and both should be based on the same TZ (for example UTC)
var nextEndTimeUTC = next.Time.ConvertToUtc(Exchange.TimeZone) + _dataResolution;
if (potentialBarEndTime < nextEndTimeUTC)
var nextEndTimeUTC = next.Time.ConvertToUtc(Exchange.TimeZone) + period;
if (potentialBarEndTime < nextEndTimeUTC
// let's fill forward based on previous (which isn't auxiliary) if next is auxiliary and they share the end time
// we do allow emitting both an auxiliary data point and a Filled Forwared data for the same end time
|| next.DataType == MarketDataType.Auxiliary && potentialBarEndTime == nextEndTimeUTC)
{
// to check open hours we need to convert potential
// bar EndTime into exchange time zone

View File

@@ -16,8 +16,8 @@
using System;
using System.Linq;
using System.Collections;
using QuantConnect.Data;
using System.Collections;
using System.Globalization;
using QuantConnect.Logging;
using QuantConnect.Interfaces;
@@ -67,9 +67,6 @@ namespace QuantConnect.Lean.Engine.DataFeeds
private bool _pastDelistedDate;
// true if we're in live mode, false otherwise
private readonly bool _isLiveMode;
private BaseData _previous;
private decimal? _lastRawPrice;
private readonly IEnumerator<DateTime> _tradeableDates;
@@ -129,21 +126,15 @@ namespace QuantConnect.Lean.Engine.DataFeeds
/// Subscription data reader takes a subscription request, loads the type, accepts the data source and enumerate on the results.
/// </summary>
/// <param name="config">Subscription configuration object</param>
/// <param name="periodStart">Start date for the data request/backtest</param>
/// <param name="periodFinish">Finish date for the data request/backtest</param>
/// <param name="mapFileResolver">Used for resolving the correct map files</param>
/// <param name="dataRequest">The data request</param>
/// <param name="mapFileProvider">Used for resolving the correct map files</param>
/// <param name="factorFileProvider">Used for getting factor files</param>
/// <param name="dataCacheProvider">Used for caching files</param>
/// <param name="tradeableDates">Defines the dates for which we'll request data, in order, in the security's data time zone</param>
/// <param name="isLiveMode">True if we're in live mode, false otherwise</param>
/// <param name="dataProvider">The data provider to use</param>
public SubscriptionDataReader(SubscriptionDataConfig config,
DateTime periodStart,
DateTime periodFinish,
BaseDataRequest dataRequest,
IMapFileProvider mapFileProvider,
IFactorFileProvider factorFileProvider,
IEnumerable<DateTime> tradeableDates,
bool isLiveMode,
IDataCacheProvider dataCacheProvider,
IDataProvider dataProvider)
{
@@ -151,15 +142,14 @@ namespace QuantConnect.Lean.Engine.DataFeeds
_config = config;
//Save Start and End Dates:
_periodStart = periodStart;
_periodFinish = periodFinish;
_periodStart = dataRequest.StartTimeLocal;
_periodFinish = dataRequest.EndTimeLocal;
_mapFileProvider = mapFileProvider;
_factorFileProvider = factorFileProvider;
_dataCacheProvider = dataCacheProvider;
//Save access to securities
_isLiveMode = isLiveMode;
_tradeableDates = tradeableDates.GetEnumerator();
_tradeableDates = dataRequest.TradableDays.GetEnumerator();
_dataProvider = dataProvider;
}
@@ -217,7 +207,7 @@ namespace QuantConnect.Lean.Engine.DataFeeds
_factorFile = factorFile;
// if factor file has minimum date, update start period if before minimum date
if (!_isLiveMode && _factorFile != null && _factorFile.FactorFileMinimumDate.HasValue)
if (_factorFile != null && _factorFile.FactorFileMinimumDate.HasValue)
{
if (_periodStart < _factorFile.FactorFileMinimumDate.Value)
{
@@ -254,7 +244,6 @@ namespace QuantConnect.Lean.Engine.DataFeeds
// adding a day so we stop at EOD
_delistingDate = _delistingDate.AddDays(1);
UpdateDataEnumerator(true);
_initialized = true;
@@ -289,14 +278,6 @@ namespace QuantConnect.Lean.Engine.DataFeeds
if (_subscriptionFactoryEnumerator == null)
{
// in live mode the trade able dates will eventually advance to the next
if (_isLiveMode)
{
// HACK attack -- we don't want to block in live mode
Current = null;
return true;
}
_endOfStream = true;
return false;
}
@@ -343,6 +324,7 @@ namespace QuantConnect.Lean.Engine.DataFeeds
// if we move past our current 'date' then we need to do daily things, such
// as updating factors and symbol mapping
var shouldSkip = false;
while (instance.Time.ConvertTo(_config.ExchangeTimeZone, _config.DataTimeZone).Date > _tradeableDates.Current)
{
var currentTradeableDate = _tradeableDates.Current;
@@ -416,7 +398,7 @@ namespace QuantConnect.Lean.Engine.DataFeeds
// called on date changes, never return null for live mode, we'll always
// just keep trying to refresh the subscription
DateTime date;
if (!TryGetNextDate(out date) && !_isLiveMode)
if (!TryGetNextDate(out date))
{
_subscriptionFactoryEnumerator = null;
// if we run out of dates then we're finished with this subscription
@@ -424,12 +406,11 @@ namespace QuantConnect.Lean.Engine.DataFeeds
}
// fetch the new source, using the data time zone for the date
var newSource = _dataFactory.GetSource(_config, date, _isLiveMode);
var newSource = _dataFactory.GetSource(_config, date, false);
// check if we should create a new subscription factory
var sourceChanged = _source != newSource && newSource.Source != "";
var liveRemoteFile = _isLiveMode && (_source == null || _source.TransportMedium == SubscriptionTransportMedium.RemoteFile);
if (sourceChanged || liveRemoteFile)
if (sourceChanged)
{
// dispose of the current enumerator before creating a new one
Dispose();
@@ -457,7 +438,7 @@ namespace QuantConnect.Lean.Engine.DataFeeds
private ISubscriptionDataSourceReader CreateSubscriptionFactory(SubscriptionDataSource source, BaseData baseDataInstance, IDataProvider dataProvider)
{
var factory = SubscriptionDataSourceReader.ForSource(source, _dataCacheProvider, _config, _tradeableDates.Current, _isLiveMode, baseDataInstance, dataProvider);
var factory = SubscriptionDataSourceReader.ForSource(source, _dataCacheProvider, _config, _tradeableDates.Current, false, baseDataInstance, dataProvider);
AttachEventHandlers(factory, source);
return factory;
}
@@ -521,13 +502,6 @@ namespace QuantConnect.Lean.Engine.DataFeeds
/// <returns>True if we got a new date from the enumerator, false if it's exhausted, or in live mode if we're already at today</returns>
private bool TryGetNextDate(out DateTime date)
{
if (_isLiveMode && _tradeableDates.Current >= DateTime.Today)
{
// special behavior for live mode, don't advance past today
date = _tradeableDates.Current;
return false;
}
while (_tradeableDates.MoveNext())
{
date = _tradeableDates.Current;

View File

@@ -80,7 +80,7 @@ namespace QuantConnect.Lean.Engine.HistoricalData
var subscriptions = new List<Subscription>();
foreach (var request in requests)
{
var subscription = CreateSubscription(request, request.StartTimeUtc, request.EndTimeUtc);
var subscription = CreateSubscription(request);
subscriptions.Add(subscription);
}
@@ -90,14 +90,10 @@ namespace QuantConnect.Lean.Engine.HistoricalData
/// <summary>
/// Creates a subscription to process the request
/// </summary>
private Subscription CreateSubscription(HistoryRequest request, DateTime startUtc, DateTime endUtc)
private Subscription CreateSubscription(HistoryRequest request)
{
// data reader expects these values in local times
var startTimeLocal = startUtc.ConvertFromUtc(request.ExchangeHours.TimeZone);
var endTimeLocal = endUtc.ConvertFromUtc(request.ExchangeHours.TimeZone);
var config = request.ToSubscriptionDataConfig();
DataPermissionManager.AssertConfiguration(config, startTimeLocal, endTimeLocal);
DataPermissionManager.AssertConfiguration(config, request.StartTimeLocal, request.EndTimeLocal);
var security = new Security(
request.ExchangeHours,
@@ -109,16 +105,10 @@ namespace QuantConnect.Lean.Engine.HistoricalData
new SecurityCache()
);
// Tradable dates are defined with the data time zone to access the right source
var tradableDates = Time.EachTradeableDayInTimeZone(request.ExchangeHours, startTimeLocal, endTimeLocal, request.DataTimeZone, request.IncludeExtendedMarketHours);
var dataReader = new SubscriptionDataReader(config,
startTimeLocal,
endTimeLocal,
request,
_mapFileProvider,
_factorFileProvider,
tradableDates,
false,
_dataCacheProvider,
_dataProvider
);
@@ -143,7 +133,7 @@ namespace QuantConnect.Lean.Engine.HistoricalData
_factorFileProvider,
dataReader,
_mapFileProvider,
startTimeLocal);
request.StartTimeLocal);
// optionally apply fill forward behavior
if (request.FillForwardResolution.HasValue)
@@ -155,7 +145,7 @@ namespace QuantConnect.Lean.Engine.HistoricalData
}
var readOnlyRef = Ref.CreateReadOnly(() => request.FillForwardResolution.Value.ToTimeSpan());
reader = new FillForwardEnumerator(reader, security.Exchange, readOnlyRef, request.IncludeExtendedMarketHours, endTimeLocal, config.Increment, config.DataTimeZone);
reader = new FillForwardEnumerator(reader, security.Exchange, readOnlyRef, request.IncludeExtendedMarketHours, request.EndTimeLocal, config.Increment, config.DataTimeZone);
}
// since the SubscriptionDataReader performs an any overlap condition on the trade bar's entire
@@ -163,7 +153,7 @@ namespace QuantConnect.Lean.Engine.HistoricalData
// so to combat this we deliberately filter the results from the data reader to fix these cases
// which only apply to non-tick data
reader = new SubscriptionFilterEnumerator(reader, security, endTimeLocal, config.ExtendedMarketHours, false, request.ExchangeHours);
reader = new SubscriptionFilterEnumerator(reader, security, request.EndTimeLocal, config.ExtendedMarketHours, false, request.ExchangeHours);
reader = new FilterEnumerator<BaseData>(reader, data =>
{
// allow all ticks
@@ -171,9 +161,9 @@ namespace QuantConnect.Lean.Engine.HistoricalData
// filter out all aux data
if (data.DataType == MarketDataType.Auxiliary) return false;
// filter out future data
if (data.EndTime > endTimeLocal) return false;
if (data.EndTime > request.EndTimeLocal) return false;
// filter out data before the start
return data.EndTime > startTimeLocal;
return data.EndTime > request.StartTimeLocal;
});
var subscriptionRequest = new SubscriptionRequest(false, null, security, config, request.StartTimeUtc, request.EndTimeUtc);
if (_parallelHistoryRequestsEnabled)

View File

@@ -1,4 +1,4 @@
/*
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
@@ -203,7 +203,7 @@ namespace QuantConnect.Lean.Engine.Storage
// Before saving confirm we are abiding by the control rules
// Start by counting our file and its length
var fileCount = 1;
var expectedStorageSizeBytes = contents.Length;
var expectedStorageSizeBytes = contents?.Length ?? 0;
foreach (var kvp in _storage)
{
if (key.Equals(kvp.Key))
@@ -214,7 +214,10 @@ namespace QuantConnect.Lean.Engine.Storage
else
{
fileCount++;
expectedStorageSizeBytes += kvp.Value.Length;
if(kvp.Value != null)
{
expectedStorageSizeBytes += kvp.Value.Length;
}
}
}
@@ -277,6 +280,8 @@ namespace QuantConnect.Lean.Engine.Storage
/// <summary>
/// Returns the file path for the specified key
/// </summary>
/// <remarks>If the key is not already inserted it will just return a path associated with it
/// and add the key with null value</remarks>
/// <param name="key">The object key</param>
/// <returns>The path for the file</returns>
public virtual string GetFilePath(string key)
@@ -284,13 +289,15 @@ namespace QuantConnect.Lean.Engine.Storage
// Ensure we have an object for that key
if (!ContainsKey(key))
{
throw new KeyNotFoundException($"Object with key '{key}' was not found in the current project. " +
"Please use ObjectStore.ContainsKey(key) to check if an object exists before attempting to read."
);
// Add a key with null value to tell Persist() not to delete the file created in the path associated
// with this key and not update it with the value associated with the key(null)
SaveBytes(key, null);
}
else
{
// Persist to ensure pur files are up to date
Persist();
}
// Persist to ensure pur files are up to date
Persist();
// Fetch the path to file and return it
return PathForKey(key);
@@ -414,9 +421,13 @@ namespace QuantConnect.Lean.Engine.Storage
// Write all our store data to disk
foreach (var kvp in data)
{
// Get a path for this key and write to it
var path = PathForKey(kvp.Key);
File.WriteAllBytes(path, kvp.Value);
// Skip the key associated with null values. They are not linked to a file yet
if (kvp.Value != null)
{
// Get a path for this key and write to it
var path = PathForKey(kvp.Key);
File.WriteAllBytes(path, kvp.Value);
}
}
return true;

View File

@@ -1012,26 +1012,6 @@ namespace QuantConnect.Lean.Engine.TransactionHandlers
order.Tag += " - " + orderEvent.Message;
}
}
if (_algorithm.BrokerageModel.AccountType == AccountType.Cash
&& order.Direction == OrderDirection.Buy
&& CurrencyPairUtil.TryDecomposeCurrencyPair(orderEvent.Symbol, out var baseCurrency, out _)
&& orderEvent.OrderFee.Value.Currency == baseCurrency)
{
// fees are in the base currency, so we have to subtract them from the filled quantity
// else the virtual position will bigger than the real size and we might no be able to liquidate
orderEvent.FillQuantity -= orderEvent.OrderFee.Value.Amount;
orderEvent.OrderFee = new ModifiedFillQuantityOrderFee(orderEvent.OrderFee.Value);
if (!_loggedFeeAdjustmentWarning)
{
_loggedFeeAdjustmentWarning = true;
const string message = "When buying currency pairs, using Cash account types, fees in base currency" +
" will be deducted from the filled quantity so virtual positions reflect actual holdings.";
Log.Trace($"BrokerageTransactionHandler.HandleOrderEvent(): {message}");
_algorithm.Debug(message);
}
}
break;
case OrderStatus.UpdateSubmitted:
@@ -1076,15 +1056,26 @@ namespace QuantConnect.Lean.Engine.TransactionHandlers
// check if the fill currency and the order currency match the symbol currency
var security = _algorithm.Securities[orderEvent.Symbol];
// Bug in FXCM API flipping the currencies -- disabling for now. 5/17/16 RFB
//if (fill.FillPriceCurrency != security.SymbolProperties.QuoteCurrency)
//{
// Log.Error(string.Format("Currency mismatch: Fill currency: {0}, Symbol currency: {1}", fill.FillPriceCurrency, security.SymbolProperties.QuoteCurrency));
//}
//if (order.PriceCurrency != security.SymbolProperties.QuoteCurrency)
//{
// Log.Error(string.Format("Currency mismatch: Order currency: {0}, Symbol currency: {1}", order.PriceCurrency, security.SymbolProperties.QuoteCurrency));
//}
if (_algorithm.BrokerageModel.AccountType == AccountType.Cash
&& order.Direction == OrderDirection.Buy
&& CurrencyPairUtil.TryDecomposeCurrencyPair(orderEvent.Symbol, out var baseCurrency, out var quoteCurrency)
&& orderEvent.OrderFee.Value.Currency == baseCurrency)
{
// fees are in the base currency, so we have to subtract them from the filled quantity
// else the virtual position will bigger than the real size and we might no be able to liquidate
orderEvent.FillQuantity -= orderEvent.OrderFee.Value.Amount;
orderEvent.OrderFee = new ModifiedFillQuantityOrderFee(orderEvent.OrderFee.Value, quoteCurrency, security.SymbolProperties.ContractMultiplier);
if (!_loggedFeeAdjustmentWarning)
{
_loggedFeeAdjustmentWarning = true;
const string message = "When buying currency pairs, using Cash account types, fees in base currency" +
" will be deducted from the filled quantity so virtual positions reflect actual holdings.";
Log.Trace($"BrokerageTransactionHandler.HandleOrderEvent(): {message}");
_algorithm.Debug(message);
}
}
var multiplier = security.SymbolProperties.ContractMultiplier;
var securityConversionRate = security.QuoteCurrency.ConversionRate;
@@ -1183,10 +1174,14 @@ namespace QuantConnect.Lean.Engine.TransactionHandlers
{
if (_algorithm.Securities.TryGetValue(e.Symbol, out var security))
{
Log.Trace(
"BrokerageTransactionHandler.HandleDelistingNotification(): clearing position for delisted holding: " +
$"Symbol: {e.Symbol.Value}, " +
$"Quantity: {security.Holdings.Quantity}");
// only log always in live trading, in backtesting log if not 0 holdings
if (_algorithm.LiveMode || security.Holdings.Quantity != 0)
{
Log.Trace(
$"BrokerageTransactionHandler.HandleDelistingNotification(): UtcTime: {CurrentTimeUtc} clearing position for delisted holding: " +
$"Symbol: {e.Symbol.Value}, " +
$"Quantity: {security.Holdings.Quantity}");
}
// Only submit an order if we have holdings
var quantity = -security.Holdings.Quantity;
@@ -1232,7 +1227,7 @@ namespace QuantConnect.Lean.Engine.TransactionHandlers
if (_algorithm.LiveMode || security.Holdings.Quantity != 0)
{
Log.Trace(
"BrokerageTransactionHandler.HandleOptionNotification(): clearing position for expired option holding: " +
$"BrokerageTransactionHandler.HandleOptionNotification(): UtcTime: {CurrentTimeUtc} clearing position for expired option holding: " +
$"Symbol: {e.Symbol.Value}, " +
$"Holdings: {security.Holdings.Quantity}");
}

View File

@@ -12,6 +12,7 @@
<OutputPath>bin\$(Configuration)\</OutputPath>
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<ServerGarbageCollection>true</ServerGarbageCollection>
<Description>QuantConnect LEAN Engine: Launcher Project - Main startup executable for live and backtesting</Description>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">

View File

@@ -152,6 +152,15 @@
"tt-order-routing-port": "",
"tt-log-fix-messages": false,
// Exante trading configuration
// client-id, application-id, shared-key are required to access Exante REST API
// Exante generates them at https://exante.eu/clientsarea/dashboard/ after adding an application
"exante-client-id": "",
"exante-application-id": "",
"exante-shared-key": "",
"exante-account-id": "", // Account-id is assigned after registration at Exante
"exante-platform-type": "", // Environment of the application: live or demo
// Required to access data from Nasdaq
// To get your access token go to https://data.nasdaq.com/account/profile
"nasdaq-auth-token": "",
@@ -451,6 +460,20 @@
"transaction-handler": "QuantConnect.Lean.Engine.TransactionHandlers.BrokerageTransactionHandler",
"history-provider": "BrokerageHistoryProvider"
},
"live-exante": {
"live-mode": true,
// real brokerage implementations require the BrokerageTransactionHandler
"live-mode-brokerage": "QuantConnect.ExanteBrokerage.ExanteBrokerage",
"data-queue-handler": [ "QuantConnect.ExanteBrokerage.ExanteBrokerage" ],
"setup-handler": "QuantConnect.Lean.Engine.Setup.BrokerageSetupHandler",
"result-handler": "QuantConnect.Lean.Engine.Results.LiveTradingResultHandler",
"data-feed-handler": "QuantConnect.Lean.Engine.DataFeeds.LiveTradingDataFeed",
"real-time-handler": "QuantConnect.Lean.Engine.RealTime.LiveTradingRealTimeHandler",
"transaction-handler": "QuantConnect.Lean.Engine.TransactionHandlers.BrokerageTransactionHandler",
"history-provider": "BrokerageHistoryProvider"
},
// defines the 'live-ftxus' environment
"live-ftxus": {

View File

@@ -15,11 +15,15 @@
using System;
using NodaTime;
using System.IO;
using System.Linq;
using Python.Runtime;
using NUnit.Framework;
using QuantConnect.Data;
using QuantConnect.Util;
using QuantConnect.Python;
using QuantConnect.Algorithm;
using QuantConnect.Securities;
using QuantConnect.Interfaces;
using QuantConnect.Data.Market;
using System.Collections.Generic;
@@ -27,7 +31,6 @@ using QuantConnect.Lean.Engine.DataFeeds;
using QuantConnect.Tests.Engine.DataFeeds;
using QuantConnect.Data.Custom.AlphaStreams;
using QuantConnect.Lean.Engine.HistoricalData;
using QuantConnect.Securities;
using HistoryRequest = QuantConnect.Data.HistoryRequest;
namespace QuantConnect.Tests.Algorithm
@@ -262,6 +265,60 @@ namespace QuantConnect.Tests.Algorithm
Assert.AreEqual(1, lastKnownPrices.Count(data => data.GetType() == typeof(QuoteBar)));
}
[TestCase(Language.CSharp)]
[TestCase(Language.Python)]
public void GetLastKnownPricesCustomData(Language language)
{
var algorithm = GetAlgorithm(new DateTime(2013, 10, 8));
Symbol symbol;
if (language == Language.CSharp)
{
symbol = algorithm.AddData<CustomData>("SPY").Symbol;
}
else
{
using (Py.GIL())
{
var customDataType = PythonEngine.ModuleFromString("testModule",
@"
from AlgorithmImports import *
from QuantConnect.Tests import *
class Test(PythonData):
def GetSource(self, config, date, isLiveMode):
fileName = LeanData.GenerateZipFileName(Symbols.SPY, date, config.Resolution, config.TickType)
source = f'{Globals.DataFolder}equity/usa/minute/spy/{fileName}'
return SubscriptionDataSource(source, SubscriptionTransportMedium.LocalFile, FileFormat.Csv)
def Reader(self, config, line, date, isLiveMode):
data = line.split(',')
result = Test()
result.DataType = MarketDataType.Base
result.Symbol = config.Symbol
result.Time = date + timedelta(milliseconds=int(data[0]))
result.Value = 1
return result
").GetAttr("Test");
symbol = algorithm.AddData(customDataType, "SPY").Symbol;
}
}
var lastKnownPrices = algorithm.GetLastKnownPrices(symbol).ToList();
Assert.AreEqual(1, lastKnownPrices.Count);
if (language == Language.CSharp)
{
Assert.AreEqual(1, lastKnownPrices.Count(data => data.GetType() == typeof(CustomData)));
}
else
{
Assert.AreEqual(1, lastKnownPrices.Count(data => data.GetType() == typeof(PythonData)));
}
}
[Test]
public void GetLastKnownPriceEquity()
{
@@ -428,5 +485,27 @@ namespace QuantConnect.Tests.Algorithm
return Slices.Where(x => x.Time >= startTime && x.Time <= endTime).ToList();
}
}
public class CustomData : TradeBar
{
public override SubscriptionDataSource GetSource(SubscriptionDataConfig config, DateTime date, bool isLiveMode)
{
var source = Path.Combine(Globals.DataFolder, "equity", "usa", config.Resolution.ToString().ToLower(),
Symbols.SPY.Value.ToLowerInvariant(), LeanData.GenerateZipFileName(Symbols.SPY, date, config.Resolution, config.TickType));
return new SubscriptionDataSource(source, SubscriptionTransportMedium.LocalFile, FileFormat.Csv);
}
public override BaseData Reader(SubscriptionDataConfig config, string line, DateTime date, bool isLiveMode)
{
var baseData = base.Reader(new SubscriptionDataConfig(config, symbol: Symbols.SPY), line, date, isLiveMode);
return new CustomData
{
DataType = MarketDataType.Base,
Symbol = config.Symbol,
Time = baseData.EndTime,
Value = baseData.Price
};
}
}
}
}

View File

@@ -0,0 +1,99 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using Moq;
using NUnit.Framework;
using QuantConnect.Brokerages;
using QuantConnect.Brokerages.Binance;
using QuantConnect.Configuration;
using QuantConnect.Interfaces;
using QuantConnect.Lean.Engine.DataFeeds;
using QuantConnect.Securities;
using QuantConnect.Tests.Common.Securities;
using System;
using QuantConnect.Util;
namespace QuantConnect.Tests.Brokerages.Binance
{
[TestFixture, Explicit("This test requires a configured and testable Binance practice account")]
public class BinanceBrokerageAdditionalTests
{
[Test]
public void ParameterlessConstructorComposerUsage()
{
var brokerage = Composer.Instance.GetExportedValueByTypeName<IDataQueueHandler>("BinanceBrokerage");
Assert.IsNotNull(brokerage);
Assert.True(brokerage.IsConnected);
}
[Test]
public void ConnectedIfNoAlgorithm()
{
using var brokerage = CreateBrokerage(null);
Assert.True(brokerage.IsConnected);
}
[Test]
public void ConnectedIfAlgorithmIsNotNullAndClientNotCreated()
{
using var brokerage = CreateBrokerage(Mock.Of<IAlgorithm>());
Assert.True(brokerage.IsConnected);
}
[Test]
public void ConnectToUserDataStreamIfAlgorithmNotNullAndApiIsCreated()
{
var securities = new SecurityManager(new TimeKeeper(DateTime.UtcNow, TimeZones.NewYork));
var transactions = new SecurityTransactionManager(null, securities);
transactions.SetOrderProcessor(new FakeOrderProcessor());
var algorithm = new Mock<IAlgorithm>();
algorithm.Setup(a => a.Transactions).Returns(transactions);
algorithm.Setup(a => a.BrokerageModel).Returns(new BinanceBrokerageModel());
algorithm.Setup(a => a.Portfolio).Returns(new SecurityPortfolioManager(securities, transactions));
using var brokerage = CreateBrokerage(algorithm.Object);
Assert.True(brokerage.IsConnected);
var _ = brokerage.GetCashBalance();
Assert.True(brokerage.IsConnected);
brokerage.Disconnect();
Assert.False(brokerage.IsConnected);
}
private static Brokerage CreateBrokerage(IAlgorithm algorithm)
{
var apiKey = Config.Get("binance-api-key");
var apiSecret = Config.Get("binance-api-secret");
var apiUrl = Config.Get("binance-api-url", "https://api.binance.com");
var websocketUrl = Config.Get("binance-websocket-url", "wss://stream.binance.com:9443/ws");
return new BinanceBrokerage(
apiKey,
apiSecret,
apiUrl,
websocketUrl,
algorithm,
new AggregationManager(),
null
);
}
}
}

View File

@@ -0,0 +1,97 @@
/*
* 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 NUnit.Framework;
using QuantConnect.Brokerages.Binance;
using QuantConnect.Data;
using QuantConnect.Data.Market;
using QuantConnect.Interfaces;
using QuantConnect.Logging;
using QuantConnect.Util;
using System.Threading;
namespace QuantConnect.Tests.Brokerages.Binance
{
[TestFixture]
public partial class BinanceBrokerageTests
{
private static readonly Symbol XRP_USDT = Symbol.Create("XRPUSDT", SecurityType.Crypto, Market.FTX);
private static TestCaseData[] TestParameters
{
get
{
return new[]
{
// valid parameters, for example
new TestCaseData(XRP_USDT, Resolution.Tick, false),
new TestCaseData(XRP_USDT, Resolution.Minute, false),
new TestCaseData(XRP_USDT, Resolution.Second, false),
};
}
}
[Test, TestCaseSource(nameof(TestParameters))]
public void StreamsData(Symbol symbol, Resolution resolution, bool throwsException)
{
var cancelationToken = new CancellationTokenSource();
var brokerage = (BinanceBrokerage)Brokerage;
SubscriptionDataConfig[] configs;
if (resolution == Resolution.Tick)
{
var tradeConfig = new SubscriptionDataConfig(GetSubscriptionDataConfig<Tick>(symbol, resolution),
tickType: TickType.Trade);
var quoteConfig = new SubscriptionDataConfig(GetSubscriptionDataConfig<Tick>(symbol, resolution),
tickType: TickType.Quote);
configs = new[] { tradeConfig, quoteConfig };
}
else
{
configs = new[]
{
GetSubscriptionDataConfig<QuoteBar>(symbol, resolution),
GetSubscriptionDataConfig<TradeBar>(symbol, resolution)
};
}
foreach (var config in configs)
{
ProcessFeed(brokerage.Subscribe(config, (s, e) =>
{
}),
cancelationToken,
(baseData) =>
{
if (baseData != null)
{
Log.Trace("{baseData}");
}
});
}
Thread.Sleep(20000);
foreach (var config in configs)
{
brokerage.Unsubscribe(config);
}
Thread.Sleep(20000);
cancelationToken.Cancel();
}
}
}

View File

@@ -33,7 +33,7 @@ namespace QuantConnect.Tests.Brokerages.Binance
[TestFixture, Explicit("This test requires a configured and testable Binance practice account")]
public partial class BinanceBrokerageTests : BrokerageTests
{
private BinanceRestApiClient _binanceApi;
private BinanceBaseRestApiClient _binanceApi;
/// <summary>
/// Creates the brokerage under test and connects it
@@ -53,6 +53,7 @@ namespace QuantConnect.Tests.Brokerages.Binance
var algorithm = new Mock<IAlgorithm>();
algorithm.Setup(a => a.Transactions).Returns(transactions);
algorithm.Setup(a => a.Securities).Returns(securities);
algorithm.Setup(a => a.BrokerageModel).Returns(new BinanceBrokerageModel());
algorithm.Setup(a => a.Portfolio).Returns(new SecurityPortfolioManager(securities, transactions));
@@ -61,7 +62,7 @@ namespace QuantConnect.Tests.Brokerages.Binance
var apiUrl = Config.Get("binance-api-url", "https://api.binance.com");
var websocketUrl = Config.Get("binance-websocket-url", "wss://stream.binance.com:9443/ws");
_binanceApi = new BinanceRestApiClient(
_binanceApi = new BinanceSpotRestApiClient(
new SymbolPropertiesDatabaseSymbolMapper(Market.Binance),
algorithm.Object?.Portfolio,
apiKey,

View 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 System.Linq;
using Newtonsoft.Json;
using NUnit.Framework;
using QuantConnect.Brokerages.Binance.Messages;
namespace QuantConnect.Tests.Brokerages.Binance
{
[TestFixture]
public class MarginAccountConverterTests
{
[Test]
public void DeserializeJson()
{
var json = @"{
""borrowEnabled"": true,
""marginLevel"": ""11.64405625"",
""totalAssetOfBtc"": ""6.82728457"",
""totalLiabilityOfBtc"": ""0.58633215"",
""totalNetAssetOfBtc"": ""6.24095242"",
""tradeEnabled"": true,
""transferEnabled"": true,
""userAssets"": [
{
""asset"": ""BTC"",
""borrowed"": ""0.00000000"",
""free"": ""0.00499500"",
""interest"": ""0.00000000"",
""locked"": ""0.00000000"",
""netAsset"": ""0.00499500""
},
{
""asset"": ""BNB"",
""borrowed"": ""201.66666672"",
""free"": ""2346.50000000"",
""interest"": ""0.00000000"",
""locked"": ""0.00000000"",
""netAsset"": ""2144.83333328""
},
{
""asset"": ""ETH"",
""borrowed"": ""0.00000000"",
""free"": ""0.00000000"",
""interest"": ""0.00000000"",
""locked"": ""0.00000000"",
""netAsset"": ""0.00000000""
},
{
""asset"": ""USDT"",
""borrowed"": ""0.00000000"",
""free"": ""0.00000000"",
""interest"": ""0.00000000"",
""locked"": ""0.00000000"",
""netAsset"": ""0.00000000""
}
]
}";
var balances = JsonConvert.DeserializeObject<AccountInformation>(json, new MarginAccountConverter()).Balances
.Cast<MarginBalance>()
.ToArray();
Assert.AreEqual(4, balances.Length);
var bnb = balances.FirstOrDefault(a => a.Asset == "BNB");
Assert.NotNull(bnb);
Assert.AreEqual(201.66666672m, bnb.Borrowed);
Assert.AreEqual(2144.83333328m, bnb.NetAsset);
Assert.AreEqual(bnb.NetAsset, bnb.Amount);
}
}
}

View File

@@ -0,0 +1,68 @@
/*
* 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.Linq;
using Newtonsoft.Json;
using NUnit.Framework;
using QuantConnect.Brokerages.Binance.Messages;
namespace QuantConnect.Tests.Brokerages.Binance
{
[TestFixture]
public class SpotAccountConverterTests
{
[Test]
public void DeserializeJson()
{
var json = @"{
""makerCommission"": 15,
""takerCommission"": 15,
""buyerCommission"": 0,
""sellerCommission"": 0,
""canTrade"": true,
""canWithdraw"": true,
""canDeposit"": true,
""updateTime"": 123456789,
""accountType"": ""SPOT"",
""balances"": [
{
""asset"": ""BTC"",
""free"": ""4723846.89208129"",
""locked"": ""0.00000000""
},
{
""asset"": ""LTC"",
""free"": ""4763368.68006011"",
""locked"": ""1.00000000""
}
],
""permissions"": [
""SPOT""
]
}";
var balances = JsonConvert.DeserializeObject<AccountInformation>(json, new SpotAccountConverter()).Balances
.Cast<SpotBalance>()
.ToArray();
Assert.AreEqual(2, balances.Length);
var bnb = balances.FirstOrDefault(a => a.Asset == "LTC");
Assert.NotNull(bnb);
Assert.AreEqual(4763368.68006011m, bnb.Free);
Assert.AreEqual(1m, bnb.Locked);
Assert.AreEqual(bnb.Free + bnb.Locked, bnb.Amount);
}
}
}

View File

@@ -0,0 +1,157 @@
/*
* 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 NUnit.Framework;
using QuantConnect.Brokerages;
using QuantConnect.Data;
using QuantConnect.Data.Market;
using QuantConnect.Orders;
using QuantConnect.Orders.Fees;
using QuantConnect.Securities;
using System;
namespace QuantConnect.Tests.Brokerages.Exante
{
[TestFixture]
public class ExanteFeeModelTests
{
private static decimal HighPrice => 1000m;
private static decimal LowPrice => 100m;
private static decimal Quantity => 1m;
private static Symbol Symbol => Symbols.SPY;
private static OrderSubmissionData OrderSubmissionData =>
new(Security.BidPrice, Security.AskPrice, (Security.BidPrice + Security.AskPrice) / 2);
private static Security Security
{
get
{
var security = new Security(
SecurityExchangeHours.AlwaysOpen(TimeZones.NewYork),
new SubscriptionDataConfig(
typeof(TradeBar),
Symbol,
Resolution.Minute,
TimeZones.NewYork,
TimeZones.NewYork,
false,
false,
false
),
new Cash("USD", 0, 1m),
SymbolProperties.GetDefault("USD"),
ErrorCurrencyConverter.Instance,
RegisteredSecurityDataTypesProvider.Null,
new SecurityCache()
);
security.SetMarketPrice(new Tick(DateTime.UtcNow, Symbol, LowPrice, HighPrice));
return security;
}
}
[Test]
public static void GetFeeModelTest()
{
var model = new ExanteBrokerageModel();
Assert.IsInstanceOf<ExanteFeeModel>(model.GetFeeModel(Security));
}
private static TestCaseData[] MakerOrders => new[]
{
new TestCaseData(new LimitOrderTestParameters(Symbol, HighPrice, LowPrice)),
new TestCaseData(new LimitOrderTestParameters(Symbol, HighPrice, LowPrice)
{ OrderSubmissionData = OrderSubmissionData }),
new TestCaseData(new LimitOrderTestParameters(Symbol, HighPrice, LowPrice, new OrderProperties())),
new TestCaseData(
new LimitOrderTestParameters(Symbol, LowPrice, HighPrice,
new OrderProperties()) { OrderSubmissionData = OrderSubmissionData }),
new TestCaseData(new LimitOrderTestParameters(Symbol, HighPrice, LowPrice, new OrderProperties()))
};
private static TestCaseData[] TakerOrders => new[]
{
new TestCaseData(new MarketOrderTestParameters(Symbol)),
new TestCaseData(new MarketOrderTestParameters(Symbol, new OrderProperties())),
new TestCaseData(new LimitOrderTestParameters(Symbol, LowPrice, HighPrice)
{ OrderSubmissionData = OrderSubmissionData })
};
[Test]
[TestCaseSource(nameof(MakerOrders))]
public void ReturnShortOrderMakerFees(OrderTestParameters parameters)
{
IFeeModel feeModel = new ExanteFeeModel();
var order = parameters.CreateShortOrder(Quantity);
var fee = feeModel.GetOrderFee(new OrderFeeParameters(Security, order));
Assert.AreEqual(
ExanteFeeModel.MarketUsaRate * Math.Abs(Quantity),
fee.Value.Amount
);
Assert.AreEqual(Currencies.USD, fee.Value.Currency);
}
[Test]
[TestCaseSource(nameof(TakerOrders))]
public void ReturnShortOrderTakerFees(OrderTestParameters parameters)
{
IFeeModel feeModel = new ExanteFeeModel();
var order = parameters.CreateShortOrder(Quantity);
var fee = feeModel.GetOrderFee(new OrderFeeParameters(Security, order));
Assert.AreEqual(
ExanteFeeModel.MarketUsaRate * Math.Abs(Quantity),
fee.Value.Amount
);
Assert.AreEqual(Currencies.USD, fee.Value.Currency);
}
[Test]
[TestCaseSource(nameof(MakerOrders))]
public void ReturnLongOrderMakerFees(OrderTestParameters parameters)
{
IFeeModel feeModel = new ExanteFeeModel();
var order = parameters.CreateLongOrder(Quantity);
var fee = feeModel.GetOrderFee(new OrderFeeParameters(Security, order));
Assert.AreEqual(
ExanteFeeModel.MarketUsaRate * Math.Abs(Quantity),
fee.Value.Amount
);
Assert.AreEqual(Currencies.USD, fee.Value.Currency);
}
[Test]
[TestCaseSource(nameof(TakerOrders))]
public void ReturnLongOrderTakerFees(OrderTestParameters parameters)
{
IFeeModel feeModel = new ExanteFeeModel();
var order = parameters.CreateLongOrder(Quantity);
var fee = feeModel.GetOrderFee(new OrderFeeParameters(Security, order));
Assert.AreEqual(
ExanteFeeModel.MarketUsaRate * Math.Abs(Quantity),
fee.Value.Amount
);
Assert.AreEqual(Currencies.USD, fee.Value.Currency);
}
}
}

View File

@@ -81,6 +81,10 @@ namespace QuantConnect.Tests.Brokerages.InteractiveBrokers
"ZS",
"ZT",
"ZW",
"2YY",
"5YY",
"10Y",
"30Y"
}
},
{
@@ -88,21 +92,28 @@ namespace QuantConnect.Tests.Brokerages.InteractiveBrokers
new[]
{
"6A",
"M6A",
"6B",
"M6B",
"6C",
"M6C",
"6E",
"M6E",
"6J",
"M6J",
"6L",
"6M",
"6N",
"6R",
"6S",
"M6S",
"6Z",
//"ACD",
//"AJY",
//"ANE",
"BIO",
"BTC",
"MicroBTC",
"CB",
//"CJY",
//"CNH",
@@ -115,6 +126,7 @@ namespace QuantConnect.Tests.Brokerages.InteractiveBrokers
//"EI",
"EMD",
"ES",
"MES",
//"ESK",
"GD",
"GDK",
@@ -128,7 +140,9 @@ namespace QuantConnect.Tests.Brokerages.InteractiveBrokers
"LE",
"NKD",
"NQ",
"MicroNQ",
"RTY",
"M2K"
}
},
{
@@ -138,8 +152,10 @@ namespace QuantConnect.Tests.Brokerages.InteractiveBrokers
//"AUP",
//"EDP",
"GC",
"MGC",
"HG",
"SI",
"SIL"
}
},
{
@@ -232,6 +248,15 @@ namespace QuantConnect.Tests.Brokerages.InteractiveBrokers
"PL",
"RB",
//"YO",
"M1B",
"M35",
"M5F",
"MAF",
"MCL",
"MEF",
"PAM",
"R5O",
"S5O"
}
}
};

View File

@@ -28,9 +28,10 @@ namespace QuantConnect.Tests.Brokerages
Symbol symbol,
decimal highLimit,
decimal lowLimit,
IOrderProperties properties = null
IOrderProperties properties = null,
OrderSubmissionData orderSubmissionData = null
)
: base(symbol, properties)
: base(symbol, properties, orderSubmissionData)
{
_highLimit = highLimit;
_lowLimit = lowLimit;

View File

@@ -24,8 +24,8 @@ namespace QuantConnect.Tests.Brokerages
private readonly decimal _highLimit;
private readonly decimal _lowLimit;
public LimitOrderTestParameters(Symbol symbol, decimal highLimit, decimal lowLimit, IOrderProperties properties = null)
: base(symbol, properties)
public LimitOrderTestParameters(Symbol symbol, decimal highLimit, decimal lowLimit, IOrderProperties properties = null, OrderSubmissionData orderSubmissionData = null)
: base(symbol, properties, orderSubmissionData)
{
_highLimit = highLimit;
_lowLimit = lowLimit;
@@ -81,4 +81,4 @@ namespace QuantConnect.Tests.Brokerages
public override bool ModifyUntilFilled => false;
}
}
}

View File

@@ -21,8 +21,8 @@ namespace QuantConnect.Tests.Brokerages
{
public class MarketOrderTestParameters : OrderTestParameters
{
public MarketOrderTestParameters(Symbol symbol, IOrderProperties properties = null)
: base(symbol, properties)
public MarketOrderTestParameters(Symbol symbol, IOrderProperties properties = null, OrderSubmissionData orderSubmissionData = null)
: base(symbol, properties, orderSubmissionData)
{
}
@@ -54,4 +54,4 @@ namespace QuantConnect.Tests.Brokerages
public override bool ExpectedCancellationResult => false;
}
}
}

View File

@@ -29,11 +29,12 @@ namespace QuantConnect.Tests.Brokerages
public IOrderProperties Properties { get; private set; }
public OrderSubmissionData OrderSubmissionData { get; internal set; }
protected OrderTestParameters(Symbol symbol, IOrderProperties properties = null)
protected OrderTestParameters(Symbol symbol, IOrderProperties properties = null, OrderSubmissionData orderSubmissionData = null)
{
Symbol = symbol;
SecurityType = symbol.ID.SecurityType;
Properties = properties;
OrderSubmissionData = orderSubmissionData;
}
public MarketOrder CreateLongMarketOrder(decimal quantity)
@@ -76,9 +77,6 @@ namespace QuantConnect.Tests.Brokerages
/// <summary>
/// True to continue modifying the order until it is filled, false otherwise
/// </summary>
public virtual bool ModifyUntilFilled
{
get { return true; }
}
public virtual bool ModifyUntilFilled => true;
}
}
}

View File

@@ -24,8 +24,8 @@ namespace QuantConnect.Tests.Brokerages
private readonly decimal _highLimit;
private readonly decimal _lowLimit;
public StopLimitOrderTestParameters(Symbol symbol, decimal highLimit, decimal lowLimit, IOrderProperties properties = null)
: base(symbol, properties)
public StopLimitOrderTestParameters(Symbol symbol, decimal highLimit, decimal lowLimit, IOrderProperties properties = null, OrderSubmissionData orderSubmissionData = null)
: base(symbol, properties, orderSubmissionData)
{
_highLimit = highLimit;
_lowLimit = lowLimit;
@@ -94,4 +94,4 @@ namespace QuantConnect.Tests.Brokerages
public override bool ModifyUntilFilled => false;
}
}
}

View File

@@ -24,8 +24,8 @@ namespace QuantConnect.Tests.Brokerages
private readonly decimal _highLimit;
private readonly decimal _lowLimit;
public StopMarketOrderTestParameters(Symbol symbol, decimal highLimit, decimal lowLimit, IOrderProperties properties = null)
: base(symbol, properties)
public StopMarketOrderTestParameters(Symbol symbol, decimal highLimit, decimal lowLimit, IOrderProperties properties = null, OrderSubmissionData orderSubmissionData = null)
: base(symbol, properties, orderSubmissionData)
{
_highLimit = highLimit;
_lowLimit = lowLimit;
@@ -80,4 +80,4 @@ namespace QuantConnect.Tests.Brokerages
public override bool ModifyUntilFilled => false;
}
}
}

View File

@@ -138,5 +138,29 @@ namespace QuantConnect.Tests.Common.Brokerages
Assert.AreEqual(false, _binanceBrokerageModel.CanSubmitOrder(security, order.Object, out var message));
Assert.NotNull(message);
}
[Test]
public void Returns1m_IfCashAccount()
{
Assert.AreEqual(1m, new BinanceBrokerageModel(AccountType.Cash).GetLeverage(_security));
}
[Test]
public void Returns3m_IfMarginAccount()
{
Assert.AreEqual(3m, new BinanceBrokerageModel(AccountType.Margin).GetLeverage(_security));
}
[Test]
public void ReturnsCashBuyinPowerModel_ForCashAccount()
{
Assert.IsInstanceOf<CashBuyingPowerModel>(new BinanceBrokerageModel(AccountType.Cash).GetBuyingPowerModel(_security));
}
[Test]
public void ReturnsSecurityMarginModel_ForMarginAccount()
{
Assert.IsInstanceOf<SecurityMarginModel>(new BinanceBrokerageModel(AccountType.Margin).GetBuyingPowerModel(_security));
}
}
}

View 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 Moq;
using NUnit.Framework;
using QuantConnect.Brokerages;
using QuantConnect.Orders;
using QuantConnect.Tests.Brokerages;
using QuantConnect.Securities;
namespace QuantConnect.Tests.Common.Brokerages
{
[TestFixture, Parallelizable(ParallelScope.All)]
public class ExanteBrokerageModelTests
{
private readonly ExanteBrokerageModel _exanteBrokerageModel = new();
private readonly Symbol _btcusd = Symbol.Create("BTCUSD", SecurityType.Crypto, "empty");
private Security _security;
[SetUp]
public void Init()
{
_security = TestsHelpers.GetSecurity(symbol: _btcusd.Value, market: _btcusd.ID.Market,
quoteCurrency: "EUR");
}
[Test]
public void CannotSubmitMarketOrder_IfPriceNotInitialized()
{
var order = new Mock<MarketOrder>
{
Object =
{
Quantity = 1
}
};
var security =
TestsHelpers.GetSecurity(symbol: _btcusd.Value, market: _btcusd.ID.Market, quoteCurrency: "EUR");
Assert.False(_exanteBrokerageModel.CanSubmitOrder(security, order.Object, out var message));
Assert.NotNull(message);
}
}
}

View File

@@ -64,6 +64,7 @@ namespace QuantConnect.Tests.Common.Data.Auxiliary
var dataProviderTest = new DefaultDataProviderTest();
fileProviderTest.Initialize(TestGlobals.MapFileProvider, dataProviderTest);
fileProviderTest.CacheCleared.Reset();
fileProviderTest.Get(Symbols.AAPL);
Assert.AreEqual(1, dataProviderTest.FetchCount);
@@ -71,7 +72,7 @@ namespace QuantConnect.Tests.Common.Data.Auxiliary
fileProviderTest.Get(Symbols.AAPL);
Assert.AreEqual(1, dataProviderTest.FetchCount);
Thread.Sleep(1000);
fileProviderTest.CacheCleared.WaitOne(TimeSpan.FromSeconds(2));
fileProviderTest.Get(Symbols.AAPL);
Assert.AreEqual(2, dataProviderTest.FetchCount);
@@ -83,6 +84,7 @@ namespace QuantConnect.Tests.Common.Data.Auxiliary
private class LocalZipFactorFileProviderTest : LocalZipFactorFileProvider
{
public bool Enabled = true;
public readonly ManualResetEvent CacheCleared = new (false);
protected override TimeSpan CacheRefreshPeriod => TimeSpan.FromMilliseconds(500);
protected override void StartExpirationTask()
@@ -90,6 +92,7 @@ namespace QuantConnect.Tests.Common.Data.Auxiliary
if (Enabled)
{
base.StartExpirationTask();
CacheCleared.Set();
}
}
}

View File

@@ -16,6 +16,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using NodaTime;
using NUnit.Framework;
using Python.Runtime;
using QuantConnect.Data;
@@ -229,6 +230,58 @@ def Test(slice):
}
}
[Test]
public void PythonGetPythonCustomData()
{
using (Py.GIL())
{
dynamic testModule = PythonEngine.ModuleFromString("testModule",
@"
from AlgorithmImports import *
class CustomDataTest(PythonData):
def Reader(self, config, line, date, isLiveMode):
result = CustomDataTest()
result.Symbol = config.Symbol
result.Value = 10
return result
def GetSource(config, date, isLiveMode):
return None
class CustomDataTest2(PythonData):
def Reader(self, config, line, date, isLiveMode):
result = CustomDataTest2()
result.Symbol = config.Symbol
result.Value = 11
return result
def GetSource(config, date, isLiveMode):
return None
def Test(slice):
data = slice.Get(CustomDataTest)
return data");
var test = testModule.GetAttr("Test");
var type = Extensions.CreateType(testModule.GetAttr("CustomDataTest"));
var customDataTest = new PythonData(testModule.GetAttr("CustomDataTest")());
var config = new SubscriptionDataConfig(type, Symbols.SPY, Resolution.Daily, DateTimeZone.Utc,
DateTimeZone.Utc, false, false, false, isCustom: true);
var data1 = customDataTest.Reader(config, "something", DateTime.UtcNow, false);
var customDataTest2 = new PythonData(testModule.GetAttr("CustomDataTest2")());
var config2 = new SubscriptionDataConfig(config, Extensions.CreateType(testModule.GetAttr("CustomDataTest2")));
var data2 = customDataTest2.Reader(config2, "something2", DateTime.UtcNow, false);
var unlinkedDataSpy = new UnlinkedData { Symbol = Symbols.SPY, Time = DateTime.UtcNow, Value = 10 };
var slice = new Slice(DateTime.UtcNow, new[] { unlinkedDataSpy, data2, data1 });
var data = test(new PythonSlice(slice));
Assert.AreEqual(1, (int)data.Count);
Assert.AreEqual(10, (int)data[Symbols.SPY].Value);
}
}
[Test]
public void PythonEnumerationWorks()
{

View File

@@ -1,46 +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.Collections.Generic;
using Newtonsoft.Json;
using NUnit.Framework;
using QuantConnect.Packets;
namespace QuantConnect.Tests.Common.Packets
{
[TestFixture, Parallelizable(ParallelScope.All)]
public class BreakpointTests
{
[Test]
public void SurvivesSerializationRoundTrip()
{
var breakpoints = new List<Breakpoint>
{
new Breakpoint{ FileName = "MichelAngelo", LineNumber = 1475},
new Breakpoint{ FileName = "LeonardoDaVinci", LineNumber = 1452}
};
var serialized = JsonConvert.SerializeObject(breakpoints);
var deserialized = JsonConvert.DeserializeObject<List<Breakpoint>>(serialized);
Assert.AreEqual(deserialized.Count, 2);
Assert.AreEqual(deserialized[0].FileName, "MichelAngelo");
Assert.AreEqual(deserialized[0].LineNumber, 1475);
Assert.AreEqual(deserialized[1].FileName, "LeonardoDaVinci");
Assert.AreEqual(deserialized[1].LineNumber, 1452);
}
}
}

View File

@@ -1,4 +1,4 @@
/*
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
@@ -152,6 +152,8 @@ namespace QuantConnect.Tests.Common.Securities.Futures
[TestCase(QuantConnect.Securities.Futures.Currencies.EURCAD, NineSixteenCentralTime)]
[TestCase(QuantConnect.Securities.Futures.Currencies.EURSEK, NineSixteenCentralTime)]
[TestCase(QuantConnect.Securities.Futures.Currencies.JapaneseYenEmini, NineSixteenCentralTime)]
[TestCase(QuantConnect.Securities.Futures.Currencies.MicroEUR, NineSixteenCentralTime)]
[TestCase(QuantConnect.Securities.Futures.Currencies.MicroBTC, FourPMLondonTime)]
public void CurrenciesExpiryDateFunction_WithDifferentDates_ShouldFollowContract(string symbol, string dayTime)
{
Assert.IsTrue(_data.ContainsKey(symbol), "Symbol " + symbol + " not present in Test Data");
@@ -241,6 +243,7 @@ namespace QuantConnect.Tests.Common.Securities.Futures
[TestCase(QuantConnect.Securities.Futures.Energies.NaturalGas, Zero)]
[TestCase(QuantConnect.Securities.Futures.Energies.BrentCrude, Zero)]
[TestCase(QuantConnect.Securities.Futures.Energies.LowSulfurGasoil, TwelveOclock)]
[TestCase(QuantConnect.Securities.Futures.Energies.MicroCrudeOilWTI, Zero)]
public void EnergiesExpiryDateFunction_WithDifferentDates_ShouldFollowContract(string symbol, string dayTime)
{
Assert.IsTrue(_data.ContainsKey(symbol), "Symbol " + symbol + " not present in Test Data");
@@ -267,6 +270,7 @@ namespace QuantConnect.Tests.Common.Securities.Futures
[TestCase(QuantConnect.Securities.Futures.Financials.FiveYearUSDMACSwap, TwoPMCentralTime)]
[TestCase(QuantConnect.Securities.Futures.Financials.UltraUSTreasuryBond, TwelveOne)]
[TestCase(QuantConnect.Securities.Futures.Financials.UltraTenYearUSTreasuryNote, Zero)]
[TestCase(QuantConnect.Securities.Futures.Financials.MicroY10TreasuryNote, Zero)]
public void FinancialsExpiryDateFunction_WithDifferentDates_ShouldFollowContract(string symbol, string dayTime)
{
Assert.IsTrue(_data.ContainsKey(symbol), "Symbol " + symbol + " not present in Test Data");
@@ -303,6 +307,8 @@ namespace QuantConnect.Tests.Common.Securities.Futures
[TestCase(QuantConnect.Securities.Futures.Indices.BankNifty, ThreeThirtyPM)]
[TestCase(QuantConnect.Securities.Futures.Indices.BseSensex, ThreeThirtyPM)]
[TestCase(QuantConnect.Securities.Futures.Indices.HangSeng, FourPM)]
[TestCase(QuantConnect.Securities.Futures.Indices.MicroSP500EMini, NineThirtyEasternTime)]
[TestCase(QuantConnect.Securities.Futures.Indices.MicroDow30EMini, NineThirtyEasternTime)]
public void IndicesExpiryDateFunction_WithDifferentDates_ShouldFollowContract(string symbol, string dayTime)
{
Assert.IsTrue(_data.ContainsKey(symbol), "Symbol " + symbol + " not present in Test Data");
@@ -369,6 +375,7 @@ namespace QuantConnect.Tests.Common.Securities.Futures
[TestCase(QuantConnect.Securities.Futures.Metals.AluminiumEuropeanPremiumDutyPaidMetalBulletin, Zero)]
[TestCase(QuantConnect.Securities.Futures.Metals.Copper, TwelvePMCentralTime)]
[TestCase(QuantConnect.Securities.Futures.Metals.USMidwestDomesticHotRolledCoilSteelCRUIndex, Zero)]
[TestCase(QuantConnect.Securities.Futures.Metals.MicroGold, Zero)]
public void MetalsExpiryDateFunction_WithDifferentDates_ShouldFollowContract(string symbol, string dayTime)
{
Assert.IsTrue(_data.ContainsKey(symbol), "Symbol " + symbol + " not present in Test Data");

View File

@@ -1,4 +1,4 @@
/*
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
@@ -301,7 +301,11 @@ namespace QuantConnect.Tests.Common.Securities.Futures
}
[TestCase("06/01/2015 00:00:01", DayOfWeek.Friday, "30/01/2015 00:00:00")]
[TestCase("06/07/2015 00:00:01", DayOfWeek.Thursday, "30/07/2015 00:00:00")]
[TestCase("06/05/2016 00:00:01", DayOfWeek.Wednesday, "25/05/2016 00:00:00")]
[TestCase("06/01/2016 00:00:01", DayOfWeek.Friday, "29/01/2016 00:00:00")]
[TestCase("06/07/2016 00:00:01", DayOfWeek.Thursday, "28/07/2016 00:00:00")]
[TestCase("06/05/2017 00:00:01", DayOfWeek.Wednesday, "31/05/2017 00:00:00")]
public void Last_WeekDay_ShouldReturnCorrectDate(string contractDate, DayOfWeek dayOfWeek, string expectedOutput)
{
// Arrange

View File

@@ -148,9 +148,9 @@ namespace QuantConnect.Tests.Common.Securities.Options.StrategyMatcher
}
[Test]
public void None_CreatesOptionPosition_WithZeroQuantity()
public void Empty_CreatesOptionPosition_WithZeroQuantity()
{
var none = OptionPosition.None(Symbols.SPY);
var none = OptionPosition.Empty(Symbols.SPY);
Assert.AreEqual(0, none.Quantity);
Assert.AreEqual(Symbols.SPY, none.Symbol);
}

View File

@@ -1,4 +1,4 @@
/*
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
@@ -68,7 +68,7 @@ namespace QuantConnect.Tests.Common.Storage
Log.LogHandler = _logHandler;
}
[TestCase(FileAccess.Read, false)]
[TestCase(FileAccess.Read, true)]
[TestCase(FileAccess.ReadWrite, false)]
[TestCase(0, true)]
[TestCase(FileAccess.Write, true)]
@@ -83,7 +83,7 @@ namespace QuantConnect.Tests.Common.Storage
}
else
{
Assert.Throws<KeyNotFoundException>(() => store.GetFilePath("Jose"));
Assert.DoesNotThrow(() => store.GetFilePath("Jose"));
}
}
@@ -250,7 +250,6 @@ namespace QuantConnect.Tests.Common.Storage
public void GetFilePathReturnsFileName(string key, string expectedRelativePath)
{
var expectedPath = Path.GetFullPath(expectedRelativePath).Replace("\\", "/");
_store.SaveString(key, "data");
Assert.AreEqual(expectedPath, _store.GetFilePath(key).Replace("\\", "/"));
}
@@ -412,6 +411,55 @@ namespace QuantConnect.Tests.Common.Storage
Assert.IsFalse(_store.SaveString("breaker", "gotem"));
}
[Test]
public void WriteFromExternalMethodAndSaveFromSource()
{
using (var store = new ObjectStore(new LocalObjectStore()))
{
store.Initialize("test", 0, 0, "", new Controls() { PersistenceIntervalSeconds = -1 });
Assert.IsTrue(Directory.Exists("./LocalObjectStoreTests/test"));
var key = "Test";
var content = "Example text";
var path = store.GetFilePath(key);
DummyMachineLearning(path, content);
store.Save(key);
var storeContent = store.Read(key);
Assert.AreEqual(content, storeContent);
}
}
[Test]
public void GetFilePathMethodWorksProperly()
{
using (var store = new ObjectStore(new LocalObjectStore()))
{
store.Initialize("test", 0, 0, "", new Controls() { PersistenceIntervalSeconds = -1 });
Assert.IsTrue(Directory.Exists("./LocalObjectStoreTests/test"));
var key = "test";
var path = store.GetFilePath(key);
Assert.IsFalse(File.Exists(path));
Assert.IsNull(store.Read(key));
}
}
[Test]
public void TrySaveKeyWithNotFileAssociated()
{
using (var store = new ObjectStore(new LocalObjectStore()))
{
store.Initialize("test", 0, 0, "", new Controls() { PersistenceIntervalSeconds = -1 });
Assert.IsTrue(Directory.Exists("./LocalObjectStoreTests/test"));
var key = "test";
Assert.Throws<ArgumentException>(() => store.Save(key));
}
}
[Test]
public void DeletedObjectIsNotReloaded()
{
@@ -448,6 +496,20 @@ namespace QuantConnect.Tests.Common.Storage
}
}
private static void DummyMachineLearning(string outputFile, string content)
{
try
{
var sw = new StreamWriter(outputFile);
sw.Write(content);
sw.Close();
}
catch(Exception e)
{
throw e;
}
}
public class TestSettings
{
public int EmaFastPeriod { get; set; }

View File

@@ -42,6 +42,33 @@ namespace QuantConnect.Tests.Common.Util
[TestFixture]
public class ExtensionsTests
{
[TestCase("20220101", false, true, Resolution.Daily)]
[TestCase("20220101", false, false, Resolution.Daily)]
[TestCase("20220103 09:31", true, false, Resolution.Minute)]
[TestCase("20220103 07:31", false, false, Resolution.Minute)]
[TestCase("20220103 07:31", false, false, Resolution.Daily)]
[TestCase("20220103 07:31", true, true, Resolution.Daily)]
[TestCase("20220103 08:31", true, true, Resolution.Daily)]
public void IsMarketOpenSecurity(string exchangeTime, bool expectedResult, bool extendedMarketHours, Resolution resolution)
{
var security = CreateSecurity(Symbols.SPY);
var utcTime = Time.ParseDate(exchangeTime).ConvertToUtc(security.Exchange.TimeZone);
security.SetLocalTimeKeeper(new LocalTimeKeeper(utcTime, security.Exchange.TimeZone));
Assert.AreEqual(expectedResult, security.IsMarketOpen(extendedMarketHours));
}
[TestCase("20220101", false, true)]
[TestCase("20220101", false, false)]
[TestCase("20220103 09:31", true, false)]
[TestCase("20220103 07:31", false, false)]
[TestCase("20220103 08:31", true, true)]
public void IsMarketOpenSymbol(string nyTime, bool expectedResult, bool extendedMarketHours)
{
var utcTime = Time.ParseDate(nyTime).ConvertToUtc(TimeZones.NewYork);
Assert.AreEqual(expectedResult, Symbols.SPY.IsMarketOpen(utcTime, extendedMarketHours));
}
[TestCase("CL XTN6UA1G9QKH")]
[TestCase("ES VU1EHIDJYLMP")]
[TestCase("ES VRJST036ZY0X")]
@@ -1448,5 +1475,20 @@ actualDictionary.update({'IBM': 5})
private class Derived2 : Derived1
{
}
private static Security CreateSecurity(Symbol symbol)
{
var entry = MarketHoursDatabase.FromDataFolder()
.GetEntry(symbol.ID.Market, symbol, symbol.SecurityType);
return new Security(symbol,
entry.ExchangeHours,
new Cash(Currencies.USD, 0, 1),
SymbolProperties.GetDefault(Currencies.USD),
ErrorCurrencyConverter.Instance,
RegisteredSecurityDataTypesProvider.Null,
new SecurityCache()
);
}
}
}

View File

@@ -33,6 +33,7 @@ using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using QuantConnect.Securities.Future;
namespace QuantConnect.Tests.Engine.DataFeeds.Enumerators
{
@@ -1696,7 +1697,8 @@ namespace QuantConnect.Tests.Engine.DataFeeds.Enumerators
while (fillForwardEnumerator.MoveNext())
{
Assert.NotNull(fillForwardEnumerator.Current);
Assert.GreaterOrEqual(fillForwardEnumerator.Current.Time, previous?.Time);
// we don't care about 'Time' because lean only uses 'EndTime', in case some auxiliary data point comes in 'Time == EndTime'
// but the enumerator output should always go increasing 'EndTime'
Assert.GreaterOrEqual(fillForwardEnumerator.Current.EndTime, previous?.EndTime);
Assert.AreEqual(
fillForwardEnumerator.Current.DataType != MarketDataType.Auxiliary,
@@ -1825,6 +1827,72 @@ namespace QuantConnect.Tests.Engine.DataFeeds.Enumerators
fillForwardEnumerator.Dispose();
}
[Test]
public void FillsForwardSymbolChangedDailyResolution()
{
var symbol = Symbols.Fut_SPY_Mar19_2016;
var entry = MarketHoursDatabase.FromDataFolder().GetEntry(symbol.ID.Market, symbol, symbol.SecurityType);
var reference = new DateTime(2014, 6, 5, 20, 0, 0);
var dataResolution = Time.OneDay;
var data = new BaseData[]
{
new TradeBar {
Time = reference,
Value = 1,
Period = dataResolution,
Volume = 100,
Symbol = symbol
}, new TradeBar {
Time = reference.AddDays(1),
Value = 2,
Period = dataResolution,
Volume = 200,
Symbol = symbol
},
new SymbolChangedEvent(symbol, reference.AddDays(3).Date, symbol, symbol),
new TradeBar {
Time = reference.AddDays(2),
Value = 3,
Period = dataResolution,
Volume = 300,
Symbol = symbol
}}.ToList();
var enumerator = data.GetEnumerator();
var fillForwardEnumerator = new FillForwardEnumerator(enumerator,
new FutureExchange(entry.ExchangeHours),
Ref.Create(dataResolution),
false,
data.Last().EndTime,
dataResolution,
entry.DataTimeZone);
BaseData previous = null;
var counter = 0;
while (fillForwardEnumerator.MoveNext())
{
Assert.NotNull(fillForwardEnumerator.Current);
// we don't care about 'Time' because lean only uses 'EndTime', in case some auxiliary data point comes in 'Time == EndTime'
// but the enumerator output should always go increasing 'EndTime'
if (previous != null)
{
Assert.GreaterOrEqual(fillForwardEnumerator.Current.EndTime, previous?.EndTime);
}
if (fillForwardEnumerator.Current.IsFillForward)
{
Assert.AreNotEqual(MarketDataType.Auxiliary, fillForwardEnumerator.Current.DataType);
counter++;
}
previous = fillForwardEnumerator.Current;
}
Assert.AreEqual((int)(data.Last().EndTime - data[1].EndTime).TotalDays - 1, counter);
fillForwardEnumerator.Dispose();
}
[Test]
[TestCaseSource(nameof(ExchangeDaylightTimeSet), new object[] { 6, Resolution.Daily })]
[TestCaseSource(nameof(ExchangeDaylightTimeSet), new object[] { 7, Resolution.Daily })]
@@ -2056,7 +2124,8 @@ namespace QuantConnect.Tests.Engine.DataFeeds.Enumerators
while (fillForwardEnumerator.MoveNext())
{
Assert.NotNull(fillForwardEnumerator.Current);
Assert.GreaterOrEqual(fillForwardEnumerator.Current.Time, previous?.Time ?? DateTime.MinValue);
// we don't care about .Time because lean only uses .EndTime
// in case some auxiliary data point comes in it will respect endtime being ascendant but it's time == endtime
Assert.GreaterOrEqual(fillForwardEnumerator.Current.EndTime, previous?.EndTime ?? DateTime.MinValue);
Assert.AreEqual(
fillForwardEnumerator.Current.DataType != MarketDataType.Auxiliary,

View File

@@ -17,12 +17,15 @@
using System;
using System.Collections.Generic;
using System.IO;
using NodaTime;
using NUnit.Framework;
using QuantConnect.Data;
using QuantConnect.Data.Auxiliary;
using QuantConnect.Data.Market;
using QuantConnect.Data.UniverseSelection;
using QuantConnect.Interfaces;
using QuantConnect.Lean.Engine.DataFeeds;
using QuantConnect.Securities;
using QuantConnect.Util;
namespace QuantConnect.Tests.Engine.DataFeeds
@@ -47,21 +50,20 @@ namespace QuantConnect.Tests.Engine.DataFeeds
var start = new DateTime(2019, 12, 9);
var end = new DateTime(2019, 12, 12);
var dataReader = new SubscriptionDataReader(
new SubscriptionDataConfig(typeof(TradeBar),
Symbols.SPY,
dataResolution,
TimeZones.NewYork,
TimeZones.NewYork,
false,
false,
false),
start,
end,
var symbol = Symbols.SPY;
var entry = MarketHoursDatabase.FromDataFolder().GetEntry(symbol.ID.Market, symbol, symbol.SecurityType);
var config = new SubscriptionDataConfig(typeof(TradeBar),
symbol,
dataResolution,
TimeZones.NewYork,
TimeZones.NewYork,
false,
false,
false);
var dataReader = new SubscriptionDataReader(config,
new HistoryRequest(config, entry.ExchangeHours, start, end),
TestGlobals.MapFileProvider,
TestGlobals.FactorFileProvider,
LinqExtensions.Range(start, end, time => time + TimeSpan.FromDays(1)),
false,
new TestDataCacheProvider
{ Data = data },
TestGlobals.DataProvider

View File

@@ -13,6 +13,7 @@
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<GenerateBindingRedirectsOutputType>true</GenerateBindingRedirectsOutputType>
<ServerGarbageCollection>true</ServerGarbageCollection>
<Description>QuantConnect LEAN Engine: Tests Project - The test collection</Description>
<NoWarn>CS0618</NoWarn>
</PropertyGroup>

View File

@@ -91,7 +91,7 @@ namespace QuantConnect.Tests
from type in typeof(BasicTemplateAlgorithm).Assembly.GetTypes()
where typeof(IRegressionAlgorithmDefinition).IsAssignableFrom(type)
where !type.IsAbstract // non-abstract
where type.GetConstructor(new Type[0]) != null // has default ctor
where type.GetConstructor(Array.Empty<Type>()) != null // has default ctor
let instance = (IRegressionAlgorithmDefinition) Activator.CreateInstance(type)
let status = nonDefaultStatuses.GetValueOrDefault(type.Name, AlgorithmStatus.Completed)
where instance.CanRunLocally // open source has data to run this algorithm

View File

@@ -1,6 +1,10 @@
Globex,Product Name,MultipleFactor,Info
10Y,Micro 10-Year Yield Futures,0.1,
1S,Propane Non-LDH Mont Belvieu (OPIS) BALMO Futures,1,
22,Argus Propane Far East Index BALMO Futures,1,
2YY,Micro 2-Year Yield Futures,0.1,
30Y,Micro 30-Year Yield Futures,0.1,
5YY,Micro 5-Year Yield Futures,0.1
6A,Australian Dollar Futures,0.01,
6B,British Pound Futures,0.01,
6C,Canadian Dollar Futures,0.01,
@@ -126,31 +130,49 @@ LIT,2-Year Eris Swap Futures,1,
LIW,5-year Eris Swap Futures,1,
LIY,10-year Eris Swap Futures,1,
LT,Gulf Coast ULSD (Platts) Up-Down Futures,0.01,
M1B,Micro Gasoil 0.1% Barges FOB ARA (Platts) Futures,1,
M2K,Micro E-mini Russell 2000 Index Futures,1,
M35,Micro European 3.5% Fuel Oil Cargoes FOB Med (Platts) Futures,0.1,
M5F,Micro Coal (API 5) fob Newcastle (Argus/McCloskey) Futures,1,
M6A,E-micro Australian Dollar/American Dollar Futures,100,
M6B,E-micro British Pound/American Dollar Futures,100,
M6C,Micro USD/CAD Futures,100,
M6E,E-micro Euro/American Dollar Futures,100,
M6J,Micro USD/JPY Futures,100,
M6S,Micro USD/CHF Futures,1000,
MAE,Mini Argus Propane Far East Index Futures,0.1,
MAF,Micro Singapore Fuel Oil 380CST (Platts) Futures,1,
MBT,Micro Bitcoin Futures,100,
MCD,E-micro Canadian Dollar/American Dollar Futures,100,
MCL,Micro WTI Crude Oil Futures,1,
ME,Gulf Coast Jet (Platts) Up-Down Futures,0.01,
MEF,Micro European 3.5% Fuel Oil Barges FOB Rdam (Platts) Futures,0.1,
MEE,Mini European Naphtha (Platts) BALMO Futures,1,
MEO,Mini Gasoline Euro-bob Oxy NWE Barges (Argus) Futures,0.1,
MES,Micro E-mini Standard and Poor's 500 Stock Price Index Futures,1,
MET,Micro Ether Futures,1,
MFB,Gulf Coast HSFO (Platts) Futures,1,
MFF,Coal (API4) FOB Richards Bay (ARGUS-McCloskey) Futures,1,
MGB,Mini Gasoil 0.1 Barges FOB Rdam (Platts) vs. Low Sulphur Gasoil Futures,0.1,
MGC,E-micro Gold Futures,10,
MIR,E-micro Indian Rupee/USD Futures,100,
MGT,Micro Gold TAS,1,
MIB,BTIC on Micro Bitcoin Futures,1,
MIR,E-micro Indian Rupee/USD Futures,1,
MJN,Mini Japan C&F Naphtha (Platts) Futures,0.1,
MJY,E-micro Japanese Yen/American Dollar Futures,100,
MM,New York Harbor Residual Fuel 1.0% (Platts) Futures,1,
MMF,Mini 3.5% Fuel Oil Cargoes FOB MED (Platts) Financial Futures,0.1,
MNC,Mini European Naphtha CIF NWE (Platts) Futures,0.1,
MNH,Micro USD/CNH Futures,100,
MNQ,Micro E-mini Nasdaq-100 Index Futures,1,
MPS,Mini European Propane CIF ARA (Argus) Futures,2,
MRB,BTIC on Micro Ether Futures,1,
MSF,E-micro Swiss Franc/American Dollar Futures,100,
MSG,Mini Singapore Gasoil (Platts) Futures,0.1,
MTB,Mini Singapore Fuel Oil 380 cst (Platts) BALMO Futures,3,
MTF,Coal (API2) CIF ARA (ARGUS-McCloskey) Futures,1,
MTS,Mini Singapore Fuel Oil 380 cst (Platts) Futures,0.1,
MYM,Micro E-mini Dow Jones Industrial Average Index Futures,100,
N1B,Singapore Mogas 92 Unleaded (Platts) Futures,4,
N1U,10-Year USD MAC Swap Futures,5,
NBB,Naphtha Cargoes CIF NWE (Platts) Crack Spread (1000mt) BALMO Futures,6,
@@ -162,6 +184,7 @@ NOK,Norwegian Krone Futures,0.001,
NOO,Naphtha Cargoes CIF NWE (Platts) Crack Spread (1000mt) Futures,0.01,
NQ,E-mini Nasdaq-100 Futures,1,
PA,Palladium Futures,1,
PAM,Micro Palladium Futures,1,
PJY,British Pound/Japanese Yen Futures,1,
PL,Platinum Futures,10,
PLN,Polish Zloty Futures,0.001,
@@ -171,6 +194,7 @@ QG,E-mini Natural Gas Futures,0.1,
QI,E-mini Silver Futures,0.01,
QM,E-mini Crude Oil Futures,0.1,
QO,E-mini Gold Futures,1,
R5O,Micro European FOB Rdam Marine Fuel 0.5% Barges (Platts) Futures,1,
RB,RBOB Gasoline Futures,0.01,
RBB,RBOB Gasoline Brent Crack Spread Futures,0.1,
RF,Euro/Swiss Franc Futures,0.01,
@@ -185,6 +209,7 @@ RY,Euro/Japanese Yen Futures,1,
SDA,S&P 500 Annual Dividend Index Futures,0.1,
SE,Singapore Fuel Oil 380 cst (Platts) Futures,0.1,
SEK,Swedish Krona Futures,0.001,
S5O,Micro Singapore FOB Marine Fuel 0.5% (Platts) Futures,1,
SI,Silver Futures,0.1,
SIL,1000-oz. Silver Futures,0.1,
SIR,Indian Rupee/USD Futures,1,
1 Globex Product Name MultipleFactor Info
2 10Y Micro 10-Year Yield Futures 0.1
3 1S Propane Non-LDH Mont Belvieu (OPIS) BALMO Futures 1
4 22 Argus Propane Far East Index BALMO Futures 1
5 2YY Micro 2-Year Yield Futures 0.1
6 30Y Micro 30-Year Yield Futures 0.1
7 5YY Micro 5-Year Yield Futures 0.1
8 6A Australian Dollar Futures 0.01
9 6B British Pound Futures 0.01
10 6C Canadian Dollar Futures 0.01
130 LIW 5-year Eris Swap Futures 1
131 LIY 10-year Eris Swap Futures 1
132 LT Gulf Coast ULSD (Platts) Up-Down Futures 0.01
133 M1B Micro Gasoil 0.1% Barges FOB ARA (Platts) Futures 1
134 M2K Micro E-mini Russell 2000 Index Futures 1
135 M35 Micro European 3.5% Fuel Oil Cargoes FOB Med (Platts) Futures 0.1
136 M5F Micro Coal (API 5) fob Newcastle (Argus/McCloskey) Futures 1
137 M6A E-micro Australian Dollar/American Dollar Futures 100
138 M6B E-micro British Pound/American Dollar Futures 100
139 M6C Micro USD/CAD Futures 100
140 M6E E-micro Euro/American Dollar Futures 100
141 M6J Micro USD/JPY Futures 100
142 M6S Micro USD/CHF Futures 1000
143 MAE Mini Argus Propane Far East Index Futures 0.1
144 MAF Micro Singapore Fuel Oil 380CST (Platts) Futures 1
145 MBT Micro Bitcoin Futures 100
146 MCD E-micro Canadian Dollar/American Dollar Futures 100
147 MCL Micro WTI Crude Oil Futures 1
148 ME Gulf Coast Jet (Platts) Up-Down Futures 0.01
149 MEF Micro European 3.5% Fuel Oil Barges FOB Rdam (Platts) Futures 0.1
150 MEE Mini European Naphtha (Platts) BALMO Futures 1
151 MEO Mini Gasoline Euro-bob Oxy NWE Barges (Argus) Futures 0.1
152 MES Micro E-mini Standard and Poor's 500 Stock Price Index Futures 1
153 MET Micro Ether Futures 1
154 MFB Gulf Coast HSFO (Platts) Futures 1
155 MFF Coal (API4) FOB Richards Bay (ARGUS-McCloskey) Futures 1
156 MGB Mini Gasoil 0.1 Barges FOB Rdam (Platts) vs. Low Sulphur Gasoil Futures 0.1
157 MGC E-micro Gold Futures 10
158 MIR MGT E-micro Indian Rupee/USD Futures Micro Gold TAS 100 1
159 MIB BTIC on Micro Bitcoin Futures 1
160 MIR E-micro Indian Rupee/USD Futures 1
161 MJN Mini Japan C&F Naphtha (Platts) Futures 0.1
162 MJY E-micro Japanese Yen/American Dollar Futures 100
163 MM New York Harbor Residual Fuel 1.0% (Platts) Futures 1
164 MMF Mini 3.5% Fuel Oil Cargoes FOB MED (Platts) Financial Futures 0.1
165 MNC Mini European Naphtha CIF NWE (Platts) Futures 0.1
166 MNH Micro USD/CNH Futures 100
167 MNQ Micro E-mini Nasdaq-100 Index Futures 1
168 MPS Mini European Propane CIF ARA (Argus) Futures 2
169 MRB BTIC on Micro Ether Futures 1
170 MSF E-micro Swiss Franc/American Dollar Futures 100
171 MSG Mini Singapore Gasoil (Platts) Futures 0.1
172 MTB Mini Singapore Fuel Oil 380 cst (Platts) BALMO Futures 3
173 MTF Coal (API2) CIF ARA (ARGUS-McCloskey) Futures 1
174 MTS Mini Singapore Fuel Oil 380 cst (Platts) Futures 0.1
175 MYM Micro E-mini Dow Jones Industrial Average Index Futures 100
176 N1B Singapore Mogas 92 Unleaded (Platts) Futures 4
177 N1U 10-Year USD MAC Swap Futures 5
178 NBB Naphtha Cargoes CIF NWE (Platts) Crack Spread (1000mt) BALMO Futures 6
184 NOO Naphtha Cargoes CIF NWE (Platts) Crack Spread (1000mt) Futures 0.01
185 NQ E-mini Nasdaq-100 Futures 1
186 PA Palladium Futures 1
187 PAM Micro Palladium Futures 1
188 PJY British Pound/Japanese Yen Futures 1
189 PL Platinum Futures 10
190 PLN Polish Zloty Futures 0.001
194 QI E-mini Silver Futures 0.01
195 QM E-mini Crude Oil Futures 0.1
196 QO E-mini Gold Futures 1
197 R5O Micro European FOB Rdam Marine Fuel 0.5% Barges (Platts) Futures 1
198 RB RBOB Gasoline Futures 0.01
199 RBB RBOB Gasoline Brent Crack Spread Futures 0.1
200 RF Euro/Swiss Franc Futures 0.01
209 SDA S&P 500 Annual Dividend Index Futures 0.1
210 SE Singapore Fuel Oil 380 cst (Platts) Futures 0.1
211 SEK Swedish Krona Futures 0.001
212 S5O Micro Singapore FOB Marine Fuel 0.5% (Platts) Futures 1
213 SI Silver Futures 0.1
214 SIL 1000-oz. Silver Futures 0.1
215 SIR Indian Rupee/USD Futures 1

View File

@@ -53,7 +53,6 @@
</PackageReference>
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
<PackageReference Include="NodaTime" Version="3.0.5" />
<PackageReference Include="SharpZipLib" Version="1.2.0" />
</ItemGroup>
<ItemGroup>
<None Include="..\LICENSE">

Some files were not shown because too many files have changed in this diff Show More