Compare commits
64 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
201aa70c87 | ||
|
|
8633714bd0 | ||
|
|
baaef45704 | ||
|
|
a229df86b7 | ||
|
|
385330a476 | ||
|
|
6d272c3481 | ||
|
|
25a49f48f5 | ||
|
|
3f716ba61a | ||
|
|
d5069b5b46 | ||
|
|
ff1f4d6cfa | ||
|
|
f4e826fb59 | ||
|
|
f996df7348 | ||
|
|
cece3b50eb | ||
|
|
b109427542 | ||
|
|
e70df95b7c | ||
|
|
8102dc3de3 | ||
|
|
aed5a4cea0 | ||
|
|
887822f76f | ||
|
|
9658286820 | ||
|
|
a311732f47 | ||
|
|
e30800357d | ||
|
|
ad3c2aada7 | ||
|
|
6b425ead2c | ||
|
|
27ab68100d | ||
|
|
f930c11a93 | ||
|
|
a17be3ccba | ||
|
|
b81c13ac4a | ||
|
|
1e6713ccf0 | ||
|
|
e149940fb9 | ||
|
|
f0908e3e75 | ||
|
|
c9638871ad | ||
|
|
07a90c7455 | ||
|
|
69963d493a | ||
|
|
32bd8c248f | ||
|
|
64f1b87b01 | ||
|
|
1ad5916968 | ||
|
|
128adba745 | ||
|
|
02e88c0370 | ||
|
|
5e0f1b3742 | ||
|
|
0fdd3759b2 | ||
|
|
bdb5ec9521 | ||
|
|
993c3b036d | ||
|
|
29968de84c | ||
|
|
3a9303ecc6 | ||
|
|
78a381c569 | ||
|
|
dfd4f54e3f | ||
|
|
b9f4cb87e3 | ||
|
|
aad49fecbf | ||
|
|
47eedf6ccd | ||
|
|
3ef8e0d16f | ||
|
|
e58dab6c5e | ||
|
|
39496b10a4 | ||
|
|
afa3c23450 | ||
|
|
5fff7cc399 | ||
|
|
388dd25827 | ||
|
|
4ec92a93a4 | ||
|
|
96ccc567f7 | ||
|
|
068e09e897 | ||
|
|
4edf4e2e63 | ||
|
|
078a977eb6 | ||
|
|
bd5f4e47be | ||
|
|
457b8f3839 | ||
|
|
10d467fb72 | ||
|
|
5d63f27688 |
@@ -40,8 +40,8 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
|
||||
var aapl = QuantConnect.Symbol.Create("AAPL", SecurityType.Equity, Market.USA);
|
||||
|
||||
_contract = OptionChain(aapl)
|
||||
.OrderBy(x => x.ID.Symbol)
|
||||
_contract = OptionChainProvider.GetOptionContractList(aapl, Time)
|
||||
.OrderBy(symbol => symbol.ID.Symbol)
|
||||
.FirstOrDefault(optionContract => optionContract.ID.OptionRight == OptionRight.Call
|
||||
&& optionContract.ID.OptionStyle == OptionStyle.American);
|
||||
AddOptionContract(_contract);
|
||||
|
||||
@@ -39,8 +39,8 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
|
||||
var aapl = AddEquity("AAPL").Symbol;
|
||||
|
||||
_contract = OptionChain(aapl)
|
||||
.OrderBy(x => x.ID.Symbol)
|
||||
_contract = OptionChainProvider.GetOptionContractList(aapl, Time)
|
||||
.OrderBy(symbol => symbol.ID.Symbol)
|
||||
.FirstOrDefault(optionContract => optionContract.ID.OptionRight == OptionRight.Call
|
||||
&& optionContract.ID.OptionStyle == OptionStyle.American);
|
||||
}
|
||||
|
||||
@@ -49,7 +49,7 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
{
|
||||
foreach (var contract in futuresContracts)
|
||||
{
|
||||
var option_contract_symbols = OptionChain(contract.Symbol).ToList();
|
||||
var option_contract_symbols = OptionChainProvider.GetOptionContractList(contract.Symbol, Time).ToList();
|
||||
if(option_contract_symbols.Count == 0)
|
||||
{
|
||||
continue;
|
||||
|
||||
@@ -46,8 +46,8 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
{
|
||||
if (_option == null)
|
||||
{
|
||||
var option = OptionChain(_twx)
|
||||
.OrderBy(x => x.ID.Symbol)
|
||||
var option = OptionChainProvider.GetOptionContractList(_twx, Time)
|
||||
.OrderBy(symbol => symbol.ID.Symbol)
|
||||
.FirstOrDefault(optionContract => optionContract.ID.Date == _expiration
|
||||
&& optionContract.ID.OptionRight == OptionRight.Call
|
||||
&& optionContract.ID.OptionStyle == OptionStyle.American);
|
||||
|
||||
@@ -13,12 +13,12 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
using QuantConnect.Data;
|
||||
using QuantConnect.Data.UniverseSelection;
|
||||
using QuantConnect.Interfaces;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using QuantConnect.Data;
|
||||
using QuantConnect.Data.UniverseSelection;
|
||||
using QuantConnect.Interfaces;
|
||||
|
||||
namespace QuantConnect.Algorithm.CSharp
|
||||
{
|
||||
@@ -110,14 +110,14 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
|
||||
foreach (var addedSecurity in changes.AddedSecurities)
|
||||
{
|
||||
var option = OptionChain(addedSecurity.Symbol)
|
||||
.OrderBy(contractData => contractData.ID.Symbol)
|
||||
var option = OptionChainProvider.GetOptionContractList(addedSecurity.Symbol, Time)
|
||||
.OrderBy(symbol => symbol.ID.Symbol)
|
||||
.First(optionContract => optionContract.ID.Date == _expiration
|
||||
&& optionContract.ID.OptionRight == OptionRight.Call
|
||||
&& optionContract.ID.OptionStyle == OptionStyle.American);
|
||||
AddOptionContract(option);
|
||||
|
||||
foreach (var symbol in new[] { option.Symbol, option.Underlying.Symbol })
|
||||
foreach (var symbol in new[] { option, option.Underlying })
|
||||
{
|
||||
var config = SubscriptionManager.SubscriptionDataConfigService.GetSubscriptionDataConfigs(symbol).ToList();
|
||||
|
||||
|
||||
@@ -43,8 +43,8 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
|
||||
var aapl = QuantConnect.Symbol.Create("AAPL", SecurityType.Equity, Market.USA);
|
||||
|
||||
_contract = OptionChain(aapl)
|
||||
.OrderBy(x => x.ID.StrikePrice)
|
||||
_contract = OptionChainProvider.GetOptionContractList(aapl, Time)
|
||||
.OrderBy(symbol => symbol.ID.StrikePrice)
|
||||
.FirstOrDefault(optionContract => optionContract.ID.OptionRight == OptionRight.Call
|
||||
&& optionContract.ID.OptionStyle == OptionStyle.American);
|
||||
AddOptionContract(_contract);
|
||||
|
||||
@@ -41,8 +41,8 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
|
||||
var aapl = QuantConnect.Symbol.Create("AAPL", SecurityType.Equity, Market.USA);
|
||||
|
||||
var contracts = OptionChain(aapl)
|
||||
.OrderBy(x => x.ID.StrikePrice)
|
||||
var contracts = OptionChainProvider.GetOptionContractList(aapl, Time)
|
||||
.OrderBy(symbol => symbol.ID.StrikePrice)
|
||||
.Where(optionContract => optionContract.ID.OptionRight == OptionRight.Call
|
||||
&& optionContract.ID.OptionStyle == OptionStyle.American)
|
||||
.Take(2)
|
||||
|
||||
@@ -1,239 +0,0 @@
|
||||
/*
|
||||
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
|
||||
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using QuantConnect.Data;
|
||||
using QuantConnect.Data.UniverseSelection;
|
||||
using QuantConnect.Interfaces;
|
||||
using QuantConnect.Orders;
|
||||
using QuantConnect.Securities;
|
||||
using QuantConnect.Securities.Future;
|
||||
|
||||
namespace QuantConnect.Algorithm.CSharp
|
||||
{
|
||||
/// <summary>
|
||||
/// This algorithm tests and demonstrates EUREX futures subscription and trading:
|
||||
/// - It tests contracts rollover by adding a continuous future and asserting that mapping happens at some point.
|
||||
/// - It tests basic trading by buying a contract and holding it until expiration.
|
||||
/// - It tests delisting and asserts the holdings are liquidated after that.
|
||||
/// </summary>
|
||||
public class BasicTemplateEurexFuturesAlgorithm : QCAlgorithm, IRegressionAlgorithmDefinition
|
||||
{
|
||||
private Future _continuousContract;
|
||||
private Symbol _mappedSymbol;
|
||||
private Symbol _contractToTrade;
|
||||
private int _mappingsCount;
|
||||
private decimal _boughtQuantity;
|
||||
private decimal _liquidatedQuantity;
|
||||
private bool _delisted;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
SetStartDate(2024, 5, 30);
|
||||
SetEndDate(2024, 6, 23);
|
||||
|
||||
SetAccountCurrency(Currencies.EUR);
|
||||
SetCash(1000000);
|
||||
|
||||
_continuousContract = AddFuture(Futures.Indices.EuroStoxx50, Resolution.Minute,
|
||||
dataNormalizationMode: DataNormalizationMode.BackwardsRatio,
|
||||
dataMappingMode: DataMappingMode.FirstDayMonth,
|
||||
contractDepthOffset: 0);
|
||||
_continuousContract.SetFilter(TimeSpan.Zero, TimeSpan.FromDays(180));
|
||||
_mappedSymbol = _continuousContract.Mapped;
|
||||
|
||||
var benchmark = AddIndex("SX5E", market: Market.EUREX);
|
||||
SetBenchmark(benchmark.Symbol);
|
||||
|
||||
var seeder = new FuncSecuritySeeder(GetLastKnownPrices);
|
||||
SetSecurityInitializer(security => seeder.SeedSecurity(security));
|
||||
}
|
||||
|
||||
public override void OnData(Slice slice)
|
||||
{
|
||||
foreach (var changedEvent in slice.SymbolChangedEvents.Values)
|
||||
{
|
||||
if (++_mappingsCount > 1)
|
||||
{
|
||||
throw new RegressionTestException($"{Time} - Unexpected number of symbol changed events (mappings): {_mappingsCount}. " +
|
||||
$"Expected only 1.");
|
||||
}
|
||||
|
||||
Debug($"{Time} - SymbolChanged event: {changedEvent}");
|
||||
|
||||
if (changedEvent.OldSymbol != _mappedSymbol.ID.ToString())
|
||||
{
|
||||
throw new RegressionTestException($"{Time} - Unexpected symbol changed event old symbol: {changedEvent}");
|
||||
}
|
||||
|
||||
if (changedEvent.NewSymbol != _continuousContract.Mapped.ID.ToString())
|
||||
{
|
||||
throw new RegressionTestException($"{Time} - Unexpected symbol changed event new symbol: {changedEvent}");
|
||||
}
|
||||
|
||||
// Let's trade the previous mapped contract, so we can hold it until expiration for testing
|
||||
// (will be sooner than the new mapped contract)
|
||||
_contractToTrade = _mappedSymbol;
|
||||
_mappedSymbol = _continuousContract.Mapped;
|
||||
}
|
||||
|
||||
// Let's trade after the mapping is done
|
||||
if (_contractToTrade != null && _boughtQuantity == 0 && Securities[_contractToTrade].Exchange.ExchangeOpen)
|
||||
{
|
||||
Buy(_contractToTrade, 1);
|
||||
}
|
||||
|
||||
if (_contractToTrade != null && slice.Delistings.TryGetValue(_contractToTrade, out var delisting))
|
||||
{
|
||||
if (delisting.Type == DelistingType.Delisted)
|
||||
{
|
||||
_delisted = true;
|
||||
|
||||
if (Portfolio.Invested)
|
||||
{
|
||||
throw new RegressionTestException($"{Time} - Portfolio should not be invested after the traded contract is delisted.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnOrderEvent(OrderEvent orderEvent)
|
||||
{
|
||||
if (orderEvent.Symbol != _contractToTrade)
|
||||
{
|
||||
throw new RegressionTestException($"{Time} - Unexpected order event symbol: {orderEvent.Symbol}. Expected {_contractToTrade}");
|
||||
}
|
||||
|
||||
if (orderEvent.Direction == OrderDirection.Buy)
|
||||
{
|
||||
if (orderEvent.Status == OrderStatus.Filled)
|
||||
{
|
||||
if (_boughtQuantity != 0 && _liquidatedQuantity != 0)
|
||||
{
|
||||
throw new RegressionTestException($"{Time} - Unexpected buy order event status: {orderEvent.Status}");
|
||||
}
|
||||
_boughtQuantity = orderEvent.Quantity;
|
||||
}
|
||||
}
|
||||
else if (orderEvent.Direction == OrderDirection.Sell)
|
||||
{
|
||||
if (orderEvent.Status == OrderStatus.Filled)
|
||||
{
|
||||
if (_boughtQuantity <= 0 && _liquidatedQuantity != 0)
|
||||
{
|
||||
throw new RegressionTestException($"{Time} - Unexpected sell order event status: {orderEvent.Status}");
|
||||
}
|
||||
_liquidatedQuantity = orderEvent.Quantity;
|
||||
|
||||
if (_liquidatedQuantity != -_boughtQuantity)
|
||||
{
|
||||
throw new RegressionTestException($"{Time} - Unexpected liquidated quantity: {_liquidatedQuantity}. Expected: {-_boughtQuantity}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnSecuritiesChanged(SecurityChanges changes)
|
||||
{
|
||||
foreach (var addedSecurity in changes.AddedSecurities)
|
||||
{
|
||||
if (addedSecurity.Symbol.SecurityType == SecurityType.Future && addedSecurity.Symbol.IsCanonical())
|
||||
{
|
||||
_mappedSymbol = _continuousContract.Mapped;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnEndOfAlgorithm()
|
||||
{
|
||||
if (_mappingsCount == 0)
|
||||
{
|
||||
throw new RegressionTestException($"Unexpected number of symbol changed events (mappings): {_mappingsCount}. Expected 1.");
|
||||
}
|
||||
|
||||
if (!_delisted)
|
||||
{
|
||||
throw new RegressionTestException("Contract was not delisted");
|
||||
}
|
||||
|
||||
// Make sure we traded and that the position was liquidated on delisting
|
||||
if (_boughtQuantity <= 0 || _liquidatedQuantity >= 0)
|
||||
{
|
||||
throw new RegressionTestException($"Unexpected sold quantity: {_boughtQuantity} and liquidated quantity: {_liquidatedQuantity}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <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 List<Language> Languages { get; } = new() { Language.CSharp, Language.Python };
|
||||
|
||||
/// <summary>
|
||||
/// Data Points count of all timeslices of algorithm
|
||||
/// </summary>
|
||||
public long DataPoints => 133945;
|
||||
|
||||
/// <summary>
|
||||
/// Data Points count of the algorithm history
|
||||
/// </summary>
|
||||
public int AlgorithmHistoryDataPoints => 26;
|
||||
|
||||
/// <summary>
|
||||
/// Final status of the algorithm
|
||||
/// </summary>
|
||||
public AlgorithmStatus AlgorithmStatus => AlgorithmStatus.Completed;
|
||||
|
||||
/// <summary>
|
||||
/// This is used by the regression test system to indicate what the expected statistics are from running the algorithm
|
||||
/// </summary>
|
||||
public Dictionary<string, string> ExpectedStatistics => new Dictionary<string, string>
|
||||
{
|
||||
{"Total Orders", "2"},
|
||||
{"Average Win", "0%"},
|
||||
{"Average Loss", "-0.11%"},
|
||||
{"Compounding Annual Return", "-1.667%"},
|
||||
{"Drawdown", "0.100%"},
|
||||
{"Expectancy", "-1"},
|
||||
{"Start Equity", "1000000"},
|
||||
{"End Equity", "998849.48"},
|
||||
{"Net Profit", "-0.115%"},
|
||||
{"Sharpe Ratio", "-34.455"},
|
||||
{"Sortino Ratio", "-57.336"},
|
||||
{"Probabilistic Sharpe Ratio", "0.002%"},
|
||||
{"Loss Rate", "100%"},
|
||||
{"Win Rate", "0%"},
|
||||
{"Profit-Loss Ratio", "0"},
|
||||
{"Alpha", "0"},
|
||||
{"Beta", "0"},
|
||||
{"Annual Standard Deviation", "0.002"},
|
||||
{"Annual Variance", "0"},
|
||||
{"Information Ratio", "-6.176"},
|
||||
{"Tracking Error", "0.002"},
|
||||
{"Treynor Ratio", "0"},
|
||||
{"Total Fees", "€1.02"},
|
||||
{"Estimated Strategy Capacity", "€2300000000.00"},
|
||||
{"Lowest Capacity Asset", "FESX YJHOAMPYKRS5"},
|
||||
{"Portfolio Turnover", "0.40%"},
|
||||
{"OrderListHash", "54040d29a467becaedcf59d79323321b"}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -43,12 +43,14 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
SetEndDate(2021, 1, 10);
|
||||
SetCash(1000000);
|
||||
|
||||
var spx = AddIndex("SPX").Symbol;
|
||||
|
||||
// regular option SPX contracts
|
||||
var spxOptions = AddIndexOption("SPX");
|
||||
var spxOptions = AddIndexOption(spx);
|
||||
spxOptions.SetFilter(u => u.Strikes(0, 1).Expiration(0, 30));
|
||||
|
||||
// weekly option SPX contracts
|
||||
var spxw = AddIndexOption("SPX", "SPXW");
|
||||
var spxw = AddIndexOption(spx, "SPXW");
|
||||
spxw.SetFilter(u => u.Strikes(0, 1)
|
||||
// single week ahead since there are many SPXW contracts and we want to preserve performance
|
||||
.Expiration(0, 7)
|
||||
|
||||
@@ -53,6 +53,7 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
// - 6th: AAPL is selected, TWX is removed but subscriptions are not removed because the securities are invested.
|
||||
// - TWX and its options are liquidated.
|
||||
// - 7th: Since options universe selection is daily now, TWX subscriptions are removed the next day (7th)
|
||||
//SetEndDate(2014, 06, 06);
|
||||
SetEndDate(2014, 06, 07);
|
||||
|
||||
var selectionUniverse = AddUniverse(enumerable => new[] { Time.Date <= new DateTime(2014, 6, 5) ? _twx : _aapl },
|
||||
|
||||
@@ -37,9 +37,9 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
|
||||
var equity = AddEquity("GOOG");
|
||||
|
||||
_optionSymbol = OptionChain(equity.Symbol)
|
||||
.OrderBy(x => x.ID.StrikePrice)
|
||||
.ThenByDescending(x => x.ID.Date)
|
||||
_optionSymbol = OptionChainProvider.GetOptionContractList(equity.Symbol, Time)
|
||||
.OrderBy(symbol => symbol.ID.StrikePrice)
|
||||
.ThenByDescending(symbol => symbol.ID.Date)
|
||||
.First(optionContract => optionContract.ID.OptionRight == OptionRight.Call);
|
||||
var option = AddOptionContract(_optionSymbol);
|
||||
|
||||
|
||||
@@ -51,7 +51,10 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
|
||||
if (_addOption)
|
||||
{
|
||||
var contracts = OptionChain(_spx).Where(x => x.ID.OptionRight == OptionRight.Put && x.ID.Date.Date == new DateTime(2021, 1, 15));
|
||||
var contracts = OptionChainProvider.GetOptionContractList(_spx, Time);
|
||||
contracts = contracts.Where(x =>
|
||||
x.ID.OptionRight == OptionRight.Put &&
|
||||
x.ID.Date.Date == new DateTime(2021, 1, 15));
|
||||
|
||||
var option = AddIndexOptionContract(contracts.First(), Resolution.Minute);
|
||||
_optionExpiry = option.Expiry;
|
||||
|
||||
@@ -52,7 +52,7 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
var _twxOption = AddOption("TWX", Resolution.Minute);
|
||||
_exchange = _twxOption.Exchange;
|
||||
_twxOption.SetFilter((x) => x
|
||||
.Contracts(c => c.Where(s => _contracts.Contains(s.Symbol.Value))));
|
||||
.Contracts(c => c.Select(x => x.Symbol).Where(s => _contracts.Contains(s.Value))));
|
||||
SetBenchmark(t => 1);
|
||||
}
|
||||
|
||||
|
||||
@@ -136,10 +136,10 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
{"Tracking Error", "0.456"},
|
||||
{"Treynor Ratio", "0"},
|
||||
{"Total Fees", "$2650.41"},
|
||||
{"Estimated Strategy Capacity", "$29000.00"},
|
||||
{"Estimated Strategy Capacity", "$30000.00"},
|
||||
{"Lowest Capacity Asset", "BTCUSD 2XR"},
|
||||
{"Portfolio Turnover", "46.79%"},
|
||||
{"OrderListHash", "70610cb67cc63d197e22ca71180b2df2"}
|
||||
{"OrderListHash", "864a3590199bfde14bed81bfbb8fcf70"}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,10 +58,10 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
Resolution.Minute).Symbol;
|
||||
|
||||
// Select a future option expiring ITM, and adds it to the algorithm.
|
||||
var esOptions = OptionChain(es20m20)
|
||||
.Concat(OptionChain(es20h20))
|
||||
.Where(contractData => contractData.ID.StrikePrice == 3200m && contractData.ID.OptionRight == OptionRight.Call)
|
||||
.Select(contractData => AddFutureOptionContract(contractData, Resolution.Minute).Symbol)
|
||||
var esOptions = OptionChainProvider.GetOptionContractList(es20m20, Time)
|
||||
.Concat(OptionChainProvider.GetOptionContractList(es20h20, Time))
|
||||
.Where(x => x.ID.StrikePrice == 3200m && x.ID.OptionRight == OptionRight.Call)
|
||||
.Select(x => AddFutureOptionContract(x, Resolution.Minute).Symbol)
|
||||
.ToList();
|
||||
|
||||
var expectedContracts = new[]
|
||||
|
||||
@@ -53,7 +53,7 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
Resolution.Minute).Symbol;
|
||||
|
||||
// Select a future option expiring ITM, and adds it to the algorithm.
|
||||
_esOption = AddFutureOptionContract(OptionChain(_es19m20)
|
||||
_esOption = AddFutureOptionContract(OptionChainProvider.GetOptionContractList(_es19m20, Time)
|
||||
.Where(x => x.ID.StrikePrice <= 3200m && x.ID.OptionRight == OptionRight.Call)
|
||||
.OrderByDescending(x => x.ID.StrikePrice)
|
||||
.Take(1)
|
||||
|
||||
@@ -55,7 +55,7 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
TimeSpan.FromMinutes(1));
|
||||
|
||||
// Select a future option expiring ITM, and adds it to the algorithm.
|
||||
_esOption = AddFutureOptionContract(OptionChain(_es19m20.Symbol)
|
||||
_esOption = AddFutureOptionContract(OptionChainProvider.GetOptionContractList(_es19m20.Symbol, new DateTime(2020, 1, 5))
|
||||
.Where(x => x.ID.StrikePrice <= 3200m && x.ID.OptionRight == OptionRight.Call)
|
||||
.OrderByDescending(x => x.ID.StrikePrice)
|
||||
.Take(1)
|
||||
|
||||
@@ -59,9 +59,9 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
Resolution.Minute).Symbol;
|
||||
|
||||
// Select a future option call expiring OTM, and adds it to the algorithm.
|
||||
_esOption = AddFutureOptionContract(OptionChain(_es19m20)
|
||||
.Where(contractData => contractData.ID.StrikePrice >= 3300m && contractData.ID.OptionRight == OptionRight.Call)
|
||||
.OrderBy(contractData => contractData.ID.StrikePrice)
|
||||
_esOption = AddFutureOptionContract(OptionChainProvider.GetOptionContractList(_es19m20, Time)
|
||||
.Where(x => x.ID.StrikePrice >= 3300m && x.ID.OptionRight == OptionRight.Call)
|
||||
.OrderBy(x => x.ID.StrikePrice)
|
||||
.Take(1)
|
||||
.Single(), Resolution.Minute).Symbol;
|
||||
|
||||
|
||||
@@ -47,7 +47,7 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
Resolution).Symbol;
|
||||
|
||||
// Attempt to fetch a specific future option contract
|
||||
DcOption = OptionChain(dc)
|
||||
DcOption = OptionChainProvider.GetOptionContractList(dc, Time)
|
||||
.Where(x => x.ID.StrikePrice == 17m && x.ID.OptionRight == OptionRight.Call)
|
||||
.Select(x => AddFutureOptionContract(x, Resolution).Symbol)
|
||||
.FirstOrDefault();
|
||||
|
||||
@@ -32,7 +32,7 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
var underlying = AddFutureContract(QuantConnect.Symbol.CreateFuture(Futures.Indices.SP500EMini, Market.CME, new DateTime(2020, 3, 20)),
|
||||
Resolution.Minute).Symbol;
|
||||
|
||||
var option = AddFutureOptionContract(OptionChain(underlying)
|
||||
var option = AddFutureOptionContract(OptionChainProvider.GetOptionContractList(underlying, Time)
|
||||
.Where(x => x.ID.StrikePrice <= 3200m && x.ID.OptionRight == OptionRight.Call)
|
||||
.OrderByDescending(x => x.ID.StrikePrice)
|
||||
.Take(1)
|
||||
|
||||
@@ -54,7 +54,7 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
Resolution.Minute).Symbol;
|
||||
|
||||
// Select a future option expiring ITM, and adds it to the algorithm.
|
||||
_esOption = AddFutureOptionContract(OptionChain(_es19m20)
|
||||
_esOption = AddFutureOptionContract(OptionChainProvider.GetOptionContractList(_es19m20, Time)
|
||||
.Where(x => x.ID.StrikePrice >= 3300m && x.ID.OptionRight == OptionRight.Put)
|
||||
.OrderBy(x => x.ID.StrikePrice)
|
||||
.Take(1)
|
||||
|
||||
@@ -58,7 +58,7 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
Resolution.Minute).Symbol;
|
||||
|
||||
// Select a future option expiring ITM, and adds it to the algorithm.
|
||||
_esOption = AddFutureOptionContract(OptionChain(_es19m20)
|
||||
_esOption = AddFutureOptionContract(OptionChainProvider.GetOptionContractList(_es19m20, Time)
|
||||
.Where(x => x.ID.StrikePrice <= 3150m && x.ID.OptionRight == OptionRight.Put)
|
||||
.OrderByDescending(x => x.ID.StrikePrice)
|
||||
.Take(1)
|
||||
|
||||
@@ -54,7 +54,7 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
Resolution.Minute).Symbol;
|
||||
|
||||
// Select a future option expiring ITM, and adds it to the algorithm.
|
||||
_esOption = AddFutureOptionContract(OptionChain(_es19m20)
|
||||
_esOption = AddFutureOptionContract(OptionChainProvider.GetOptionContractList(_es19m20, Time)
|
||||
.Where(x => x.ID.StrikePrice <= 3100m && x.ID.OptionRight == OptionRight.Call)
|
||||
.OrderByDescending(x => x.ID.StrikePrice)
|
||||
.Take(1)
|
||||
|
||||
@@ -55,7 +55,7 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
Resolution.Minute).Symbol;
|
||||
|
||||
// Select a future option expiring ITM, and adds it to the algorithm.
|
||||
_esOption = AddFutureOptionContract(OptionChain(_es19m20)
|
||||
_esOption = AddFutureOptionContract(OptionChainProvider.GetOptionContractList(_es19m20, Time)
|
||||
.Where(x => x.ID.StrikePrice >= 3400m && x.ID.OptionRight == OptionRight.Call)
|
||||
.OrderBy(x => x.ID.StrikePrice)
|
||||
.Take(1)
|
||||
|
||||
@@ -54,7 +54,7 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
Resolution.Minute).Symbol;
|
||||
|
||||
// Select a future option expiring ITM, and adds it to the algorithm.
|
||||
_esOption = AddFutureOptionContract(OptionChain(_es19m20)
|
||||
_esOption = AddFutureOptionContract(OptionChainProvider.GetOptionContractList(_es19m20, Time)
|
||||
.Where(x => x.ID.StrikePrice <= 3400m && x.ID.OptionRight == OptionRight.Put)
|
||||
.OrderByDescending(x => x.ID.StrikePrice)
|
||||
.Take(1)
|
||||
|
||||
@@ -55,7 +55,7 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
Resolution.Minute).Symbol;
|
||||
|
||||
// Select a future option expiring ITM, and adds it to the algorithm.
|
||||
_esOption = AddFutureOptionContract(OptionChain(_es19m20)
|
||||
_esOption = AddFutureOptionContract(OptionChainProvider.GetOptionContractList(_es19m20, Time)
|
||||
.Where(x => x.ID.StrikePrice <= 3000m && x.ID.OptionRight == OptionRight.Put)
|
||||
.OrderByDescending(x => x.ID.StrikePrice)
|
||||
.Take(1)
|
||||
|
||||
@@ -46,7 +46,7 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
var spx = AddIndex("SPX", Resolution.Minute).Symbol;
|
||||
|
||||
// Select a index option expiring ITM, and adds it to the algorithm.
|
||||
var spxOptions = OptionChain(spx)
|
||||
var spxOptions = OptionChainProvider.GetOptionContractList(spx, Time)
|
||||
.Where(x => (x.ID.StrikePrice == 3700m || x.ID.StrikePrice == 3800m) && x.ID.OptionRight == OptionRight.Call && x.ID.Date.Year == 2021 && x.ID.Date.Month == 1)
|
||||
.Select(x => AddIndexOptionContract(x, Resolution.Minute).Symbol)
|
||||
.OrderBy(x => x.ID.StrikePrice)
|
||||
|
||||
@@ -51,7 +51,7 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
_spx = AddIndex("SPX", Resolution).Symbol;
|
||||
|
||||
// Select an index option expiring ITM, and adds it to the algorithm.
|
||||
_spxOption = AddIndexOptionContract(OptionChain(_spx)
|
||||
_spxOption = AddIndexOptionContract(OptionChainProvider.GetOptionContractList(_spx, Time)
|
||||
.Where(x => x.ID.StrikePrice <= 3200m && x.ID.OptionRight == OptionRight.Call && x.ID.Date.Year == 2021 && x.ID.Date.Month == 1)
|
||||
.OrderByDescending(x => x.ID.StrikePrice)
|
||||
.Take(1)
|
||||
|
||||
@@ -45,7 +45,7 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
_spx = spx.Symbol;
|
||||
|
||||
// Select an index option expiring ITM, and adds it to the algorithm.
|
||||
_spxOption = AddIndexOptionContract(OptionChain(_spx)
|
||||
_spxOption = AddIndexOptionContract(OptionChainProvider.GetOptionContractList(_spx, Time)
|
||||
.Where(x => x.ID.StrikePrice <= 3200m && x.ID.OptionRight == OptionRight.Call && x.ID.Date.Year == 2021 && x.ID.Date.Month == 1)
|
||||
.OrderByDescending(x => x.ID.StrikePrice)
|
||||
.Take(1)
|
||||
|
||||
@@ -56,7 +56,7 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
_spx = AddIndex("SPX", Resolution).Symbol;
|
||||
|
||||
// Select a index option call expiring OTM, and adds it to the algorithm.
|
||||
_spxOption = AddIndexOptionContract(OptionChain(_spx)
|
||||
_spxOption = AddIndexOptionContract(OptionChainProvider.GetOptionContractList(_spx, Time)
|
||||
.Where(x => x.ID.StrikePrice >= 4250m && x.ID.OptionRight == OptionRight.Call && x.ID.Date.Year == 2021 && x.ID.Date.Month == 1)
|
||||
.OrderBy(x => x.ID.StrikePrice)
|
||||
.Take(1)
|
||||
|
||||
@@ -48,7 +48,7 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
_spx = AddIndex("SPX", Resolution.Minute).Symbol;
|
||||
|
||||
// Select a index option expiring ITM, and adds it to the algorithm.
|
||||
_spxOption = AddIndexOptionContract(OptionChain(_spx)
|
||||
_spxOption = AddIndexOptionContract(OptionChainProvider.GetOptionContractList(_spx, Time)
|
||||
.Where(x => x.ID.StrikePrice >= 4200m && x.ID.OptionRight == OptionRight.Put && x.ID.Date.Year == 2021 && x.ID.Date.Month == 1)
|
||||
.OrderBy(x => x.ID.StrikePrice)
|
||||
.Take(1)
|
||||
|
||||
@@ -53,7 +53,7 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
_spx = AddIndex("SPX", Resolution.Minute).Symbol;
|
||||
|
||||
// Select a index option expiring ITM, and adds it to the algorithm.
|
||||
_spxOption = AddIndexOptionContract(OptionChain(_spx)
|
||||
_spxOption = AddIndexOptionContract(OptionChainProvider.GetOptionContractList(_spx, Time)
|
||||
.Where(x => x.ID.StrikePrice <= 3200m && x.ID.OptionRight == OptionRight.Put && x.ID.Date.Year == 2021 && x.ID.Date.Month == 1)
|
||||
.OrderByDescending(x => x.ID.StrikePrice)
|
||||
.Take(1)
|
||||
|
||||
@@ -60,9 +60,9 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
_spx = AddIndex("SPX", Resolution.Minute).Symbol;
|
||||
|
||||
// Select a index option expiring ITM, and adds it to the algorithm.
|
||||
_esOption = AddIndexOptionContract(OptionChain(_spx)
|
||||
.Where(contractData => contractData.ID.StrikePrice <= 3200m && contractData.ID.OptionRight == OptionRight.Call && contractData.ID.Date.Year == 2021 && contractData.ID.Date.Month == 1)
|
||||
.OrderByDescending(contractData => contractData.ID.StrikePrice)
|
||||
_esOption = AddIndexOptionContract(OptionChainProvider.GetOptionContractList(_spx, Time)
|
||||
.Where(x => x.ID.StrikePrice <= 3200m && x.ID.OptionRight == OptionRight.Call && x.ID.Date.Year == 2021 && x.ID.Date.Month == 1)
|
||||
.OrderByDescending(x => x.ID.StrikePrice)
|
||||
.Take(1)
|
||||
.Single(), Resolution.Minute).Symbol;
|
||||
|
||||
|
||||
@@ -50,7 +50,7 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
_spx = AddIndex("SPX", Resolution.Minute).Symbol;
|
||||
|
||||
// Select a index option expiring ITM, and adds it to the algorithm.
|
||||
_spxOption = AddIndexOptionContract(OptionChain(_spx)
|
||||
_spxOption = AddIndexOptionContract(OptionChainProvider.GetOptionContractList(_spx, Time)
|
||||
.Where(x => x.ID.StrikePrice >= 4250m && x.ID.OptionRight == OptionRight.Call && x.ID.Date.Year == 2021 && x.ID.Date.Month == 1)
|
||||
.OrderBy(x => x.ID.StrikePrice)
|
||||
.Take(1)
|
||||
|
||||
@@ -59,9 +59,9 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
_spx = AddIndex("SPX", Resolution.Minute).Symbol;
|
||||
|
||||
// Select a index option expiring ITM, and adds it to the algorithm.
|
||||
_spxOption = AddIndexOptionContract(OptionChain(_spx)
|
||||
.Where(contractData => contractData.ID.StrikePrice <= 4200m && contractData.ID.OptionRight == OptionRight.Put && contractData.ID.Date.Year == 2021 && contractData.ID.Date.Month == 1)
|
||||
.OrderByDescending(contractData => contractData.ID.StrikePrice)
|
||||
_spxOption = AddIndexOptionContract(OptionChainProvider.GetOptionContractList(_spx, Time)
|
||||
.Where(x => x.ID.StrikePrice <= 4200m && x.ID.OptionRight == OptionRight.Put && x.ID.Date.Year == 2021 && x.ID.Date.Month == 1)
|
||||
.OrderByDescending(x => x.ID.StrikePrice)
|
||||
.Take(1)
|
||||
.Single(), Resolution.Minute).Symbol;
|
||||
|
||||
|
||||
@@ -50,7 +50,7 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
_spx = AddIndex("SPX", Resolution.Minute).Symbol;
|
||||
|
||||
// Select a index option expiring ITM, and adds it to the algorithm.
|
||||
_spxOption = AddIndexOptionContract(OptionChain(_spx)
|
||||
_spxOption = AddIndexOptionContract(OptionChainProvider.GetOptionContractList(_spx, Time)
|
||||
.Where(x => x.ID.StrikePrice <= 3200m && x.ID.OptionRight == OptionRight.Put && x.ID.Date.Year == 2021 && x.ID.Date.Month == 1)
|
||||
.OrderByDescending(x => x.ID.StrikePrice)
|
||||
.Take(1)
|
||||
|
||||
@@ -105,7 +105,7 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
/// <summary>
|
||||
/// Data Points count of the algorithm history
|
||||
/// </summary>
|
||||
public int AlgorithmHistoryDataPoints => 69;
|
||||
public int AlgorithmHistoryDataPoints => 70;
|
||||
|
||||
/// <summary>
|
||||
/// Final status of the algorithm
|
||||
|
||||
@@ -128,6 +128,7 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
if (_futureContract == null)
|
||||
{
|
||||
_futureContract = futureChain.TradeBars.Values.FirstOrDefault().Symbol;
|
||||
return;
|
||||
}
|
||||
|
||||
if (futureChain.TradeBars.TryGetValue(_futureContract, out var value))
|
||||
@@ -152,24 +153,23 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
throw new RegressionTestException("At least one trade bar should have been found, but none was found");
|
||||
}
|
||||
|
||||
var backtestDays = (EndDate - StartDate).Days;
|
||||
var futureIndicator = new Identity("");
|
||||
var futureVolumeHistory = IndicatorHistory(futureIndicator, _futureContract, backtestDays, Resolution.Daily, Field.Volume);
|
||||
var futureVolumeHistory = IndicatorHistory(futureIndicator, _futureContract, 200, Resolution.Daily, Field.Volume);
|
||||
if (Math.Abs(futureVolumeHistory.Current.Select(x => x.Value).Where(x => x != 0).Average() - _futurePoints.Average()) > 0.001m)
|
||||
{
|
||||
throw new RegressionTestException($"No history indicator future data point was found using Field.Volume selector for {_futureContract}!");
|
||||
throw new Exception("No history indicator future data point was found using Field.Volume selector!");
|
||||
}
|
||||
|
||||
var volumeHistory = IndicatorHistory(_tradebarIndicatorHistory, _aapl, 109, Resolution.Daily, Field.Volume);
|
||||
if (Math.Abs(volumeHistory.Current.Select(x => x.Value).Average() - _aaplPoints.Average()) > 0.001m)
|
||||
{
|
||||
throw new RegressionTestException($"No history indicator data point was found using Field.Volume selector for {_aapl}!");
|
||||
throw new Exception("No history indicator data point was found using Field.Volume selector!");
|
||||
}
|
||||
|
||||
var bidCloseHistory = IndicatorHistory(_quotebarIndicatorHistory, _eurusd, 132, Resolution.Daily, Field.BidClose);
|
||||
if (Math.Abs(bidCloseHistory.Current.Select(x => x.Value).Average() - _eurusdPoints.Average()) > 0.001m)
|
||||
{
|
||||
throw new RegressionTestException($"No history indicator data point was found using Field.BidClose selector for {_eurusd}!");
|
||||
throw new Exception("No history indicator data point was found using Field.BidClose selector!");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -191,7 +191,7 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
/// <summary>
|
||||
/// Data Points count of the algorithm history
|
||||
/// </summary>
|
||||
public int AlgorithmHistoryDataPoints => 351;
|
||||
public int AlgorithmHistoryDataPoints => 354;
|
||||
|
||||
/// <summary>
|
||||
/// Final status of the algorithm
|
||||
|
||||
@@ -44,7 +44,7 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
|
||||
_stock = AddEquity("GOOG").Symbol;
|
||||
|
||||
var contracts = OptionChain(_stock).ToList();
|
||||
var contracts = OptionChainProvider.GetOptionContractList(_stock, UtcTime).ToList();
|
||||
_option = contracts
|
||||
.Where(c => c.ID.OptionRight == OptionRight.Put)
|
||||
.OrderBy(c => c.ID.Date)
|
||||
|
||||
@@ -111,7 +111,7 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
/// <summary>
|
||||
/// Data Points count of the algorithm history
|
||||
/// </summary>
|
||||
public int AlgorithmHistoryDataPoints => 7;
|
||||
public int AlgorithmHistoryDataPoints => 6;
|
||||
|
||||
/// <summary>
|
||||
/// Final status of the algorithm
|
||||
|
||||
@@ -46,7 +46,7 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
SetCash(100000);
|
||||
Stock = AddEquity("GOOG", Resolution.Minute);
|
||||
|
||||
var contracts = OptionChain(Stock.Symbol).ToList();
|
||||
var contracts = OptionChainProvider.GetOptionContractList(Stock.Symbol, UtcTime).ToList();
|
||||
|
||||
PutOptionSymbol = contracts
|
||||
.Where(c => c.ID.OptionRight == OptionRight.Put)
|
||||
|
||||
@@ -48,7 +48,7 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
|
||||
_goog = AddEquity("GOOG", Resolution.Minute);
|
||||
|
||||
var contracts = OptionChain(_goog.Symbol).ToList();
|
||||
var contracts = OptionChainProvider.GetOptionContractList(_goog.Symbol, UtcTime).ToList();
|
||||
|
||||
_googCall600Symbol = contracts
|
||||
.Where(c => c.ID.OptionRight == OptionRight.Call)
|
||||
|
||||
@@ -1,127 +0,0 @@
|
||||
/*
|
||||
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
|
||||
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using QuantConnect.Data;
|
||||
using QuantConnect.Interfaces;
|
||||
using QuantConnect.Securities;
|
||||
|
||||
namespace QuantConnect.Algorithm.CSharp
|
||||
{
|
||||
/// <summary>
|
||||
/// Regression algorithm illustrating the usage of the <see cref="QCAlgorithm.OptionChain(Symbol)"/> method
|
||||
/// to get an option chain, which contains additional data besides the symbols, including prices, implied volatility and greeks.
|
||||
/// It also shows how this data can be used to filter the contracts based on certain criteria.
|
||||
/// </summary>
|
||||
public class OptionChainFullDataRegressionAlgorithm : QCAlgorithm, IRegressionAlgorithmDefinition
|
||||
{
|
||||
private Symbol _optionContract;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
SetStartDate(2015, 12, 24);
|
||||
SetEndDate(2015, 12, 24);
|
||||
SetCash(100000);
|
||||
|
||||
var goog = AddEquity("GOOG").Symbol;
|
||||
|
||||
_optionContract = OptionChain(goog)
|
||||
// Get contracts expiring within 10 days, with an implied volatility greater than 0.5 and a delta less than 0.5
|
||||
.Where(contractData => contractData.ID.Date - Time <= TimeSpan.FromDays(10) &&
|
||||
contractData.ImpliedVolatility > 0.5m &&
|
||||
contractData.Greeks.Delta < 0.5m)
|
||||
// Get the contract with the latest expiration date
|
||||
.OrderByDescending(x => x.ID.Date)
|
||||
.First();
|
||||
|
||||
AddOptionContract(_optionContract);
|
||||
}
|
||||
|
||||
public override void OnData(Slice slice)
|
||||
{
|
||||
// Do some trading with the selected contract for sample purposes
|
||||
if (!Portfolio.Invested)
|
||||
{
|
||||
MarketOrder(_optionContract, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
Liquidate();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This is used by the regression test system to indicate if the open source Lean repository has the required data to run this algorithm.
|
||||
/// </summary>
|
||||
public bool CanRunLocally { get; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// This is used by the regression test system to indicate which languages this algorithm is written in.
|
||||
/// </summary>
|
||||
public virtual List<Language> Languages { get; } = new() { Language.CSharp, Language.Python };
|
||||
|
||||
/// <summary>
|
||||
/// Data Points count of all timeslices of algorithm
|
||||
/// </summary>
|
||||
public long DataPoints => 1057;
|
||||
|
||||
/// <summary>
|
||||
/// Data Points count of the algorithm history
|
||||
/// </summary>
|
||||
public int AlgorithmHistoryDataPoints => 1;
|
||||
|
||||
/// <summary>
|
||||
/// Final status of the algorithm
|
||||
/// </summary>
|
||||
public AlgorithmStatus AlgorithmStatus => AlgorithmStatus.Completed;
|
||||
|
||||
/// <summary>
|
||||
/// This is used by the regression test system to indicate what the expected statistics are from running the algorithm
|
||||
/// </summary>
|
||||
public Dictionary<string, string> ExpectedStatistics => new Dictionary<string, string>
|
||||
{
|
||||
{"Total Orders", "210"},
|
||||
{"Average Win", "0%"},
|
||||
{"Average Loss", "0%"},
|
||||
{"Compounding Annual Return", "0%"},
|
||||
{"Drawdown", "0%"},
|
||||
{"Expectancy", "0"},
|
||||
{"Start Equity", "100000"},
|
||||
{"End Equity", "96041"},
|
||||
{"Net Profit", "0%"},
|
||||
{"Sharpe Ratio", "0"},
|
||||
{"Sortino Ratio", "0"},
|
||||
{"Probabilistic Sharpe Ratio", "0%"},
|
||||
{"Loss Rate", "0%"},
|
||||
{"Win Rate", "0%"},
|
||||
{"Profit-Loss Ratio", "0"},
|
||||
{"Alpha", "0"},
|
||||
{"Beta", "0"},
|
||||
{"Annual Standard Deviation", "0"},
|
||||
{"Annual Variance", "0"},
|
||||
{"Information Ratio", "0"},
|
||||
{"Tracking Error", "0"},
|
||||
{"Treynor Ratio", "0"},
|
||||
{"Total Fees", "$209.00"},
|
||||
{"Estimated Strategy Capacity", "$0"},
|
||||
{"Lowest Capacity Asset", "GOOCV W6U7PD1F2WYU|GOOCV VP83T1ZUHROL"},
|
||||
{"Portfolio Turnover", "85.46%"},
|
||||
{"OrderListHash", "a7ab1a9e64fe9ba76ea33a40a78a4e3b"}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -96,7 +96,7 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
|
||||
protected override OptionFilterUniverse Filter(OptionFilterUniverse filter)
|
||||
{
|
||||
return filter.BackMonth().Contracts(contracts => contracts.Take(15));
|
||||
return filter.BackMonth().Contracts(filter.Take(15).Select(x => x.Symbol));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -63,7 +63,7 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
}
|
||||
return universe.IncludeWeeklys()
|
||||
.BackMonth() // back month so that they don't get removed because of being delisted
|
||||
.Contracts(contracts => contracts.Take(5));
|
||||
.Contracts(universe.Take(5).Select(x => x.Symbol));
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -95,7 +95,7 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
/// <summary>
|
||||
/// Data Points count of all timeslices of algorithm
|
||||
/// </summary>
|
||||
public long DataPoints => 19701;
|
||||
public long DataPoints => 19700;
|
||||
|
||||
/// <summary>
|
||||
/// Data Points count of the algorithm history
|
||||
|
||||
@@ -44,11 +44,11 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
var option = AddOption("AAPL", Resolution.Minute);
|
||||
_option = option.Symbol;
|
||||
|
||||
option.SetFilter(universe => from contract in universe
|
||||
option.SetFilter(universe => from symbol in universe
|
||||
.WeeklysOnly()
|
||||
.Strikes(-5, +5)
|
||||
.Expiration(TimeSpan.Zero, TimeSpan.FromDays(29))
|
||||
select contract.Symbol);
|
||||
select symbol.Symbol);
|
||||
}
|
||||
|
||||
public override void OnOrderEvent(OrderEvent orderEvent)
|
||||
|
||||
@@ -58,7 +58,7 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
Resolution.Minute).Symbol;
|
||||
|
||||
// Select a future option call expiring OTM, and adds it to the algorithm.
|
||||
_esOption = AddFutureOptionContract(OptionChain(_es19m20)
|
||||
_esOption = AddFutureOptionContract(OptionChainProvider.GetOptionContractList(_es19m20, Time)
|
||||
.Where(x => x.ID.StrikePrice >= 3300m && x.ID.OptionRight == OptionRight.Call)
|
||||
.OrderBy(x => x.ID.StrikePrice)
|
||||
.Take(1)
|
||||
|
||||
@@ -1,137 +0,0 @@
|
||||
/*
|
||||
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
|
||||
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using QuantConnect.Data;
|
||||
using QuantConnect.Interfaces;
|
||||
using QuantConnect.Data.Market;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace QuantConnect.Algorithm.CSharp
|
||||
{
|
||||
/// <summary>
|
||||
/// Regression algorithm asserting the resolution being used for options universe and it's data respecting universe settings
|
||||
/// </summary>
|
||||
public class OptionResolutionRegressionAlgorithm : QCAlgorithm, IRegressionAlgorithmDefinition
|
||||
{
|
||||
private Symbol _optionSymbol;
|
||||
public override void Initialize()
|
||||
{
|
||||
SetStartDate(2015, 12, 24);
|
||||
SetEndDate(2015, 12, 24);
|
||||
SetCash(100000);
|
||||
|
||||
UniverseSettings.Resolution = Resolution.Daily;
|
||||
|
||||
var option = AddOption("GOOG");
|
||||
option.SetFilter(u => u.Strikes(-2, +2).Expiration(0, 180));
|
||||
_optionSymbol = option.Symbol;
|
||||
|
||||
if (UniverseManager.TryGetValue(option.Symbol, out var universe)
|
||||
&& (universe.Configuration.Resolution != Resolution.Daily || universe.UniverseSettings.Resolution != Resolution.Daily))
|
||||
{
|
||||
throw new RegressionTestException("Unexpected universe resolution configuration!");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Event - v3.0 DATA EVENT HANDLER: (Pattern) Basic template for user to override for receiving all subscription data in a single event
|
||||
/// </summary>
|
||||
/// <param name="slice">The current slice of data keyed by symbol string</param>
|
||||
public override void OnData(Slice slice)
|
||||
{
|
||||
if (!Portfolio.Invested)
|
||||
{
|
||||
OptionChain chain;
|
||||
if (slice.OptionChains.TryGetValue(_optionSymbol, out chain))
|
||||
{
|
||||
// we find at the money (ATM) put contract with farthest expiration
|
||||
var atmContract = chain
|
||||
.OrderByDescending(x => x.Expiry)
|
||||
.ThenBy(x => Math.Abs(chain.Underlying.Price - x.Strike))
|
||||
.ThenByDescending(x => x.Right)
|
||||
.FirstOrDefault();
|
||||
|
||||
if (atmContract != null)
|
||||
{
|
||||
// if found, trade it
|
||||
MarketOrder(atmContract.Symbol, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <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 List<Language> Languages { get; } = new() { Language.CSharp };
|
||||
|
||||
/// <summary>
|
||||
/// Data Points count of all timeslices of algorithm
|
||||
/// </summary>
|
||||
public long DataPoints => 4274;
|
||||
|
||||
/// <summary>
|
||||
/// Data Points count of the algorithm history
|
||||
/// </summary>
|
||||
public int AlgorithmHistoryDataPoints => 0;
|
||||
|
||||
/// <summary>
|
||||
/// Final status of the algorithm
|
||||
/// </summary>
|
||||
public AlgorithmStatus AlgorithmStatus => AlgorithmStatus.Completed;
|
||||
|
||||
/// <summary>
|
||||
/// This is used by the regression test system to indicate what the expected statistics are from running the algorithm
|
||||
/// </summary>
|
||||
public Dictionary<string, string> ExpectedStatistics => new Dictionary<string, string>
|
||||
{
|
||||
{"Total Orders", "1"},
|
||||
{"Average Win", "0%"},
|
||||
{"Average Loss", "0%"},
|
||||
{"Compounding Annual Return", "0%"},
|
||||
{"Drawdown", "0%"},
|
||||
{"Expectancy", "0"},
|
||||
{"Start Equity", "100000"},
|
||||
{"End Equity", "100000"},
|
||||
{"Net Profit", "0%"},
|
||||
{"Sharpe Ratio", "0"},
|
||||
{"Sortino Ratio", "0"},
|
||||
{"Probabilistic Sharpe Ratio", "0%"},
|
||||
{"Loss Rate", "0%"},
|
||||
{"Win Rate", "0%"},
|
||||
{"Profit-Loss Ratio", "0"},
|
||||
{"Alpha", "0"},
|
||||
{"Beta", "0"},
|
||||
{"Annual Standard Deviation", "0"},
|
||||
{"Annual Variance", "0"},
|
||||
{"Information Ratio", "0"},
|
||||
{"Tracking Error", "0"},
|
||||
{"Treynor Ratio", "0"},
|
||||
{"Total Fees", "$0.00"},
|
||||
{"Estimated Strategy Capacity", "$0"},
|
||||
{"Lowest Capacity Asset", ""},
|
||||
{"Portfolio Turnover", "0%"},
|
||||
{"OrderListHash", "ce4cdd4d05199b633559cd14bc6db237"}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -36,7 +36,7 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
SetEndDate(2014, 06, 09);
|
||||
|
||||
var equitySymbol = AddEquity("TWX").Symbol;
|
||||
var contracts = OptionChain(equitySymbol).ToList();
|
||||
var contracts = OptionChainProvider.GetOptionContractList(equitySymbol, UtcTime).ToList();
|
||||
|
||||
var callOptionSymbol = contracts
|
||||
.Where(c => c.ID.OptionRight == OptionRight.Call)
|
||||
|
||||
@@ -54,7 +54,7 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
_lastSliceTime = Time;
|
||||
|
||||
var underlyingPrice = Securities[_symbol].Price;
|
||||
var contractSymbol = OptionChain(_symbol)
|
||||
var contractSymbol = OptionChainProvider.GetOptionContractList(_symbol, Time)
|
||||
.Where(x => x.ID.StrikePrice - underlyingPrice > 0)
|
||||
.OrderBy(x => x.ID.Date)
|
||||
.FirstOrDefault();
|
||||
@@ -91,7 +91,7 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
/// <summary>
|
||||
/// Data Points count of the algorithm history
|
||||
/// </summary>
|
||||
public int AlgorithmHistoryDataPoints => 787;
|
||||
public int AlgorithmHistoryDataPoints => 3;
|
||||
|
||||
/// <summary>
|
||||
/// Final status of the algorithm
|
||||
|
||||
@@ -71,9 +71,9 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
|
||||
var option = AddOption("AAPL");
|
||||
if (SubscriptionManager.SubscriptionDataConfigService.GetSubscriptionDataConfigs(option.Symbol)
|
||||
.Any(config => config.Resolution != Resolution.Daily))
|
||||
.Any(config => config.Resolution != Resolution.Minute))
|
||||
{
|
||||
throw new RegressionTestException("Was expecting resolution to be set to Daily");
|
||||
throw new RegressionTestException("Was expecting resolution to be set to Minute");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
|
||||
|
||||
/*
|
||||
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
|
||||
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
|
||||
@@ -43,7 +43,7 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
AddEquity("AAPL", Resolution.Daily);
|
||||
_equitySymbol = AddEquity("TWX", Resolution.Minute).Symbol;
|
||||
|
||||
var contracts = OptionChain(_equitySymbol).ToList();
|
||||
var contracts = OptionChainProvider.GetOptionContractList(_equitySymbol, UtcTime).ToList();
|
||||
|
||||
var callOptionSymbol = contracts
|
||||
.Where(c => c.ID.OptionRight == OptionRight.Call)
|
||||
|
||||
@@ -1,147 +0,0 @@
|
||||
/*
|
||||
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
|
||||
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using QuantConnect.Interfaces;
|
||||
using QuantConnect.Data.UniverseSelection;
|
||||
using QuantConnect.Securities;
|
||||
|
||||
namespace QuantConnect.Algorithm.CSharp
|
||||
{
|
||||
/// <summary>
|
||||
/// Algorithm asserting that options are selected every day and that selection for 0DTE contracts works as expected,
|
||||
/// always including the contracts that expire the same date the option chain belongs to.
|
||||
/// </summary>
|
||||
public class ZeroDTEOptionsRegressionAlgorithm : QCAlgorithm, IRegressionAlgorithmDefinition
|
||||
{
|
||||
private List<DateTime> _selectionDays;
|
||||
private int _currentSelectionDayIndex;
|
||||
|
||||
private int _previouslyAddedContracts;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
SetStartDate(2024, 01, 01);
|
||||
SetEndDate(2024, 01, 10);
|
||||
SetCash(100000);
|
||||
|
||||
var equity = AddEquity("SPY");
|
||||
var option = AddOption(equity.Symbol);
|
||||
|
||||
option.SetFilter(u => u.IncludeWeeklys().Expiration(0, 0));
|
||||
|
||||
// use the underlying equity as the benchmark
|
||||
SetBenchmark(equity.Symbol);
|
||||
|
||||
_selectionDays = new List<DateTime>()
|
||||
{
|
||||
new DateTime(2024, 01, 01), // Sunday midnight, already Monday 1st, it's a holiday. Selection happens for Tuesday here
|
||||
new DateTime(2024, 01, 03), // Wednesday, midnight
|
||||
new DateTime(2024, 01, 04),
|
||||
new DateTime(2024, 01, 05),
|
||||
new DateTime(2024, 01, 06), // Friday midnight, selection happens for Monday here
|
||||
new DateTime(2024, 01, 09), // Monday midnight, already Tuesday, selection happens for Tuesday here
|
||||
new DateTime(2024, 01, 10),
|
||||
};
|
||||
}
|
||||
|
||||
public override void OnSecuritiesChanged(SecurityChanges changes)
|
||||
{
|
||||
// We expect selection every trading day
|
||||
if (Time.Date != _selectionDays[_currentSelectionDayIndex++])
|
||||
{
|
||||
throw new RegressionTestException($"Unexpected date. Expected {_selectionDays[_currentSelectionDayIndex]} but was {Time.Date}");
|
||||
}
|
||||
|
||||
var addedOptions = changes.AddedSecurities.Where(x => x.Symbol.SecurityType == SecurityType.Option && !x.Symbol.IsCanonical()).ToList();
|
||||
|
||||
if (addedOptions.Count == 0)
|
||||
{
|
||||
throw new RegressionTestException("No options were added");
|
||||
}
|
||||
|
||||
var removedOptions = changes.RemovedSecurities.Where(x => x.Symbol.SecurityType == SecurityType.Option && !x.Symbol.IsCanonical()).ToList();
|
||||
|
||||
// Since we are selecting only 0DTE contracts, they must be deselected that same day
|
||||
if (removedOptions.Count != _previouslyAddedContracts)
|
||||
{
|
||||
throw new RegressionTestException($"Unexpected number of removed contracts. Expected {_previouslyAddedContracts} but was {removedOptions.Count}");
|
||||
}
|
||||
_previouslyAddedContracts = addedOptions.Count;
|
||||
}
|
||||
|
||||
/// <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 List<Language> Languages { get; } = new() { Language.CSharp };
|
||||
|
||||
/// <summary>
|
||||
/// Data Points count of all timeslices of algorithm
|
||||
/// </summary>
|
||||
public long DataPoints => 227;
|
||||
|
||||
/// <summary>
|
||||
/// Data Points count of the algorithm history
|
||||
/// </summary>
|
||||
public int AlgorithmHistoryDataPoints => 0;
|
||||
|
||||
/// <summary>
|
||||
/// Final status of the algorithm
|
||||
/// </summary>
|
||||
public AlgorithmStatus AlgorithmStatus => AlgorithmStatus.Completed;
|
||||
|
||||
/// <summary>
|
||||
/// This is used by the regression test system to indicate what the expected statistics are from running the algorithm
|
||||
/// </summary>
|
||||
public Dictionary<string, string> ExpectedStatistics => new Dictionary<string, string>
|
||||
{
|
||||
{"Total Orders", "0"},
|
||||
{"Average Win", "0%"},
|
||||
{"Average Loss", "0%"},
|
||||
{"Compounding Annual Return", "0%"},
|
||||
{"Drawdown", "0%"},
|
||||
{"Expectancy", "0"},
|
||||
{"Start Equity", "100000"},
|
||||
{"End Equity", "100000"},
|
||||
{"Net Profit", "0%"},
|
||||
{"Sharpe Ratio", "0"},
|
||||
{"Sortino Ratio", "0"},
|
||||
{"Probabilistic Sharpe Ratio", "0%"},
|
||||
{"Loss Rate", "0%"},
|
||||
{"Win Rate", "0%"},
|
||||
{"Profit-Loss Ratio", "0"},
|
||||
{"Alpha", "0"},
|
||||
{"Beta", "0"},
|
||||
{"Annual Standard Deviation", "0"},
|
||||
{"Annual Variance", "0"},
|
||||
{"Information Ratio", "0"},
|
||||
{"Tracking Error", "0"},
|
||||
{"Treynor Ratio", "0"},
|
||||
{"Total Fees", "$0.00"},
|
||||
{"Estimated Strategy Capacity", "$0"},
|
||||
{"Lowest Capacity Asset", ""},
|
||||
{"Portfolio Turnover", "0%"},
|
||||
{"OrderListHash", "d41d8cd98f00b204e9800998ecf8427e"}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -43,7 +43,7 @@ class AddOptionContractExpiresRegressionAlgorithm(QCAlgorithm):
|
||||
data: Slice object keyed by symbol containing the stock data
|
||||
'''
|
||||
if self._option == None:
|
||||
options = self.option_chain(self._twx)
|
||||
options = self.option_chain_provider.get_option_contract_list(self._twx, self.time)
|
||||
options = sorted(options, key=lambda x: x.id.symbol)
|
||||
|
||||
option = next((option
|
||||
|
||||
@@ -67,7 +67,7 @@ class AddOptionContractFromUniverseRegressionAlgorithm(QCAlgorithm):
|
||||
return
|
||||
|
||||
for addedSecurity in changes.added_securities:
|
||||
options = self.option_chain(addedSecurity.symbol)
|
||||
options = self.option_chain_provider.get_option_contract_list(addedSecurity.symbol, self.time)
|
||||
options = sorted(options, key=lambda x: x.id.symbol)
|
||||
|
||||
option = next((option
|
||||
|
||||
@@ -1,120 +0,0 @@
|
||||
# QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
|
||||
# Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from AlgorithmImports import *
|
||||
|
||||
### <summary>
|
||||
### This algorithm tests and demonstrates EUREX futures subscription and trading:
|
||||
### - It tests contracts rollover by adding a continuous future and asserting that mapping happens at some point.
|
||||
### - It tests basic trading by buying a contract and holding it until expiration.
|
||||
### - It tests delisting and asserts the holdings are liquidated after that.
|
||||
### </summary>
|
||||
class BasicTemplateEurexFuturesAlgorithm(QCAlgorithm):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self._continuous_contract = None
|
||||
self._mapped_symbol = None
|
||||
self._contract_to_trade = None
|
||||
self._mappings_count = 0
|
||||
self._bought_quantity = 0
|
||||
self._liquidated_quantity = 0
|
||||
self._delisted = False
|
||||
|
||||
def initialize(self):
|
||||
self.set_start_date(2024, 5, 30)
|
||||
self.set_end_date(2024, 6, 23)
|
||||
|
||||
self.set_account_currency(Currencies.EUR);
|
||||
self.set_cash(1000000)
|
||||
|
||||
self._continuous_contract = self.add_future(
|
||||
Futures.Indices.EURO_STOXX_50,
|
||||
Resolution.MINUTE,
|
||||
data_normalization_mode=DataNormalizationMode.BACKWARDS_RATIO,
|
||||
data_mapping_mode=DataMappingMode.FIRST_DAY_MONTH,
|
||||
contract_depth_offset=0,
|
||||
)
|
||||
self._continuous_contract.set_filter(timedelta(days=0), timedelta(days=180))
|
||||
self._mapped_symbol = self._continuous_contract.mapped
|
||||
|
||||
benchmark = self.add_index("SX5E", market=Market.EUREX)
|
||||
self.set_benchmark(benchmark.symbol)
|
||||
|
||||
func_seeder = FuncSecuritySeeder(self.get_last_known_prices)
|
||||
self.set_security_initializer(lambda security: func_seeder.seed_security(security))
|
||||
|
||||
def on_data(self, slice):
|
||||
for changed_event in slice.symbol_changed_events.values():
|
||||
self._mappings_count += 1
|
||||
if self._mappings_count > 1:
|
||||
raise Exception(f"{self.time} - Unexpected number of symbol changed events (mappings): {self._mappings_count}. Expected only 1.")
|
||||
|
||||
self.debug(f"{self.time} - SymbolChanged event: {changed_event}")
|
||||
|
||||
if changed_event.old_symbol != str(self._mapped_symbol.id):
|
||||
raise Exception(f"{self.time} - Unexpected symbol changed event old symbol: {changed_event}")
|
||||
|
||||
if changed_event.new_symbol != str(self._continuous_contract.mapped.id):
|
||||
raise Exception(f"{self.time} - Unexpected symbol changed event new symbol: {changed_event}")
|
||||
|
||||
# Let's trade the previous mapped contract, so we can hold it until expiration for testing
|
||||
# (will be sooner than the new mapped contract)
|
||||
self._contract_to_trade = self._mapped_symbol
|
||||
self._mapped_symbol = self._continuous_contract.mapped
|
||||
|
||||
# Let's trade after the mapping is done
|
||||
if self._contract_to_trade is not None and self._bought_quantity == 0 and self.securities[self._contract_to_trade].exchange.exchange_open:
|
||||
self.buy(self._contract_to_trade, 1)
|
||||
|
||||
if self._contract_to_trade is not None and slice.delistings.contains_key(self._contract_to_trade):
|
||||
delisting = slice.delistings[self._contract_to_trade]
|
||||
if delisting.type == DelistingType.DELISTED:
|
||||
self._delisted = True
|
||||
|
||||
if self.portfolio.invested:
|
||||
raise Exception(f"{self.time} - Portfolio should not be invested after the traded contract is delisted.")
|
||||
|
||||
def on_order_event(self, order_event):
|
||||
if order_event.symbol != self._contract_to_trade:
|
||||
raise Exception(f"{self.time} - Unexpected order event symbol: {order_event.symbol}. Expected {self._contract_to_trade}")
|
||||
|
||||
if order_event.direction == OrderDirection.BUY:
|
||||
if order_event.status == OrderStatus.FILLED:
|
||||
if self._bought_quantity != 0 and self._liquidated_quantity != 0:
|
||||
raise Exception(f"{self.time} - Unexpected buy order event status: {order_event.status}")
|
||||
|
||||
self._bought_quantity = order_event.quantity
|
||||
elif order_event.direction == OrderDirection.SELL:
|
||||
if order_event.status == OrderStatus.FILLED:
|
||||
if self._bought_quantity <= 0 and self._liquidated_quantity != 0:
|
||||
raise Exception(f"{self.time} - Unexpected sell order event status: {order_event.status}")
|
||||
|
||||
self._liquidated_quantity = order_event.quantity
|
||||
if self._liquidated_quantity != -self._bought_quantity:
|
||||
raise Exception(f"{self.time} - Unexpected liquidated quantity: {self._liquidated_quantity}. Expected: {-self._bought_quantity}")
|
||||
|
||||
def on_securities_changed(self, changes):
|
||||
for added_security in changes.added_securities:
|
||||
if added_security.symbol.security_type == SecurityType.FUTURE and added_security.symbol.is_canonical():
|
||||
self._mapped_symbol = self._continuous_contract.mapped
|
||||
|
||||
def on_end_of_algorithm(self):
|
||||
if self._mappings_count == 0:
|
||||
raise Exception(f"Unexpected number of symbol changed events (mappings): {self._mappings_count}. Expected 1.")
|
||||
|
||||
if not self._delisted:
|
||||
raise Exception("Contract was not delisted")
|
||||
|
||||
# Make sure we traded and that the position was liquidated on delisting
|
||||
if self._bought_quantity <= 0 or self._liquidated_quantity >= 0:
|
||||
raise Exception(f"Unexpected sold quantity: {self._bought_quantity} and liquidated quantity: {self._liquidated_quantity}")
|
||||
@@ -25,12 +25,14 @@ class BasicTemplateSPXWeeklyIndexOptionsAlgorithm(QCAlgorithm):
|
||||
self.set_end_date(2021, 1, 10)
|
||||
self.set_cash(1000000)
|
||||
|
||||
self.spx = self.add_index("SPX").symbol
|
||||
|
||||
# regular option SPX contracts
|
||||
self.spx_options = self.add_index_option("SPX")
|
||||
self.spx_options = self.add_index_option(self.spx)
|
||||
self.spx_options.set_filter(lambda u: (u.strikes(0, 1).expiration(0, 30)))
|
||||
|
||||
# weekly option SPX contracts
|
||||
spxw = self.add_index_option("SPX", "SPXW")
|
||||
spxw = self.add_index_option(self.spx, "SPXW")
|
||||
# set our strike/expiry filter for this option chain
|
||||
spxw.set_filter(lambda u: (u.strikes(0, 1)
|
||||
# single week ahead since there are many SPXW contracts and we want to preserve performance
|
||||
|
||||
@@ -28,6 +28,7 @@ class CoarseFineOptionUniverseChainRegressionAlgorithm(QCAlgorithm):
|
||||
# - 6th: AAPL is selected, TWX is removed but subscriptions are not removed because the securities are invested.
|
||||
# - TWX and its options are liquidated.
|
||||
# - 7th: Since options universe selection is daily now, TWX subscriptions are removed the next day (7th)
|
||||
#self.set_end_date(2014,6,6)
|
||||
self.set_end_date(2014,6,7)
|
||||
|
||||
self.universe_settings.resolution = Resolution.MINUTE
|
||||
|
||||
@@ -52,7 +52,8 @@ class FutureOptionBuySellCallIntradayRegressionAlgorithm(QCAlgorithm):
|
||||
# Select a future option expiring ITM, and adds it to the algorithm.
|
||||
self.es_options = [
|
||||
self.add_future_option_contract(i, Resolution.MINUTE).symbol
|
||||
for i in (list(self.option_chain(self.es19m20)) + list(self.option_chain(self.es20h20)))
|
||||
for i in (self.option_chain_provider.get_option_contract_list(self.es19m20, self.time) +
|
||||
self.option_chain_provider.get_option_contract_list(self.es20h20, self.time))
|
||||
if i.id.strike_price == 3200.0 and i.id.option_right == OptionRight.CALL
|
||||
]
|
||||
|
||||
|
||||
@@ -41,8 +41,7 @@ class FutureOptionCallITMExpiryRegressionAlgorithm(QCAlgorithm):
|
||||
# Select a future option expiring ITM, and adds it to the algorithm.
|
||||
self.es_option = self.add_future_option_contract(
|
||||
list(
|
||||
sorted([x for x in self.option_chain(self.es19m20) if x.id.strike_price <= 3200.0 and x.id.option_right == OptionRight.CALL],
|
||||
key=lambda x: x.id.strike_price, reverse=True)
|
||||
sorted([x for x in self.option_chain_provider.get_option_contract_list(self.es19m20, self.time) if x.id.strike_price <= 3200.0 and x.id.option_right == OptionRight.CALL], key=lambda x: x.id.strike_price, reverse=True)
|
||||
)[0], Resolution.MINUTE).symbol
|
||||
|
||||
self.expected_contract = Symbol.create_option(self.es19m20, Market.CME, OptionStyle.AMERICAN, OptionRight.CALL, 3200.0, datetime(2020, 6, 19))
|
||||
|
||||
@@ -45,8 +45,7 @@ class FutureOptionCallOTMExpiryRegressionAlgorithm(QCAlgorithm):
|
||||
self.es_option = self.add_future_option_contract(
|
||||
list(
|
||||
sorted(
|
||||
[x for x in self.option_chain(self.es19m20)
|
||||
if x.id.strike_price >= 3300.0 and x.id.option_right == OptionRight.CALL],
|
||||
[x for x in self.option_chain_provider.get_option_contract_list(self.es19m20, self.time) if x.id.strike_price >= 3300.0 and x.id.option_right == OptionRight.CALL],
|
||||
key=lambda x: x.id.strike_price
|
||||
)
|
||||
)[0], Resolution.MINUTE).symbol
|
||||
|
||||
@@ -34,9 +34,7 @@ class FutureOptionDailyRegressionAlgorithm(QCAlgorithm):
|
||||
|
||||
# Attempt to fetch a specific ITM future option contract
|
||||
dc_options = [
|
||||
self.add_future_option_contract(x, resolution).symbol
|
||||
for x in self.option_chain(self.dc)
|
||||
if x.id.strike_price == 17 and x.id.option_right == OptionRight.CALL
|
||||
self.add_future_option_contract(x, resolution).symbol for x in (self.option_chain_provider.get_option_contract_list(self.dc, self.time)) if x.id.strike_price == 17 and x.id.option_right == OptionRight.CALL
|
||||
]
|
||||
self.dc_option = dc_options[0]
|
||||
|
||||
|
||||
@@ -40,8 +40,7 @@ class FutureOptionPutITMExpiryRegressionAlgorithm(QCAlgorithm):
|
||||
# Select a future option expiring ITM, and adds it to the algorithm.
|
||||
self.es_option = self.add_future_option_contract(
|
||||
list(
|
||||
sorted([x for x in self.option_chain(self.es19m20) if x.id.strike_price >= 3300.0 and x.id.option_right == OptionRight.PUT],
|
||||
key=lambda x: x.id.strike_price)
|
||||
sorted([x for x in self.option_chain_provider.get_option_contract_list(self.es19m20, self.time) if x.id.strike_price >= 3300.0 and x.id.option_right == OptionRight.PUT], key=lambda x: x.id.strike_price)
|
||||
)[0], Resolution.MINUTE).symbol
|
||||
|
||||
self.expected_contract = Symbol.create_option(self.es19m20, Market.CME, OptionStyle.AMERICAN, OptionRight.PUT, 3300.0, datetime(2020, 6, 19))
|
||||
|
||||
@@ -45,7 +45,7 @@ class FutureOptionPutOTMExpiryRegressionAlgorithm(QCAlgorithm):
|
||||
self.es_option = self.add_future_option_contract(
|
||||
list(
|
||||
sorted(
|
||||
[x for x in self.option_chain(self.es19m20) if x.id.strike_price <= 3150.0 and x.id.option_right == OptionRight.PUT],
|
||||
[x for x in self.option_chain_provider.get_option_contract_list(self.es19m20, self.time) if x.id.strike_price <= 3150.0 and x.id.option_right == OptionRight.PUT],
|
||||
key=lambda x: x.id.strike_price,
|
||||
reverse=True
|
||||
)
|
||||
@@ -71,7 +71,7 @@ class FutureOptionPutOTMExpiryRegressionAlgorithm(QCAlgorithm):
|
||||
if delisting.type == DelistingType.DELISTED:
|
||||
if delisting.time != datetime(2020, 6, 20):
|
||||
raise AssertionError(f"Delisting happened at unexpected date: {delisting.time}")
|
||||
|
||||
|
||||
def on_order_event(self, order_event: OrderEvent):
|
||||
if order_event.status != OrderStatus.FILLED:
|
||||
# There's lots of noise with OnOrderEvent, but we're only interested in fills.
|
||||
|
||||
@@ -41,7 +41,7 @@ class FutureOptionShortCallITMExpiryRegressionAlgorithm(QCAlgorithm):
|
||||
self.es_option = self.add_future_option_contract(
|
||||
list(
|
||||
sorted(
|
||||
[x for x in self.option_chain(self.es19m20) if x.id.strike_price <= 3100.0 and x.id.option_right == OptionRight.CALL],
|
||||
[x for x in self.option_chain_provider.get_option_contract_list(self.es19m20, self.time) if x.id.strike_price <= 3100.0 and x.id.option_right == OptionRight.CALL],
|
||||
key=lambda x: x.id.strike_price,
|
||||
reverse=True
|
||||
)
|
||||
|
||||
@@ -42,7 +42,7 @@ class FutureOptionShortCallOTMExpiryRegressionAlgorithm(QCAlgorithm):
|
||||
self.es_option = self.add_future_option_contract(
|
||||
list(
|
||||
sorted(
|
||||
[x for x in self.option_chain(self.es19m20) if x.id.strike_price >= 3400.0 and x.id.option_right == OptionRight.CALL],
|
||||
[x for x in self.option_chain_provider.get_option_contract_list(self.es19m20, self.time) if x.id.strike_price >= 3400.0 and x.id.option_right == OptionRight.CALL],
|
||||
key=lambda x: x.id.strike_price
|
||||
)
|
||||
)[0], Resolution.MINUTE).symbol
|
||||
|
||||
@@ -41,7 +41,7 @@ class FutureOptionShortPutITMExpiryRegressionAlgorithm(QCAlgorithm):
|
||||
self.es_option = self.add_future_option_contract(
|
||||
list(
|
||||
sorted(
|
||||
[x for x in self.option_chain(self.es19m20) if x.id.strike_price <= 3400.0 and x.id.option_right == OptionRight.PUT],
|
||||
[x for x in self.option_chain_provider.get_option_contract_list(self.es19m20, self.time) if x.id.strike_price <= 3400.0 and x.id.option_right == OptionRight.PUT],
|
||||
key=lambda x: x.id.strike_price,
|
||||
reverse=True
|
||||
)
|
||||
|
||||
@@ -42,7 +42,7 @@ class FutureOptionShortPutOTMExpiryRegressionAlgorithm(QCAlgorithm):
|
||||
self.es_option = self.add_future_option_contract(
|
||||
list(
|
||||
sorted(
|
||||
[x for x in self.option_chain(self.es19m20) if x.id.strike_price <= 3000.0 and x.id.option_right == OptionRight.PUT],
|
||||
[x for x in self.option_chain_provider.get_option_contract_list(self.es19m20, self.time) if x.id.strike_price <= 3000.0 and x.id.option_right == OptionRight.PUT],
|
||||
key=lambda x: x.id.strike_price,
|
||||
reverse=True
|
||||
)
|
||||
|
||||
@@ -38,7 +38,7 @@ class IndexOptionBuySellCallIntradayRegressionAlgorithm(QCAlgorithm):
|
||||
# Select a index option expiring ITM, and adds it to the algorithm.
|
||||
spx_options = list(sorted([
|
||||
self.add_index_option_contract(i, Resolution.MINUTE).symbol \
|
||||
for i in self.option_chain(spx)\
|
||||
for i in self.option_chain_provider.get_option_contract_list(spx, self.time)\
|
||||
if (i.id.strike_price == 3700 or i.id.strike_price == 3800) and i.id.option_right == OptionRight.CALL and i.id.date.year == 2021 and i.id.date.month == 1],
|
||||
key=lambda x: x.id.strike_price
|
||||
))
|
||||
@@ -66,7 +66,7 @@ class IndexOptionBuySellCallIntradayRegressionAlgorithm(QCAlgorithm):
|
||||
|
||||
if spx_options[0] != expectedContract3700:
|
||||
raise Exception(f"Contract {expectedContract3700} was not found in the chain, found instead: {spx_options[0]}")
|
||||
|
||||
|
||||
if spx_options[1] != expectedContract3800:
|
||||
raise Exception(f"Contract {expectedContract3800} was not found in the chain, found instead: {spx_options[1]}")
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@ class IndexOptionCallITMExpiryRegressionAlgorithm(QCAlgorithm):
|
||||
self.spx = self.add_index("SPX", Resolution.MINUTE).symbol
|
||||
|
||||
# Select an index option expiring ITM, and adds it to the algorithm.
|
||||
self.spx_option = list(self.option_chain(self.spx))
|
||||
self.spx_option = list(self.option_chain_provider.get_option_contract_list(self.spx, self.time))
|
||||
self.spx_option = [i for i in self.spx_option if i.id.strike_price <= 3200 and i.id.option_right == OptionRight.CALL and i.id.date.year == 2021 and i.id.date.month == 1]
|
||||
self.spx_option = list(sorted(self.spx_option, key=lambda x: x.id.strike_price, reverse=True))[0]
|
||||
self.spx_option = self.add_index_option_contract(self.spx_option, Resolution.MINUTE).symbol
|
||||
@@ -43,8 +43,8 @@ class IndexOptionCallITMExpiryRegressionAlgorithm(QCAlgorithm):
|
||||
raise Exception(f"Contract {self.expected_option_contract} was not found in the chain")
|
||||
|
||||
self.schedule.on(
|
||||
self.date_rules.tomorrow,
|
||||
self.time_rules.after_market_open(self.spx, 1),
|
||||
self.date_rules.tomorrow,
|
||||
self.time_rules.after_market_open(self.spx, 1),
|
||||
lambda: self.market_order(self.spx_option, 1)
|
||||
)
|
||||
|
||||
@@ -55,7 +55,7 @@ class IndexOptionCallITMExpiryRegressionAlgorithm(QCAlgorithm):
|
||||
if delisting.type == DelistingType.WARNING:
|
||||
if delisting.time != datetime(2021, 1, 15):
|
||||
raise Exception(f"Delisting warning issued at unexpected date: {delisting.time}")
|
||||
|
||||
|
||||
if delisting.type == DelistingType.DELISTED:
|
||||
if delisting.time != datetime(2021, 1, 16):
|
||||
raise Exception(f"Delisting happened at unexpected date: {delisting.time}")
|
||||
|
||||
@@ -30,7 +30,7 @@ class IndexOptionCallITMGreeksExpiryRegressionAlgorithm(QCAlgorithm):
|
||||
self.spx = spx.symbol
|
||||
|
||||
# Select a index option call expiring ITM, and adds it to the algorithm.
|
||||
self.spx_option = list(self.option_chain(self.spx))
|
||||
self.spx_option = list(self.option_chain_provider.get_option_contract_list(self.spx, self.time))
|
||||
self.spx_option = [i for i in self.spx_option if i.id.strike_price <= 3200 and i.id.option_right == OptionRight.CALL and i.id.date.year == 2021 and i.id.date.month == 1]
|
||||
self.spx_option = list(sorted(self.spx_option, key=lambda x: x.id.strike_price, reverse=True))[0]
|
||||
self.spx_option = self.add_index_option_contract(self.spx_option, Resolution.MINUTE)
|
||||
@@ -81,7 +81,7 @@ class IndexOptionCallITMGreeksExpiryRegressionAlgorithm(QCAlgorithm):
|
||||
|
||||
if any([i for i in rho if i == 0]):
|
||||
raise Exception("Option contract Rho was equal to zero")
|
||||
|
||||
|
||||
if any([i for i in theta if i == 0]):
|
||||
raise Exception("Option contract Theta was equal to zero")
|
||||
|
||||
|
||||
@@ -38,17 +38,17 @@ class IndexOptionCallOTMExpiryRegressionAlgorithm(QCAlgorithm):
|
||||
self.spx = self.add_index("SPX", Resolution.MINUTE).symbol
|
||||
|
||||
# Select a index option call expiring OTM, and adds it to the algorithm.
|
||||
self.spx_option = list(self.option_chain(self.spx))
|
||||
self.spx_option = list(self.option_chain_provider.get_option_contract_list(self.spx, self.time))
|
||||
self.spx_option = [i for i in self.spx_option if i.id.strike_price >= 4250 and i.id.option_right == OptionRight.CALL and i.id.date.year == 2021 and i.id.date.month == 1]
|
||||
self.spx_option = list(sorted(self.spx_option, key=lambda x: x.id.strike_price))[0]
|
||||
self.spx_option = self.add_index_option_contract(self.spx_option, Resolution.MINUTE).symbol
|
||||
|
||||
self.expected_contract = Symbol.create_option(
|
||||
self.spx,
|
||||
Market.USA,
|
||||
OptionStyle.EUROPEAN,
|
||||
OptionRight.CALL,
|
||||
4250,
|
||||
self.spx,
|
||||
Market.USA,
|
||||
OptionStyle.EUROPEAN,
|
||||
OptionRight.CALL,
|
||||
4250,
|
||||
datetime(2021, 1, 15)
|
||||
)
|
||||
|
||||
@@ -56,8 +56,8 @@ class IndexOptionCallOTMExpiryRegressionAlgorithm(QCAlgorithm):
|
||||
raise Exception(f"Contract {self.expected_contract} was not found in the chain")
|
||||
|
||||
self.schedule.on(
|
||||
self.date_rules.tomorrow,
|
||||
self.time_rules.after_market_open(self.spx, 1),
|
||||
self.date_rules.tomorrow,
|
||||
self.time_rules.after_market_open(self.spx, 1),
|
||||
lambda: self.market_order(self.spx_option, 1)
|
||||
)
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ class IndexOptionPutITMExpiryRegressionAlgorithm(QCAlgorithm):
|
||||
self.spx = self.add_index("SPX", Resolution.MINUTE).symbol
|
||||
|
||||
# Select a index option expiring ITM, and adds it to the algorithm.
|
||||
self.spx_option = list(self.option_chain(self.spx))
|
||||
self.spx_option = list(self.option_chain_provider.get_option_contract_list(self.spx, self.time))
|
||||
self.spx_option = [i for i in self.spx_option if i.id.strike_price >= 4200 and i.id.option_right == OptionRight.PUT and i.id.date.year == 2021 and i.id.date.month == 1]
|
||||
self.spx_option = list(sorted(self.spx_option, key=lambda x: x.id.strike_price))[0]
|
||||
self.spx_option = self.add_index_option_contract(self.spx_option, Resolution.MINUTE).symbol
|
||||
|
||||
@@ -38,17 +38,17 @@ class IndexOptionCallOTMExpiryRegressionAlgorithm(QCAlgorithm):
|
||||
self.spx = self.add_index("SPX", Resolution.MINUTE).symbol
|
||||
|
||||
# Select a index option call expiring OTM, and adds it to the algorithm.
|
||||
self.spx_option = list(self.option_chain(self.spx))
|
||||
self.spx_option = list(self.option_chain_provider.get_option_contract_list(self.spx, self.time))
|
||||
self.spx_option = [i for i in self.spx_option if i.id.strike_price <= 3200 and i.id.option_right == OptionRight.PUT and i.id.date.year == 2021 and i.id.date.month == 1]
|
||||
self.spx_option = list(sorted(self.spx_option, key=lambda x: x.id.strike_price, reverse=True))[0]
|
||||
self.spx_option = self.add_index_option_contract(self.spx_option, Resolution.MINUTE).symbol
|
||||
|
||||
self.expected_contract = Symbol.create_option(
|
||||
self.spx,
|
||||
Market.USA,
|
||||
OptionStyle.EUROPEAN,
|
||||
OptionRight.PUT,
|
||||
3200,
|
||||
self.spx,
|
||||
Market.USA,
|
||||
OptionStyle.EUROPEAN,
|
||||
OptionRight.PUT,
|
||||
3200,
|
||||
datetime(2021, 1, 15)
|
||||
)
|
||||
|
||||
@@ -56,8 +56,8 @@ class IndexOptionCallOTMExpiryRegressionAlgorithm(QCAlgorithm):
|
||||
raise Exception(f"Contract {self.expected_contract} was not found in the chain")
|
||||
|
||||
self.schedule.on(
|
||||
self.date_rules.tomorrow,
|
||||
self.time_rules.after_market_open(self.spx, 1),
|
||||
self.date_rules.tomorrow,
|
||||
self.time_rules.after_market_open(self.spx, 1),
|
||||
lambda: self.market_order(self.spx_option, 1)
|
||||
)
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ class IndexOptionShortCallITMExpiryRegressionAlgorithm(QCAlgorithm):
|
||||
self.spx = self.add_index("SPX", Resolution.MINUTE).symbol
|
||||
|
||||
# Select a index option expiring ITM, and adds it to the algorithm.
|
||||
self.spx_option = list(self.option_chain(self.spx))
|
||||
self.spx_option = list(self.option_chain_provider.get_option_contract_list(self.spx, self.time))
|
||||
self.spx_option = [i for i in self.spx_option if i.id.strike_price <= 3200 and i.id.option_right == OptionRight.CALL and i.id.date.year == 2021 and i.id.date.month == 1]
|
||||
self.spx_option = list(sorted(self.spx_option, key=lambda x: x.id.strike_price, reverse=True))[0]
|
||||
self.spx_option = self.add_index_option_contract(self.spx_option, Resolution.MINUTE).symbol
|
||||
|
||||
@@ -34,7 +34,7 @@ class IndexOptionShortCallOTMExpiryRegressionAlgorithm(QCAlgorithm):
|
||||
self.spx = self.add_index("SPX", Resolution.MINUTE).symbol
|
||||
|
||||
# Select a index option expiring ITM, and adds it to the algorithm.
|
||||
self.spx_option = list(self.option_chain(self.spx))
|
||||
self.spx_option = list(self.option_chain_provider.get_option_contract_list(self.spx, self.time))
|
||||
self.spx_option = [i for i in self.spx_option if i.id.strike_price >= 4250 and i.id.option_right == OptionRight.CALL and i.id.date.year == 2021 and i.id.date.month == 1]
|
||||
self.spx_option = list(sorted(self.spx_option, key=lambda x: x.id.strike_price))[0]
|
||||
self.spx_option = self.add_index_option_contract(self.spx_option, Resolution.MINUTE).symbol
|
||||
|
||||
@@ -38,7 +38,7 @@ class IndexOptionShortCallITMExpiryRegressionAlgorithm(QCAlgorithm):
|
||||
self.spx = self.add_index("SPX", Resolution.MINUTE).symbol
|
||||
|
||||
# Select a index option expiring ITM, and adds it to the algorithm.
|
||||
self.spx_option = list(self.option_chain(self.spx))
|
||||
self.spx_option = list(self.option_chain_provider.get_option_contract_list(self.spx, self.time))
|
||||
self.spx_option = [i for i in self.spx_option if i.id.strike_price <= 4200 and i.id.option_right == OptionRight.PUT and i.id.date.year == 2021 and i.id.date.month == 1]
|
||||
self.spx_option = list(sorted(self.spx_option, key=lambda x: x.id.strike_price, reverse=True))[0]
|
||||
self.spx_option = self.add_index_option_contract(self.spx_option, Resolution.MINUTE).symbol
|
||||
|
||||
@@ -34,7 +34,7 @@ class IndexOptionShortCallOTMExpiryRegressionAlgorithm(QCAlgorithm):
|
||||
self.spx = self.add_index("SPX", Resolution.MINUTE).symbol
|
||||
|
||||
# Select a index option expiring ITM, and adds it to the algorithm.
|
||||
self.spx_option = list(self.option_chain(self.spx))
|
||||
self.spx_option = list(self.option_chain_provider.get_option_contract_list(self.spx, self.time))
|
||||
self.spx_option = [i for i in self.spx_option if i.id.strike_price <= 3200 and i.id.option_right == OptionRight.PUT and i.id.date.year == 2021 and i.id.date.month == 1]
|
||||
self.spx_option = list(sorted(self.spx_option, key=lambda x: x.id.strike_price, reverse=True))[0]
|
||||
self.spx_option = self.add_index_option_contract(self.spx_option, Resolution.MINUTE).symbol
|
||||
|
||||
@@ -1,89 +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.
|
||||
|
||||
from AlgorithmImports import *
|
||||
|
||||
class IndicatorExtensionsSMAWithCustomIndicatorsRegressionAlgorithm(QCAlgorithm):
|
||||
|
||||
def initialize(self):
|
||||
self.set_start_date(2020, 2, 20)
|
||||
self.set_end_date(2020, 4, 20)
|
||||
self.qqq = self.add_equity("QQQ", Resolution.DAILY).symbol
|
||||
self.range_indicator = RangeIndicator("range1")
|
||||
self.range_sma = IndicatorExtensions.sma(self.range_indicator, 5)
|
||||
|
||||
self.range_indicator_2 = RangeIndicator2("range2")
|
||||
self.range_sma_2 = IndicatorExtensions.sma(self.range_indicator_2, 5)
|
||||
|
||||
def on_data(self, data):
|
||||
self.range_indicator.update(data.bars.get(self.qqq))
|
||||
self.range_indicator_2.update(data.bars.get(self.qqq))
|
||||
|
||||
self.debug(f"{self.range_indicator.name} {self.range_indicator.value}")
|
||||
self.debug(f"{self.range_sma.name} {self.range_sma.current.value}")
|
||||
|
||||
self.debug(f"{self.range_indicator_2.name} {self.range_indicator_2.value}")
|
||||
self.debug(f"{self.range_sma_2.name} {self.range_sma_2.current.value}")
|
||||
|
||||
def on_end_of_algorithm(self):
|
||||
if not self.range_sma.is_ready:
|
||||
raise Exception(f"{self.range_sma.name} should have been ready at the end of the algorithm, but it wasn't. The indicator received {self.range_sma.samples} samples.")
|
||||
|
||||
if not self.range_sma_2.is_ready:
|
||||
raise Exception(f"{self.range_sma_2.name} should have been ready at the end of the algorithm, but it wasn't. The indicator received {self.range_sma_2.samples} samples.")
|
||||
|
||||
class RangeIndicator(PythonIndicator):
|
||||
def __init__(self, name):
|
||||
self.name = name
|
||||
self.time = datetime.min
|
||||
self.value = 0
|
||||
self.is_ready = False;
|
||||
|
||||
@property
|
||||
def is_ready(self):
|
||||
return self._is_ready
|
||||
|
||||
@is_ready.setter
|
||||
def is_ready(self, value):
|
||||
self._is_ready = value
|
||||
|
||||
def update(self, bar: TradeBar):
|
||||
if bar is None:
|
||||
return False
|
||||
|
||||
self.value = bar.high - bar.low
|
||||
self.time = bar.time
|
||||
self.is_ready = True
|
||||
self.on_updated(IndicatorDataPoint(bar.end_time, self.value))
|
||||
return True
|
||||
|
||||
class RangeIndicator2(PythonIndicator):
|
||||
def __init__(self, name):
|
||||
self.name = name
|
||||
self.time = datetime.min
|
||||
self.value = 0
|
||||
self._is_ready = False;
|
||||
|
||||
@property
|
||||
def is_ready(self):
|
||||
return self._is_ready
|
||||
|
||||
def update(self, bar: TradeBar):
|
||||
if bar is None:
|
||||
return False
|
||||
|
||||
self.value = bar.high - bar.low
|
||||
self.time = bar.time
|
||||
self._is_ready = True
|
||||
self.on_updated(IndicatorDataPoint(bar.end_time, self.value))
|
||||
return True
|
||||
@@ -112,6 +112,7 @@ class IndicatorSelectorWorksWithDifferentOptions(QCAlgorithm):
|
||||
if (self.future in slice.futures_chains.keys()):
|
||||
if self.future_contract == None:
|
||||
self.future_contract = slice.future_chains[self.future].trade_bars.values()[0].symbol
|
||||
return
|
||||
if self.future_contract in slice.future_chains[self.future].trade_bars:
|
||||
value = slice.future_chains[self.future].trade_bars[self.future_contract]
|
||||
if value.volume != 0:
|
||||
@@ -125,12 +126,11 @@ class IndicatorSelectorWorksWithDifferentOptions(QCAlgorithm):
|
||||
raise Exception("At least one trade bar should have been found, but none was found")
|
||||
|
||||
future_indicator = Identity("")
|
||||
backtest_days = (self.end_date - self.start_date).days
|
||||
future_volume_history = self.indicator_history(future_indicator, self.future_contract, backtest_days, Resolution.DAILY, Field.VOLUME).current
|
||||
future_volume_history = self.indicator_history(future_indicator, self.future_contract, 50, Resolution.DAILY, Field.VOLUME).current
|
||||
future_volume_history_values = list(map(lambda x: x.value, future_volume_history))
|
||||
future_volume_history_values = list(filter(lambda x: x != 0, future_volume_history_values))
|
||||
if abs(sum(future_volume_history_values)/len(future_volume_history_values) - sum(self.future_points)/len(self.future_points)) > 0.001:
|
||||
raise Exception(f"No history indicator future data point was found using Field.Volume selector! {self.future_points}")
|
||||
raise Exception("No history indicator future data point was found using Field.Volume selector!")
|
||||
|
||||
volume_history = self.indicator_history(self.tradebar_history_indicator, self.aapl, 109, Resolution.DAILY, Field.VOLUME).current
|
||||
volume_history_values = list(map(lambda x: x.value, volume_history))
|
||||
|
||||
@@ -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.
|
||||
|
||||
from AlgorithmImports import *
|
||||
|
||||
### <summary>
|
||||
### Regression algorithm illustrating the usage of the <see cref="QCAlgorithm.OptionChain(Symbol)"/> method
|
||||
### to get an option chain, which contains additional data besides the symbols, including prices, implied volatility and greeks.
|
||||
### It also shows how this data can be used to filter the contracts based on certain criteria.
|
||||
### </summary>
|
||||
class OptionChainFullDataRegressionAlgorithm(QCAlgorithm):
|
||||
|
||||
def initialize(self):
|
||||
self.set_start_date(2015, 12, 24)
|
||||
self.set_end_date(2015, 12, 24)
|
||||
self.set_cash(100000)
|
||||
|
||||
goog = self.add_equity("GOOG").symbol
|
||||
|
||||
# Get contracts expiring within 10 days, with an implied volatility greater than 0.5 and a delta less than 0.5
|
||||
contracts = [
|
||||
contract_data
|
||||
for contract_data in self.option_chain(goog)
|
||||
if contract_data.id.date - self.time <= timedelta(days=10) and contract_data.implied_volatility > 0.5 and contract_data.greeks.delta < 0.5
|
||||
]
|
||||
# Get the contract with the latest expiration date
|
||||
self._option_contract = sorted(contracts, key=lambda x: x.id.date, reverse=True)[0]
|
||||
|
||||
self.add_option_contract(self._option_contract)
|
||||
|
||||
def on_data(self, data):
|
||||
# Do some trading with the selected contract for sample purposes
|
||||
if not self.portfolio.invested:
|
||||
self.market_order(self._option_contract, 1)
|
||||
else:
|
||||
self.liquidate()
|
||||
@@ -25,22 +25,22 @@ class OptionUniverseHistoryRegressionAlgorithm(QCAlgorithm):
|
||||
|
||||
option = self.add_option("GOOG").symbol
|
||||
|
||||
historical_options_data_df = self.history(option, 3, Resolution.DAILY)
|
||||
#historical_options_data = self.history(OptionUniverse, option, 3, Resolution.DAILY)
|
||||
historical_options_data = list(self.history[OptionUniverse](option, 3, Resolution.DAILY))
|
||||
|
||||
if historical_options_data_df.shape[0] != 3:
|
||||
raise RegressionTestException(f"Expected 3 option chains from history request, but got {historical_options_data_df.shape[0]}")
|
||||
if len(historical_options_data) != 3:
|
||||
raise RegressionTestException(f"Expected 3 option chains from history request, but got {historical_options_data.Count}")
|
||||
|
||||
for index, row in historical_options_data_df.iterrows():
|
||||
data = row.data
|
||||
date = index[4]
|
||||
for history_option_universe in historical_options_data:
|
||||
date = history_option_universe.end_time
|
||||
chain = list(self.option_chain_provider.get_option_contract_list(option, date))
|
||||
|
||||
if len(chain) == 0:
|
||||
raise RegressionTestException(f"No options in chain on {date}")
|
||||
|
||||
if len(chain) != len(data):
|
||||
raise RegressionTestException(f"Expected {len(chain)} options in chain on {date}, but got {len(data)}")
|
||||
if len(chain) != len(history_option_universe.data):
|
||||
raise RegressionTestException(f"Expected {len(chain)} options in chain on {date}, but got {len(history_option_universe.data.data)}")
|
||||
|
||||
for i in range(len(chain)):
|
||||
if data[i].symbol != chain[i]:
|
||||
if history_option_universe.data[i].symbol != chain[i]:
|
||||
raise RegressionTestException(f"Missing option contract {chain[i]} on {date}")
|
||||
|
||||
@@ -75,7 +75,17 @@ namespace QuantConnect.Algorithm.Framework.Alphas
|
||||
/// <returns>The new insights generated</returns>
|
||||
public override IEnumerable<Insight> Update(QCAlgorithm algorithm, Slice data)
|
||||
{
|
||||
return _model.InvokeMethodAndEnumerate<Insight>(nameof(Update), algorithm, data);
|
||||
using (Py.GIL())
|
||||
{
|
||||
var insights = _model.InvokeMethod(nameof(Update), algorithm, new PythonSlice(data));
|
||||
var iterator = insights.GetIterator();
|
||||
foreach (PyObject insight in iterator)
|
||||
{
|
||||
yield return insight.GetAndDispose<Insight>();
|
||||
}
|
||||
iterator.Dispose();
|
||||
insights.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -85,7 +95,7 @@ namespace QuantConnect.Algorithm.Framework.Alphas
|
||||
/// <param name="changes">The security additions and removals from the algorithm</param>
|
||||
public override void OnSecuritiesChanged(QCAlgorithm algorithm, SecurityChanges changes)
|
||||
{
|
||||
_model.InvokeVoidMethod(nameof(OnSecuritiesChanged), algorithm, changes);
|
||||
_model.InvokeMethod(nameof(OnSecuritiesChanged), algorithm, changes).Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,7 +77,7 @@ namespace QuantConnect.Algorithm.Framework.Portfolio
|
||||
}
|
||||
}
|
||||
|
||||
_model.InvokeVoidMethod(nameof(SetPythonWrapper), this);
|
||||
_model.InvokeMethod(nameof(SetPythonWrapper), this).Dispose();
|
||||
|
||||
_implementsDetermineTargetPercent = model.GetPythonMethod("DetermineTargetPercent") != null;
|
||||
}
|
||||
@@ -91,7 +91,7 @@ namespace QuantConnect.Algorithm.Framework.Portfolio
|
||||
/// <returns>An enumerable of portfolio targets to be sent to the execution model</returns>
|
||||
public override IEnumerable<IPortfolioTarget> CreateTargets(QCAlgorithm algorithm, Insight[] insights)
|
||||
{
|
||||
return _model.InvokeMethodAndEnumerate<IPortfolioTarget>(nameof(CreateTargets), algorithm, insights);
|
||||
return _model.InvokeMethod<IEnumerable<IPortfolioTarget>>(nameof(CreateTargets), algorithm, insights);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -101,7 +101,7 @@ namespace QuantConnect.Algorithm.Framework.Portfolio
|
||||
/// <param name="changes">The security additions and removals from the algorithm</param>
|
||||
public override void OnSecuritiesChanged(QCAlgorithm algorithm, SecurityChanges changes)
|
||||
{
|
||||
_model.InvokeVoidMethod(nameof(OnSecuritiesChanged), algorithm, changes);
|
||||
_model.InvokeMethod(nameof(OnSecuritiesChanged), algorithm, changes).Dispose();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -144,13 +144,32 @@ namespace QuantConnect.Algorithm.Framework.Portfolio
|
||||
/// <returns>A target percent for each insight</returns>
|
||||
protected override Dictionary<Insight, double> DetermineTargetPercent(List<Insight> activeInsights)
|
||||
{
|
||||
if (!_implementsDetermineTargetPercent)
|
||||
using (Py.GIL())
|
||||
{
|
||||
// the implementation is in C#
|
||||
return _model.InvokeMethod<Dictionary<Insight, double>>(nameof(DetermineTargetPercent), activeInsights);
|
||||
}
|
||||
if (!_implementsDetermineTargetPercent)
|
||||
{
|
||||
// the implementation is in C#
|
||||
return _model.InvokeMethod<Dictionary<Insight, double>>(nameof(DetermineTargetPercent), activeInsights);
|
||||
}
|
||||
|
||||
return _model.InvokeMethodAndGetDictionary<Insight, double>(nameof(DetermineTargetPercent), activeInsights);
|
||||
Dictionary<Insight, double> dic;
|
||||
var result = _model.InvokeMethod(nameof(DetermineTargetPercent), activeInsights) as dynamic;
|
||||
if ((result as PyObject).TryConvert(out dic))
|
||||
{
|
||||
// this is required if the python implementation is actually returning a C# dic, not common,
|
||||
// but could happen if its actually calling a base C# implementation
|
||||
return dic;
|
||||
}
|
||||
|
||||
dic = new Dictionary<Insight, double>();
|
||||
foreach (var pyInsight in result)
|
||||
{
|
||||
var insight = (pyInsight as PyObject).As<Insight>();
|
||||
dic[insight] = result[pyInsight];
|
||||
}
|
||||
|
||||
return dic;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -948,8 +948,8 @@ namespace QuantConnect.Algorithm
|
||||
Resolution? resolution = null, bool? fillForward = null, bool? extendedMarketHours = null, DataMappingMode? dataMappingMode = null,
|
||||
DataNormalizationMode? dataNormalizationMode = null, int? contractDepthOffset = null)
|
||||
{
|
||||
var arrayOfSymbols = symbols.ToArray();
|
||||
return CreateDateRangeHistoryRequests(symbols, Extensions.GetCustomDataTypeFromSymbols(arrayOfSymbols) ?? typeof(BaseData), startAlgoTz, endAlgoTz, resolution, fillForward, extendedMarketHours,
|
||||
symbols = symbols.ToArray();
|
||||
return CreateDateRangeHistoryRequests(symbols, GetCustomDataTypeFromSymbols((Symbol[])symbols) ?? typeof(BaseData), startAlgoTz, endAlgoTz, resolution, fillForward, extendedMarketHours,
|
||||
dataMappingMode, dataNormalizationMode, contractDepthOffset);
|
||||
}
|
||||
|
||||
@@ -1084,7 +1084,7 @@ namespace QuantConnect.Algorithm
|
||||
if (!LeanData.IsCommonLeanDataType(type) && !type.IsAbstract)
|
||||
{
|
||||
// we already know it's not a common lean data type
|
||||
var isCustom = Extensions.IsCustomDataType(symbol, type);
|
||||
var isCustom = !type.Namespace.StartsWith("QuantConnect.Data", StringComparison.InvariantCultureIgnoreCase);
|
||||
|
||||
// we were giving a specific type let's fetch it
|
||||
return new[] { new SubscriptionDataConfig(
|
||||
|
||||
@@ -3094,7 +3094,7 @@ namespace QuantConnect.Algorithm
|
||||
private IEnumerable<Slice> GetIndicatorWarmUpHistory(IEnumerable<Symbol> symbols, IIndicator indicator, TimeSpan timeSpan, out bool identityConsolidator)
|
||||
{
|
||||
identityConsolidator = false;
|
||||
if (!AssertIndicatorHasWarmupPeriod(indicator))
|
||||
if (AssertIndicatorHasWarmupPeriod(indicator))
|
||||
{
|
||||
return Enumerable.Empty<Slice>();
|
||||
}
|
||||
@@ -3143,17 +3143,16 @@ namespace QuantConnect.Algorithm
|
||||
where T : class, IBaseData
|
||||
{
|
||||
IDataConsolidator consolidator;
|
||||
if (identityConsolidator)
|
||||
{
|
||||
period = TimeSpan.Zero;
|
||||
}
|
||||
if (SubscriptionManager.SubscriptionDataConfigService.GetSubscriptionDataConfigs(symbol).Count > 0)
|
||||
{
|
||||
consolidator = Consolidate(symbol, period, handler);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (identityConsolidator)
|
||||
{
|
||||
period = TimeSpan.Zero;
|
||||
}
|
||||
|
||||
var providedType = typeof(T);
|
||||
if (providedType.IsAbstract)
|
||||
{
|
||||
@@ -3475,10 +3474,6 @@ namespace QuantConnect.Algorithm
|
||||
public IndicatorHistory IndicatorHistory(IndicatorBase<IndicatorDataPoint> indicator, IEnumerable<Symbol> symbols, int period, Resolution? resolution = null, Func<IBaseData, decimal> selector = null)
|
||||
{
|
||||
var warmupPeriod = (indicator as IIndicatorWarmUpPeriodProvider)?.WarmUpPeriod ?? 0;
|
||||
if (warmupPeriod > 0 && period > 0)
|
||||
{
|
||||
warmupPeriod -= 1;
|
||||
}
|
||||
var history = History(symbols, period + warmupPeriod, resolution, dataNormalizationMode: GetIndicatorHistoryDataNormalizationMode(indicator));
|
||||
return IndicatorHistory(indicator, history, selector);
|
||||
}
|
||||
@@ -3513,10 +3508,6 @@ namespace QuantConnect.Algorithm
|
||||
where T : IBaseData
|
||||
{
|
||||
var warmupPeriod = (indicator as IIndicatorWarmUpPeriodProvider)?.WarmUpPeriod ?? 0;
|
||||
if (warmupPeriod > 0 && period > 0)
|
||||
{
|
||||
warmupPeriod -= 1;
|
||||
}
|
||||
var history = History(symbols, period + warmupPeriod, resolution, dataNormalizationMode: GetIndicatorHistoryDataNormalizationMode(indicator));
|
||||
return IndicatorHistory(indicator, history, selector);
|
||||
}
|
||||
@@ -3902,17 +3893,13 @@ namespace QuantConnect.Algorithm
|
||||
var warmupPeriod = (indicator as IIndicatorWarmUpPeriodProvider)?.WarmUpPeriod ?? 0;
|
||||
if (warmupPeriod != 0)
|
||||
{
|
||||
warmupPeriod -= 1;
|
||||
if (warmupPeriod > 0)
|
||||
foreach (var request in CreateDateRangeHistoryRequests(symbols, start, end, resolution))
|
||||
{
|
||||
foreach (var request in CreateDateRangeHistoryRequests(symbols, start, end, resolution))
|
||||
var adjustedStart = _historyRequestFactory.GetStartTimeAlgoTz(request.StartTimeUtc, request.Symbol, warmupPeriod, request.Resolution,
|
||||
request.ExchangeHours, request.DataTimeZone, request.DataType, request.IncludeExtendedMarketHours);
|
||||
if (adjustedStart < start)
|
||||
{
|
||||
var adjustedStart = _historyRequestFactory.GetStartTimeAlgoTz(request.StartTimeUtc, request.Symbol, warmupPeriod, request.Resolution,
|
||||
request.ExchangeHours, request.DataTimeZone, request.DataType, request.IncludeExtendedMarketHours);
|
||||
if (adjustedStart < start)
|
||||
{
|
||||
start = adjustedStart;
|
||||
}
|
||||
start = adjustedStart;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3945,15 +3932,13 @@ namespace QuantConnect.Algorithm
|
||||
.ToList();
|
||||
|
||||
var indicatorsDataPointsByTime = new List<IndicatorDataPoints>();
|
||||
var lastConsumedTime = DateTime.MinValue;
|
||||
IndicatorDataPoint lastPoint = null;
|
||||
void consumeLastPoint(IndicatorDataPoint newInputPoint)
|
||||
{
|
||||
if (newInputPoint == null || lastConsumedTime == newInputPoint.EndTime)
|
||||
if (lastPoint == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
lastConsumedTime = newInputPoint.EndTime;
|
||||
|
||||
var IndicatorDataPoints = new IndicatorDataPoints { Time = newInputPoint.Time, EndTime = newInputPoint.EndTime };
|
||||
indicatorsDataPointsByTime.Add(IndicatorDataPoints);
|
||||
@@ -3962,6 +3947,7 @@ namespace QuantConnect.Algorithm
|
||||
var newPoint = indicatorsDataPointPerProperty[i].UpdateValue();
|
||||
IndicatorDataPoints.SetProperty(indicatorsDataPointPerProperty[i].Name, newPoint);
|
||||
}
|
||||
lastPoint = null;
|
||||
}
|
||||
|
||||
IndicatorUpdatedHandler callback = (object _, IndicatorDataPoint newInputPoint) =>
|
||||
@@ -3971,15 +3957,16 @@ namespace QuantConnect.Algorithm
|
||||
return;
|
||||
}
|
||||
|
||||
if (lastPoint == null || lastPoint.Time != newInputPoint.Time)
|
||||
if (lastPoint != null && lastPoint.Time != newInputPoint.Time)
|
||||
{
|
||||
// if null, it's the first point, we transitions from not ready to ready
|
||||
// else when the time changes we fetch the indicators values, some indicators which consume data from multiple symbols might trigger the Updated event
|
||||
// when the time changes we let through the previous point, some indicators which consume data from multiple symbols might trigger the Updated event
|
||||
// even if their value has not changed yet
|
||||
consumeLastPoint(newInputPoint);
|
||||
}
|
||||
lastPoint = newInputPoint;
|
||||
};
|
||||
// flush the last point
|
||||
consumeLastPoint(lastPoint);
|
||||
|
||||
// register the callback, update the indicator and unregister finally
|
||||
indicator.Updated += callback;
|
||||
@@ -3999,8 +3986,6 @@ namespace QuantConnect.Algorithm
|
||||
}
|
||||
}
|
||||
}
|
||||
// flush the last point, this will be useful for indicator consuming time from multiple symbols
|
||||
consumeLastPoint(lastPoint);
|
||||
indicator.Updated -= callback;
|
||||
|
||||
return new IndicatorHistory(indicatorsDataPointsByTime, indicatorsDataPointPerProperty,
|
||||
|
||||
@@ -715,36 +715,6 @@ namespace QuantConnect.Algorithm
|
||||
WarmUpIndicator(symbol, WrapPythonIndicator(indicator), resolution, selector?.ConvertToDelegate<Func<IBaseData, IBaseData>>());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Warms up a given indicator with historical data
|
||||
/// </summary>
|
||||
/// <param name="symbol">The symbol whose indicator we want</param>
|
||||
/// <param name="indicator">The indicator we want to warm up</param>
|
||||
/// <param name="period">The necessary period to warm up the indicator</param>
|
||||
/// <param name="selector">Selects a value from the BaseData send into the indicator, if null defaults to a cast (x => (T)x)</param>
|
||||
[DocumentationAttribute(Indicators)]
|
||||
[DocumentationAttribute(HistoricalData)]
|
||||
public void WarmUpIndicator(Symbol symbol, PyObject indicator, TimeSpan period, PyObject selector = null)
|
||||
{
|
||||
if (indicator.TryConvert(out IndicatorBase<IndicatorDataPoint> indicatorDataPoint))
|
||||
{
|
||||
WarmUpIndicator(symbol, indicatorDataPoint, period, selector?.ConvertToDelegate<Func<IBaseData, decimal>>());
|
||||
return;
|
||||
}
|
||||
if (indicator.TryConvert(out IndicatorBase<IBaseDataBar> indicatorDataBar))
|
||||
{
|
||||
WarmUpIndicator(symbol, indicatorDataBar, period, selector?.ConvertToDelegate<Func<IBaseData, IBaseDataBar>>());
|
||||
return;
|
||||
}
|
||||
if (indicator.TryConvert(out IndicatorBase<TradeBar> indicatorTradeBar))
|
||||
{
|
||||
WarmUpIndicator(symbol, indicatorTradeBar, period, selector?.ConvertToDelegate<Func<IBaseData, TradeBar>>());
|
||||
return;
|
||||
}
|
||||
|
||||
WarmUpIndicator(symbol, WrapPythonIndicator(indicator), period, selector?.ConvertToDelegate<Func<IBaseData, IBaseData>>());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Plot a chart using string series name, with value.
|
||||
/// </summary>
|
||||
@@ -936,7 +906,7 @@ namespace QuantConnect.Algorithm
|
||||
}
|
||||
|
||||
var symbols = tickers.ConvertToSymbolEnumerable().ToArray();
|
||||
var dataType = Extensions.GetCustomDataTypeFromSymbols(symbols);
|
||||
var dataType = GetCustomDataTypeFromSymbols(symbols);
|
||||
|
||||
return GetDataFrame(History(symbols, periods, resolution, fillForward, extendedMarketHours, dataMappingMode, dataNormalizationMode,
|
||||
contractDepthOffset), dataType);
|
||||
@@ -999,7 +969,7 @@ namespace QuantConnect.Algorithm
|
||||
}
|
||||
|
||||
var symbols = tickers.ConvertToSymbolEnumerable().ToArray();
|
||||
var dataType = Extensions.GetCustomDataTypeFromSymbols(symbols);
|
||||
var dataType = GetCustomDataTypeFromSymbols(symbols);
|
||||
|
||||
return GetDataFrame(History(symbols, start, end, resolution, fillForward, extendedMarketHours, dataMappingMode,
|
||||
dataNormalizationMode, contractDepthOffset), dataType);
|
||||
@@ -1749,5 +1719,20 @@ namespace QuantConnect.Algorithm
|
||||
}
|
||||
return history;
|
||||
}
|
||||
|
||||
private Type GetCustomDataTypeFromSymbols(Symbol[] symbols)
|
||||
{
|
||||
if (symbols.Any())
|
||||
{
|
||||
if (!SecurityIdentifier.TryGetCustomDataTypeInstance(symbols[0].ID.Symbol, out var dataType)
|
||||
|| symbols.Any(x => !SecurityIdentifier.TryGetCustomDataTypeInstance(x.ID.Symbol, out var customDataType) || customDataType != dataType))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return dataType;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,15 +92,7 @@ namespace QuantConnect.Algorithm
|
||||
{
|
||||
Security underlyingSecurity;
|
||||
var underlyingSymbol = security.Symbol.Underlying;
|
||||
|
||||
var resolution = configs.GetHighestResolution();
|
||||
var isFillForward = configs.IsFillForward();
|
||||
if (UniverseManager.TryGetValue(security.Symbol, out var universe))
|
||||
{
|
||||
// as if the universe had selected this asset, the configuration of the canonical can be different
|
||||
resolution = universe.UniverseSettings.Resolution;
|
||||
isFillForward = universe.UniverseSettings.FillForward;
|
||||
}
|
||||
|
||||
// create the underlying security object if it doesn't already exist
|
||||
if (!Securities.TryGetValue(underlyingSymbol, out underlyingSecurity))
|
||||
@@ -109,7 +101,7 @@ namespace QuantConnect.Algorithm
|
||||
underlyingSymbol.Value,
|
||||
resolution,
|
||||
underlyingSymbol.ID.Market,
|
||||
isFillForward,
|
||||
configs.IsFillForward(),
|
||||
Security.NullLeverage,
|
||||
configs.IsExtendedMarketHours(),
|
||||
dataNormalizationMode: DataNormalizationMode.Raw);
|
||||
|
||||
@@ -33,7 +33,6 @@ using QuantConnect.Securities;
|
||||
using QuantConnect.Securities.Cfd;
|
||||
using QuantConnect.Securities.Equity;
|
||||
using QuantConnect.Securities.Forex;
|
||||
using QuantConnect.Securities.IndexOption;
|
||||
using QuantConnect.Securities.Option;
|
||||
using QuantConnect.Statistics;
|
||||
using QuantConnect.Util;
|
||||
@@ -53,7 +52,6 @@ using Index = QuantConnect.Securities.Index.Index;
|
||||
using QuantConnect.Securities.CryptoFuture;
|
||||
using QuantConnect.Algorithm.Framework.Alphas.Analysis;
|
||||
using QuantConnect.Algorithm.Framework.Portfolio.SignalExports;
|
||||
using Python.Runtime;
|
||||
|
||||
namespace QuantConnect.Algorithm
|
||||
{
|
||||
@@ -468,9 +466,6 @@ namespace QuantConnect.Algorithm
|
||||
/// Gets the option chain provider, used to get the list of option contracts for an underlying symbol
|
||||
/// </summary>
|
||||
[DocumentationAttribute(AddingData)]
|
||||
[Obsolete("OptionChainProvider property is will soon be deprecated. " +
|
||||
"The new OptionChain() method should be used to fetch equity and index option chains, " +
|
||||
"which will contain additional data per contract, like daily price data, implied volatility and greeks.")]
|
||||
public IOptionChainProvider OptionChainProvider { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
@@ -1939,15 +1934,6 @@ namespace QuantConnect.Algorithm
|
||||
return AddOptionContract(symbol, resolution, fillForward, leverage, extendedMarketHours);
|
||||
}
|
||||
|
||||
var securityResolution = resolution;
|
||||
var securityFillForward = fillForward;
|
||||
if (isCanonical && symbol.SecurityType.IsOption() && symbol.SecurityType != SecurityType.FutureOption)
|
||||
{
|
||||
// option is daily only, for now exclude FOPs
|
||||
securityResolution = Resolution.Daily;
|
||||
securityFillForward = false;
|
||||
}
|
||||
|
||||
var isFilteredSubscription = !isCanonical;
|
||||
List<SubscriptionDataConfig> configs;
|
||||
// we pass dataNormalizationMode to SubscriptionManager.SubscriptionDataConfigService.Add conditionally,
|
||||
@@ -1955,8 +1941,8 @@ namespace QuantConnect.Algorithm
|
||||
if (dataNormalizationMode.HasValue)
|
||||
{
|
||||
configs = SubscriptionManager.SubscriptionDataConfigService.Add(symbol,
|
||||
securityResolution,
|
||||
securityFillForward,
|
||||
resolution,
|
||||
fillForward,
|
||||
extendedMarketHours,
|
||||
isFilteredSubscription,
|
||||
dataNormalizationMode: dataNormalizationMode.Value,
|
||||
@@ -1965,8 +1951,8 @@ namespace QuantConnect.Algorithm
|
||||
else
|
||||
{
|
||||
configs = SubscriptionManager.SubscriptionDataConfigService.Add(symbol,
|
||||
securityResolution,
|
||||
securityFillForward,
|
||||
resolution,
|
||||
fillForward,
|
||||
extendedMarketHours,
|
||||
isFilteredSubscription,
|
||||
contractDepthOffset: (uint)contractDepthOffset);
|
||||
@@ -1984,16 +1970,10 @@ namespace QuantConnect.Algorithm
|
||||
if (!UniverseManager.ContainsKey(symbol))
|
||||
{
|
||||
var canonicalConfig = configs.First();
|
||||
var universeSettingsResolution = canonicalConfig.Resolution;
|
||||
if (symbol.SecurityType.IsOption())
|
||||
{
|
||||
universeSettingsResolution = resolution ?? UniverseSettings.Resolution;
|
||||
}
|
||||
var settings = new UniverseSettings(universeSettingsResolution, leverage, fillForward, extendedMarketHours, UniverseSettings.MinimumTimeInUniverse)
|
||||
var settings = new UniverseSettings(canonicalConfig.Resolution, leverage, fillForward, extendedMarketHours, UniverseSettings.MinimumTimeInUniverse)
|
||||
{
|
||||
Asynchronous = UniverseSettings.Asynchronous
|
||||
};
|
||||
|
||||
if (symbol.SecurityType.IsOption())
|
||||
{
|
||||
universe = new OptionChainUniverse((Option)security, settings);
|
||||
@@ -2241,15 +2221,18 @@ namespace QuantConnect.Algorithm
|
||||
/// <summary>
|
||||
/// Creates and adds index options to the algorithm.
|
||||
/// </summary>
|
||||
/// <param name="underlying">The underlying ticker of the Index Option</param>
|
||||
/// <param name="ticker">The ticker of the Index Option</param>
|
||||
/// <param name="resolution">Resolution of the index option contracts, i.e. the granularity of the data</param>
|
||||
/// <param name="market">The foreign exchange trading market, <seealso cref="Market"/>. Default value is null and looked up using BrokerageModel.DefaultMarkets in <see cref="AddSecurity{T}"/></param>
|
||||
/// <param name="market">Market of the index option. If no market is provided, we default to <see cref="Market.USA"/> </param>
|
||||
/// <param name="fillForward">If true, this will fill in missing data points with the previous data point</param>
|
||||
/// <returns>Canonical Option security</returns>
|
||||
[DocumentationAttribute(AddingData)]
|
||||
public IndexOption AddIndexOption(string underlying, Resolution? resolution = null, string market = null, bool fillForward = true)
|
||||
public Option AddIndexOption(string ticker, Resolution? resolution = null, string market = Market.USA, bool fillForward = true)
|
||||
{
|
||||
return AddIndexOption(underlying, null, resolution, market, fillForward);
|
||||
return AddIndexOption(
|
||||
QuantConnect.Symbol.Create(ticker, SecurityType.Index, market),
|
||||
resolution,
|
||||
fillForward);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -2260,7 +2243,7 @@ namespace QuantConnect.Algorithm
|
||||
/// <param name="fillForward">If true, this will fill in missing data points with the previous data point</param>
|
||||
/// <returns>Canonical Option security</returns>
|
||||
[DocumentationAttribute(AddingData)]
|
||||
public IndexOption AddIndexOption(Symbol symbol, Resolution? resolution = null, bool fillForward = true)
|
||||
public Option AddIndexOption(Symbol symbol, Resolution? resolution = null, bool fillForward = true)
|
||||
{
|
||||
return AddIndexOption(symbol, null, resolution, fillForward);
|
||||
}
|
||||
@@ -2274,36 +2257,14 @@ namespace QuantConnect.Algorithm
|
||||
/// <param name="fillForward">If true, this will fill in missing data points with the previous data point</param>
|
||||
/// <returns>Canonical Option security</returns>
|
||||
[DocumentationAttribute(AddingData)]
|
||||
public IndexOption AddIndexOption(Symbol symbol, string targetOption, Resolution? resolution = null, bool fillForward = true)
|
||||
public Option AddIndexOption(Symbol symbol, string targetOption, Resolution? resolution = null, bool fillForward = true)
|
||||
{
|
||||
if (symbol.SecurityType != SecurityType.Index)
|
||||
{
|
||||
throw new ArgumentException("Symbol provided must be of type SecurityType.Index");
|
||||
}
|
||||
|
||||
return (IndexOption)AddOption(symbol, targetOption, resolution, symbol.ID.Market, fillForward);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates and adds index options to the algorithm.
|
||||
/// </summary>
|
||||
/// <param name="underlying">The underlying ticker of the Index Option</param>
|
||||
/// <param name="targetOption">The target option ticker. This is useful when the option ticker does not match the underlying, e.g. SPX index and the SPXW weekly option. If null is provided will use underlying</param>
|
||||
/// <param name="resolution">Resolution of the index option contracts, i.e. the granularity of the data</param>
|
||||
/// <param name="market">The foreign exchange trading market, <seealso cref="Market"/>. Default value is null and looked up using BrokerageModel.DefaultMarkets in <see cref="AddSecurity{T}"/></param>
|
||||
/// <param name="fillForward">If true, this will fill in missing data points with the previous data point</param>
|
||||
/// <returns>Canonical Option security</returns>
|
||||
[DocumentationAttribute(AddingData)]
|
||||
public IndexOption AddIndexOption(string underlying, string targetOption, Resolution? resolution = null, string market = null, bool fillForward = true)
|
||||
{
|
||||
if (market == null && !BrokerageModel.DefaultMarkets.TryGetValue(SecurityType.Index, out market))
|
||||
{
|
||||
throw new KeyNotFoundException($"No default market set for underlying security type: {SecurityType.Index}");
|
||||
}
|
||||
|
||||
return AddIndexOption(
|
||||
QuantConnect.Symbol.Create(underlying, SecurityType.Index, market),
|
||||
targetOption, resolution, fillForward);
|
||||
return AddOption(symbol, targetOption, resolution, symbol.ID.Market, fillForward);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -2315,14 +2276,14 @@ namespace QuantConnect.Algorithm
|
||||
/// <returns>Index Option Contract</returns>
|
||||
/// <exception cref="ArgumentException">The provided Symbol is not an Index Option</exception>
|
||||
[DocumentationAttribute(AddingData)]
|
||||
public IndexOption AddIndexOptionContract(Symbol symbol, Resolution? resolution = null, bool fillForward = true)
|
||||
public Option AddIndexOptionContract(Symbol symbol, Resolution? resolution = null, bool fillForward = true)
|
||||
{
|
||||
if (symbol.SecurityType != SecurityType.IndexOption || symbol.IsCanonical())
|
||||
if (symbol.SecurityType != SecurityType.IndexOption)
|
||||
{
|
||||
throw new ArgumentException("Symbol provided must be non-canonical and of type SecurityType.IndexOption");
|
||||
throw new ArgumentException("Symbol provided must be of type SecurityType.IndexOption");
|
||||
}
|
||||
|
||||
return (IndexOption)AddOptionContract(symbol, resolution, fillForward);
|
||||
return AddOptionContract(symbol, resolution, fillForward);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -3344,63 +3305,6 @@ namespace QuantConnect.Algorithm
|
||||
return symbols.Select(symbol => Fundamentals(symbol)).ToList();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the option chain for the specified symbol at the current time (<see cref="Time"/>)
|
||||
/// </summary>
|
||||
/// <param name="symbol">
|
||||
/// The symbol for which the option chain is asked for.
|
||||
/// It can be either the canonical option or the underlying symbol.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// The option chain as an enumerable of <see cref="OptionUniverse"/>,
|
||||
/// each containing the contract symbol along with additional data, including daily price data,
|
||||
/// implied volatility and greeks.
|
||||
/// </returns>
|
||||
/// <remarks>
|
||||
/// As of 2024/09/11, future options chain will not contain any additional data (e.g. daily price data, implied volatility and greeks),
|
||||
/// it will be populated with the contract symbol only. This is expected to change in the future.
|
||||
/// </remarks>
|
||||
[DocumentationAttribute(AddingData)]
|
||||
public DataHistory<OptionUniverse> OptionChain(Symbol symbol)
|
||||
{
|
||||
var canonicalSymbol = GetCanonicalOptionSymbol(symbol);
|
||||
IEnumerable<OptionUniverse> optionChain;
|
||||
|
||||
// TODO: Until future options are supported by OptionUniverse, we need to fall back to the OptionChainProvider for them
|
||||
if (canonicalSymbol.SecurityType != SecurityType.FutureOption)
|
||||
{
|
||||
var history = History<OptionUniverse>(canonicalSymbol, 1);
|
||||
optionChain = history?.SingleOrDefault()?.Data?.Cast<OptionUniverse>() ?? Enumerable.Empty<OptionUniverse>();
|
||||
}
|
||||
else
|
||||
{
|
||||
optionChain = OptionChainProvider.GetOptionContractList(canonicalSymbol, Time)
|
||||
.Select(contractSymbol => new OptionUniverse()
|
||||
{
|
||||
Symbol = contractSymbol,
|
||||
EndTime = Time.Date
|
||||
});
|
||||
}
|
||||
|
||||
return new DataHistory<OptionUniverse>(optionChain, new Lazy<PyObject>(() => PandasConverter.GetDataFrame(optionChain)));
|
||||
}
|
||||
|
||||
private static Symbol GetCanonicalOptionSymbol(Symbol symbol)
|
||||
{
|
||||
// We got the underlying
|
||||
if (symbol.SecurityType.HasOptions())
|
||||
{
|
||||
return QuantConnect.Symbol.CreateCanonicalOption(symbol);
|
||||
}
|
||||
|
||||
if (symbol.SecurityType.IsOption())
|
||||
{
|
||||
return symbol.Canonical;
|
||||
}
|
||||
|
||||
throw new ArgumentException($"The symbol {symbol} is not an option or an underlying symbol.");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set the properties and exchange hours for a given key into our databases
|
||||
/// </summary>
|
||||
|
||||
@@ -44,7 +44,17 @@ namespace QuantConnect.Algorithm.Framework.Risk
|
||||
/// <param name="targets">The current portfolio targets to be assessed for risk</param>
|
||||
public override IEnumerable<IPortfolioTarget> ManageRisk(QCAlgorithm algorithm, IPortfolioTarget[] targets)
|
||||
{
|
||||
return _model.InvokeMethodAndEnumerate<IPortfolioTarget>(nameof(ManageRisk), algorithm, targets);
|
||||
using (Py.GIL())
|
||||
{
|
||||
var riskTargetOverrides = _model.InvokeMethod("ManageRisk", algorithm, targets);
|
||||
var iterator = riskTargetOverrides.GetIterator();
|
||||
foreach (PyObject target in iterator)
|
||||
{
|
||||
yield return target.GetAndDispose<IPortfolioTarget>();
|
||||
}
|
||||
iterator.Dispose();
|
||||
riskTargetOverrides.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -71,7 +71,17 @@ namespace QuantConnect.Algorithm.Framework.Selection
|
||||
/// <returns>The universes to be used by the algorithm</returns>
|
||||
public override IEnumerable<Universe> CreateUniverses(QCAlgorithm algorithm)
|
||||
{
|
||||
return _model.InvokeMethodAndEnumerate<Universe>(nameof(CreateUniverses), algorithm);
|
||||
using (Py.GIL())
|
||||
{
|
||||
var universes = _model.InvokeMethod(nameof(CreateUniverses), algorithm);
|
||||
var iterator = universes.GetIterator();
|
||||
foreach (PyObject universe in iterator)
|
||||
{
|
||||
yield return universe.GetAndDispose<Universe>();
|
||||
}
|
||||
iterator.Dispose();
|
||||
universes.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -872,7 +872,8 @@ namespace QuantConnect.AlgorithmFactory.Python.Wrappers
|
||||
{
|
||||
using (Py.GIL())
|
||||
{
|
||||
var result = InvokeMethod(nameof(OnMarginCall), requests);
|
||||
var method = GetMethod(nameof(OnMarginCall));
|
||||
var result = method.Invoke<PyObject>(requests);
|
||||
|
||||
if (_onMarginCall != null)
|
||||
{
|
||||
|
||||
@@ -39,7 +39,7 @@ namespace QuantConnect.Brokerages
|
||||
});
|
||||
|
||||
/// <summary>
|
||||
/// HashSet containing the order types supported by the <see cref="CanSubmitOrder"/> operation in TradeStation.
|
||||
/// HashSet containing the order types supported by TradeStation.
|
||||
/// </summary>
|
||||
private readonly HashSet<OrderType> _supportOrderTypes = new(
|
||||
new[]
|
||||
@@ -47,9 +47,7 @@ namespace QuantConnect.Brokerages
|
||||
OrderType.Market,
|
||||
OrderType.Limit,
|
||||
OrderType.StopMarket,
|
||||
OrderType.StopLimit,
|
||||
OrderType.ComboMarket,
|
||||
OrderType.ComboLimit,
|
||||
OrderType.StopLimit
|
||||
});
|
||||
|
||||
/// <summary>
|
||||
@@ -96,13 +94,9 @@ namespace QuantConnect.Brokerages
|
||||
|
||||
if (!_supportOrderTypes.Contains(order.Type))
|
||||
{
|
||||
message = new BrokerageMessageEvent(BrokerageMessageType.Warning, "NotSupported", Messages.DefaultBrokerageModel.UnsupportedOrderType(this, order, _supportOrderTypes));
|
||||
return false;
|
||||
}
|
||||
message = new BrokerageMessageEvent(BrokerageMessageType.Warning, "NotSupported",
|
||||
Messages.DefaultBrokerageModel.UnsupportedOrderType(this, order, _supportOrderTypes));
|
||||
|
||||
if (BrokerageExtensions.OrderCrossesZero(security.Holdings.Quantity, order.Quantity) && IsComboOrderType(order.Type))
|
||||
{
|
||||
message = new BrokerageMessageEvent(BrokerageMessageType.Warning, "NotSupported", Messages.DefaultBrokerageModel.UnsupportedCrossZeroByOrderType(this, order.Type));
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -121,7 +115,7 @@ namespace QuantConnect.Brokerages
|
||||
{
|
||||
message = null;
|
||||
|
||||
if (BrokerageExtensions.OrderCrossesZero(security.Holdings.Quantity, order.Quantity)
|
||||
if (BrokerageExtensions.OrderCrossesZero(security.Holdings.Quantity, order.Quantity)
|
||||
&& request.Quantity != null && request.Quantity != order.Quantity)
|
||||
{
|
||||
message = new BrokerageMessageEvent(BrokerageMessageType.Warning, "UpdateRejected",
|
||||
@@ -129,23 +123,7 @@ namespace QuantConnect.Brokerages
|
||||
return false;
|
||||
}
|
||||
|
||||
if (IsComboOrderType(order.Type) && request.Quantity != null && request.Quantity != order.Quantity)
|
||||
{
|
||||
message = new BrokerageMessageEvent(BrokerageMessageType.Warning, "NotSupported", Messages.DefaultBrokerageModel.UnsupportedUpdateQuantityOrder(this, order.Type));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines if the provided order type is a combo order.
|
||||
/// </summary>
|
||||
/// <param name="orderType">The order type to check.</param>
|
||||
/// <returns>True if the order type is a combo order; otherwise, false.</returns>
|
||||
private static bool IsComboOrderType(OrderType orderType)
|
||||
{
|
||||
return orderType == OrderType.ComboMarket || orderType == OrderType.ComboLimit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,101 +0,0 @@
|
||||
/*
|
||||
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
|
||||
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
namespace QuantConnect.Data.Market
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines the greeks
|
||||
/// </summary>
|
||||
public abstract class BaseGreeks
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the delta.
|
||||
/// <para>
|
||||
/// Delta measures the rate of change of the option value with respect to changes in
|
||||
/// the underlying asset'sprice. (∂V/∂S)
|
||||
/// </para>
|
||||
/// </summary>
|
||||
public abstract decimal Delta { get; protected set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the gamma.
|
||||
/// <para>
|
||||
/// Gamma measures the rate of change of Delta with respect to changes in
|
||||
/// the underlying asset'sprice. (∂²V/∂S²)
|
||||
/// </para>
|
||||
/// </summary>
|
||||
public abstract decimal Gamma { get; protected set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the vega.
|
||||
/// <para>
|
||||
/// Vega measures the rate of change of the option value with respect to changes in
|
||||
/// the underlying's volatility. (∂V/∂σ)
|
||||
/// </para>
|
||||
/// </summary>
|
||||
public abstract decimal Vega { get; protected set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the theta.
|
||||
/// <para>
|
||||
/// Theta measures the rate of change of the option value with respect to changes in
|
||||
/// time. This is commonly known as the 'time decay.' (∂V/∂τ)
|
||||
/// </para>
|
||||
/// </summary>
|
||||
public abstract decimal Theta { get; protected set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the rho.
|
||||
/// <para>
|
||||
/// Rho measures the rate of change of the option value with respect to changes in
|
||||
/// the risk free interest rate. (∂V/∂r)
|
||||
/// </para>
|
||||
/// </summary>
|
||||
public abstract decimal Rho { get; protected set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the lambda.
|
||||
/// <para>
|
||||
/// Lambda is the percentage change in option value per percentage change in the
|
||||
/// underlying's price, a measure of leverage. Sometimes referred to as gearing.
|
||||
/// (∂V/∂S ✕ S/V)
|
||||
/// </para>
|
||||
/// </summary>
|
||||
public abstract decimal Lambda { get; protected set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the lambda.
|
||||
/// <para>
|
||||
/// Lambda is the percentage change in option value per percentage change in the
|
||||
/// underlying's price, a measure of leverage. Sometimes referred to as gearing.
|
||||
/// (∂V/∂S ✕ S/V)
|
||||
/// </para>
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Alias for <see cref="Lambda"/> required for compatibility with Python when
|
||||
/// PEP8 API is used (lambda is a reserved keyword in Python).
|
||||
/// </remarks>
|
||||
public virtual decimal Lambda_ => Lambda;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the theta per day.
|
||||
/// <para>
|
||||
/// Theta measures the rate of change of the option value with respect to changes in
|
||||
/// time. This is commonly known as the 'time decay.' (∂V/∂τ)
|
||||
/// </para>
|
||||
/// </summary>
|
||||
public virtual decimal ThetaPerDay => Theta / 365m;
|
||||
}
|
||||
}
|
||||
@@ -20,7 +20,7 @@ namespace QuantConnect.Data.Market
|
||||
/// <summary>
|
||||
/// Defines the greeks
|
||||
/// </summary>
|
||||
public class Greeks : BaseGreeks
|
||||
public class Greeks
|
||||
{
|
||||
private Lazy<decimal> _delta;
|
||||
private Lazy<decimal> _gamma;
|
||||
@@ -33,84 +33,144 @@ namespace QuantConnect.Data.Market
|
||||
// for optimization purposes (approximation of delta and gamma is very similar)
|
||||
private Lazy<Tuple<decimal, decimal>> _deltaGamma;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override decimal Delta
|
||||
/// <summary>
|
||||
/// Gets the delta.
|
||||
/// <para>
|
||||
/// Delta measures the rate of change of the option value with respect to changes in
|
||||
/// the underlying asset'sprice. (∂V/∂S)
|
||||
/// </para>
|
||||
/// </summary>
|
||||
public decimal Delta
|
||||
{
|
||||
get
|
||||
{
|
||||
return _delta != null ? _delta.Value : _deltaGamma.Value.Item1;
|
||||
}
|
||||
protected set
|
||||
private set
|
||||
{
|
||||
_delta = new Lazy<decimal>(() => value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override decimal Gamma
|
||||
/// <summary>
|
||||
/// Gets the gamma.
|
||||
/// <para>
|
||||
/// Gamma measures the rate of change of Delta with respect to changes in
|
||||
/// the underlying asset'sprice. (∂²V/∂S²)
|
||||
/// </para>
|
||||
/// </summary>
|
||||
public decimal Gamma
|
||||
{
|
||||
get
|
||||
{
|
||||
return _gamma != null ? _gamma.Value : _deltaGamma.Value.Item2;
|
||||
}
|
||||
protected set
|
||||
private set
|
||||
{
|
||||
_gamma = new Lazy<decimal>(() => value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override decimal Vega
|
||||
/// <summary>
|
||||
/// Gets the vega.
|
||||
/// <para>
|
||||
/// Vega measures the rate of change of the option value with respect to changes in
|
||||
/// the underlying's volatility. (∂V/∂σ)
|
||||
/// </para>
|
||||
/// </summary>
|
||||
public decimal Vega
|
||||
{
|
||||
get
|
||||
{
|
||||
return _vega.Value;
|
||||
}
|
||||
protected set
|
||||
private set
|
||||
{
|
||||
_vega = new Lazy<decimal>(() => value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override decimal Theta
|
||||
/// <summary>
|
||||
/// Gets the theta.
|
||||
/// <para>
|
||||
/// Theta measures the rate of change of the option value with respect to changes in
|
||||
/// time. This is commonly known as the 'time decay.' (∂V/∂τ)
|
||||
/// </para>
|
||||
/// </summary>
|
||||
public decimal Theta
|
||||
{
|
||||
get
|
||||
{
|
||||
return _theta.Value;
|
||||
}
|
||||
protected set
|
||||
private set
|
||||
{
|
||||
_theta = new Lazy<decimal>(() => value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override decimal Rho
|
||||
/// <summary>
|
||||
/// Gets the rho.
|
||||
/// <para>
|
||||
/// Rho measures the rate of change of the option value with respect to changes in
|
||||
/// the risk free interest rate. (∂V/∂r)
|
||||
/// </para>
|
||||
/// </summary>
|
||||
public decimal Rho
|
||||
{
|
||||
get
|
||||
{
|
||||
return _rho.Value;
|
||||
}
|
||||
protected set
|
||||
private set
|
||||
{
|
||||
_rho = new Lazy<decimal>(() => value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override decimal Lambda
|
||||
/// <summary>
|
||||
/// Gets the lambda.
|
||||
/// <para>
|
||||
/// Lambda is the percentage change in option value per percentage change in the
|
||||
/// underlying's price, a measure of leverage. Sometimes referred to as gearing.
|
||||
/// (∂V/∂S ✕ S/V)
|
||||
/// </para>
|
||||
/// </summary>
|
||||
public decimal Lambda
|
||||
{
|
||||
get
|
||||
{
|
||||
return _lambda.Value;
|
||||
}
|
||||
protected set
|
||||
private set
|
||||
{
|
||||
_lambda = new Lazy<decimal>(() => value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the lambda.
|
||||
/// <para>
|
||||
/// Lambda is the percentage change in option value per percentage change in the
|
||||
/// underlying's price, a measure of leverage. Sometimes referred to as gearing.
|
||||
/// (∂V/∂S ✕ S/V)
|
||||
/// </para>
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Alias for <see cref="Lambda"/> required for compatibility with Python when
|
||||
/// PEP8 API is used (lambda is a reserved keyword in Python).
|
||||
/// </remarks>
|
||||
public decimal Lambda_ => Lambda;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the theta per day.
|
||||
/// <para>
|
||||
/// Theta measures the rate of change of the option value with respect to changes in
|
||||
/// time. This is commonly known as the 'time decay.' (∂V/∂τ)
|
||||
/// </para>
|
||||
/// </summary>
|
||||
public decimal ThetaPerDay => Theta / 365m;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new default instance of the <see cref="Greeks"/> class
|
||||
/// </summary>
|
||||
|
||||
@@ -33,8 +33,6 @@ namespace QuantConnect.Data
|
||||
{
|
||||
private readonly PriorityQueue<ConsolidatorWrapper, ConsolidatorScanPriority> _consolidatorsSortedByScanTime;
|
||||
private readonly Dictionary<IDataConsolidator, ConsolidatorWrapper> _consolidators;
|
||||
private List<Tuple<ConsolidatorWrapper, ConsolidatorScanPriority>> _consolidatorsToAdd;
|
||||
private readonly object _threadSafeCollectionLock;
|
||||
private readonly ITimeKeeper _timeKeeper;
|
||||
private IAlgorithmSubscriptionManager _subscriptionManager;
|
||||
|
||||
@@ -67,7 +65,6 @@ namespace QuantConnect.Data
|
||||
_consolidators = new();
|
||||
_timeKeeper = timeKeeper;
|
||||
_consolidatorsSortedByScanTime = new(1000);
|
||||
_threadSafeCollectionLock = new object();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -184,11 +181,7 @@ namespace QuantConnect.Data
|
||||
var wrapper = _consolidators[consolidator] =
|
||||
new ConsolidatorWrapper(consolidator, subscription.Increment, _timeKeeper, _timeKeeper.GetLocalTimeKeeper(subscription.ExchangeTimeZone));
|
||||
|
||||
lock (_threadSafeCollectionLock)
|
||||
{
|
||||
_consolidatorsToAdd ??= new();
|
||||
_consolidatorsToAdd.Add(new(wrapper, wrapper.Priority));
|
||||
}
|
||||
_consolidatorsSortedByScanTime.Enqueue(wrapper, wrapper.Priority);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -267,15 +260,6 @@ namespace QuantConnect.Data
|
||||
/// <param name="algorithm">The algorithm instance</param>
|
||||
public void ScanPastConsolidators(DateTime newUtcTime, IAlgorithm algorithm)
|
||||
{
|
||||
if (_consolidatorsToAdd != null)
|
||||
{
|
||||
lock (_threadSafeCollectionLock)
|
||||
{
|
||||
_consolidatorsToAdd.DoForEach(x => _consolidatorsSortedByScanTime.Enqueue(x.Item1, x.Item2));
|
||||
_consolidatorsToAdd = null;
|
||||
}
|
||||
}
|
||||
|
||||
while (_consolidatorsSortedByScanTime.TryPeek(out _, out var priority) && priority.UtcScanTime < newUtcTime)
|
||||
{
|
||||
var consolidatorToScan = _consolidatorsSortedByScanTime.Dequeue();
|
||||
|
||||
@@ -26,11 +26,6 @@ namespace QuantConnect.Data.UniverseSelection
|
||||
/// </summary>
|
||||
public class BaseDataCollection : BaseData, IEnumerable<BaseData>
|
||||
{
|
||||
/// <summary>
|
||||
/// Cache for the symbols to avoid creating them multiple times
|
||||
/// </summary>
|
||||
private static readonly Dictionary<string, Symbol> _symbolsCache = new();
|
||||
|
||||
private DateTime _endTime;
|
||||
|
||||
/// <summary>
|
||||
@@ -111,9 +106,13 @@ namespace QuantConnect.Data.UniverseSelection
|
||||
/// <param name="underlying">The associated underlying price data if any</param>
|
||||
/// <param name="filteredContracts">The contracts selected by the universe</param>
|
||||
public BaseDataCollection(DateTime time, DateTime endTime, Symbol symbol, List<BaseData> data, BaseData underlying, HashSet<Symbol> filteredContracts)
|
||||
: this(time, endTime, symbol, underlying, filteredContracts)
|
||||
{
|
||||
if (data != null && data.Count == 1 && data[0] is BaseDataCollection collection && collection.Data != null && collection.Data.Count > 0)
|
||||
Symbol = symbol;
|
||||
Time = time;
|
||||
_endTime = endTime;
|
||||
Underlying = underlying;
|
||||
FilteredContracts = filteredContracts;
|
||||
if (data != null && data.Count == 1 && data[0] is BaseDataCollection collection && collection.Data.Count > 0)
|
||||
{
|
||||
// we were given a base data collection, let's be nice and fetch it's data if it has any
|
||||
Data = collection.Data;
|
||||
@@ -124,26 +123,13 @@ namespace QuantConnect.Data.UniverseSelection
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper method to create an instance without setting the data list
|
||||
/// </summary>
|
||||
protected BaseDataCollection(DateTime time, DateTime endTime, Symbol symbol, BaseData underlying, HashSet<Symbol> filteredContracts)
|
||||
{
|
||||
Symbol = symbol;
|
||||
Time = time;
|
||||
_endTime = endTime;
|
||||
Underlying = underlying;
|
||||
FilteredContracts = filteredContracts;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Copy constructor for <see cref="BaseDataCollection"/>
|
||||
/// </summary>
|
||||
/// <param name="other">The base data collection being copied</param>
|
||||
public BaseDataCollection(BaseDataCollection other)
|
||||
: this(other.Time, other.EndTime, other.Symbol, other.Underlying, other.FilteredContracts)
|
||||
: this(other.Time, other.EndTime, other.Symbol, other.Data, other.Underlying, other.FilteredContracts)
|
||||
{
|
||||
Data = other.Data;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -163,7 +149,7 @@ namespace QuantConnect.Data.UniverseSelection
|
||||
/// <returns>Whether this contains data that should be stored in the security cache</returns>
|
||||
public override bool ShouldCacheToSecurity()
|
||||
{
|
||||
if (Data == null || Data.Count == 0)
|
||||
if (Data.Count == 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@@ -218,32 +204,5 @@ namespace QuantConnect.Data.UniverseSelection
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tries to get a symbol from the cache
|
||||
/// </summary>
|
||||
protected static bool TryGetCachedSymbol(string ticker, out Symbol symbol)
|
||||
{
|
||||
lock (_symbolsCache)
|
||||
{
|
||||
return _symbolsCache.TryGetValue(ticker, out symbol);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Caches a symbol
|
||||
/// </summary>
|
||||
protected static void CacheSymbol(string ticker, Symbol symbol)
|
||||
{
|
||||
lock (_symbolsCache)
|
||||
{
|
||||
// limit the cache size to help with memory usage
|
||||
if (_symbolsCache.Count >= 600000)
|
||||
{
|
||||
_symbolsCache.Clear();
|
||||
}
|
||||
_symbolsCache.TryAdd(ticker, symbol);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,10 +27,16 @@ namespace QuantConnect.Data.UniverseSelection
|
||||
/// </summary>
|
||||
public class OptionUniverse : BaseDataCollection, ISymbol
|
||||
{
|
||||
private const int StartingGreeksCsvIndex = 7;
|
||||
private string[] _csvLine;
|
||||
|
||||
// We keep the properties as they are in the csv file to reduce memory usage (strings vs decimals)
|
||||
private readonly string _csvLine;
|
||||
private decimal? _open;
|
||||
private decimal? _high;
|
||||
private decimal? _low;
|
||||
private decimal? _close;
|
||||
private decimal? _volume;
|
||||
private decimal? _openInterest;
|
||||
private decimal? _impliedVolatility;
|
||||
private Greeks _greeks;
|
||||
|
||||
/// <summary>
|
||||
/// The security identifier of the option symbol
|
||||
@@ -49,8 +55,12 @@ namespace QuantConnect.Data.UniverseSelection
|
||||
{
|
||||
get
|
||||
{
|
||||
// Parse the values every time to avoid keeping them in memory
|
||||
return _csvLine.GetDecimalFromCsv(0);
|
||||
if (!_open.HasValue)
|
||||
{
|
||||
_open = GetDecimalFromCsvLine(2);
|
||||
}
|
||||
|
||||
return _open.Value;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,7 +71,12 @@ namespace QuantConnect.Data.UniverseSelection
|
||||
{
|
||||
get
|
||||
{
|
||||
return _csvLine.GetDecimalFromCsv(1);
|
||||
if (!_high.HasValue)
|
||||
{
|
||||
_high = GetDecimalFromCsvLine(3);
|
||||
}
|
||||
|
||||
return _high.Value;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,7 +87,12 @@ namespace QuantConnect.Data.UniverseSelection
|
||||
{
|
||||
get
|
||||
{
|
||||
return _csvLine.GetDecimalFromCsv(2);
|
||||
if (!_low.HasValue)
|
||||
{
|
||||
_low = GetDecimalFromCsvLine(4);
|
||||
}
|
||||
|
||||
return _low.Value;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -83,7 +103,12 @@ namespace QuantConnect.Data.UniverseSelection
|
||||
{
|
||||
get
|
||||
{
|
||||
return _csvLine.GetDecimalFromCsv(3);
|
||||
if (!_close.HasValue)
|
||||
{
|
||||
_close = GetDecimalFromCsvLine(5);
|
||||
}
|
||||
|
||||
return _close.Value;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -94,53 +119,90 @@ namespace QuantConnect.Data.UniverseSelection
|
||||
{
|
||||
get
|
||||
{
|
||||
return _csvLine.GetDecimalFromCsv(4);
|
||||
if (!_volume.HasValue)
|
||||
{
|
||||
_volume = GetDecimalFromCsvLine(6);
|
||||
}
|
||||
|
||||
return _volume.Value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Open interest value of the option
|
||||
/// </summary>
|
||||
public decimal OpenInterest
|
||||
public decimal? OpenInterest
|
||||
{
|
||||
get
|
||||
{
|
||||
ThrowIfNotAnOption(nameof(OpenInterest));
|
||||
return _csvLine.GetDecimalFromCsv(5);
|
||||
|
||||
if (!_openInterest.HasValue)
|
||||
{
|
||||
_openInterest = GetDecimalFromCsvLine(7);
|
||||
}
|
||||
|
||||
return _openInterest.Value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Implied volatility value of the option
|
||||
/// </summary>
|
||||
public decimal ImpliedVolatility
|
||||
public decimal? ImpliedVolatility
|
||||
{
|
||||
get
|
||||
{
|
||||
ThrowIfNotAnOption(nameof(ImpliedVolatility));
|
||||
return _csvLine.GetDecimalFromCsv(6);
|
||||
|
||||
if (!_impliedVolatility.HasValue)
|
||||
{
|
||||
_impliedVolatility = GetDecimalFromCsvLine(8);
|
||||
}
|
||||
|
||||
return _impliedVolatility.Value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Greeks values of the option
|
||||
/// </summary>
|
||||
public BaseGreeks Greeks
|
||||
public Greeks Greeks
|
||||
{
|
||||
get
|
||||
{
|
||||
ThrowIfNotAnOption(nameof(Greeks));
|
||||
return new PreCalculatedGreeks(_csvLine);
|
||||
|
||||
if (_greeks == null)
|
||||
{
|
||||
_greeks = new Greeks(GetDecimalFromCsvLine(9),
|
||||
GetDecimalFromCsvLine(10),
|
||||
GetDecimalFromCsvLine(11),
|
||||
GetDecimalFromCsvLine(12),
|
||||
GetDecimalFromCsvLine(13),
|
||||
0m);
|
||||
}
|
||||
|
||||
return _greeks;
|
||||
}
|
||||
private set
|
||||
{
|
||||
_greeks = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Period of the data
|
||||
/// </summary>
|
||||
public TimeSpan Period { get; } = TimeSpan.FromDays(1);
|
||||
|
||||
/// <summary>
|
||||
/// Time that the data became available to use
|
||||
/// </summary>
|
||||
public override DateTime EndTime
|
||||
{
|
||||
get { return Time + QuantConnect.Time.OneDay; }
|
||||
set { Time = value - QuantConnect.Time.OneDay; }
|
||||
get { return Time + Period; }
|
||||
set { Time = value - Period; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -153,12 +215,35 @@ namespace QuantConnect.Data.UniverseSelection
|
||||
/// <summary>
|
||||
/// Creates a new instance of the <see cref="OptionUniverse"/> class
|
||||
/// </summary>
|
||||
public OptionUniverse(DateTime date, Symbol symbol, string csv)
|
||||
: base(date, date, symbol, null, null)
|
||||
public OptionUniverse(DateTime date, Symbol symbol, string[] csv)
|
||||
: base(date, symbol)
|
||||
{
|
||||
_csvLine = csv;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of the <see cref="OptionUniverse"/> class
|
||||
/// </summary>
|
||||
public OptionUniverse(DateTime date, Symbol symbol, decimal open, decimal high, decimal low, decimal close, decimal volume,
|
||||
decimal? openInterest, decimal? impliedVolatility, Greeks greeks)
|
||||
: base(date, symbol)
|
||||
{
|
||||
Initialize(open, high, low, close, volume, openInterest, impliedVolatility, greeks);
|
||||
}
|
||||
|
||||
private void Initialize(decimal? open, decimal? high, decimal? low, decimal? close, decimal? volume, decimal? openInterest,
|
||||
decimal? impliedVolatility, Greeks greeks)
|
||||
{
|
||||
_open = open;
|
||||
_high = high;
|
||||
_low = low;
|
||||
_close = close;
|
||||
_volume = volume;
|
||||
_openInterest = openInterest;
|
||||
_impliedVolatility = impliedVolatility;
|
||||
_greeks = greeks;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of the <see cref="OptionUniverse"/> class as a copy of the given instance
|
||||
/// </summary>
|
||||
@@ -166,6 +251,7 @@ namespace QuantConnect.Data.UniverseSelection
|
||||
: base(other)
|
||||
{
|
||||
_csvLine = other._csvLine;
|
||||
Initialize(other._open, other._high, other._low, other._close, other._volume, other._openInterest, other._impliedVolatility, other._greeks);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -188,58 +274,32 @@ namespace QuantConnect.Data.UniverseSelection
|
||||
/// each time it is called.
|
||||
/// </summary>
|
||||
/// <param name="config">Subscription data config setup object</param>
|
||||
/// <param name="stream">Stream reader of the source document</param>
|
||||
/// <param name="line">Line of the source document</param>
|
||||
/// <param name="date">Date of the requested data</param>
|
||||
/// <param name="isLiveMode">true if we're in live mode, false for backtesting mode</param>
|
||||
/// <returns>Instance of the T:BaseData object generated by this line of the CSV</returns>
|
||||
public override BaseData Reader(SubscriptionDataConfig config, StreamReader stream, DateTime date, bool isLiveMode)
|
||||
public override BaseData Reader(SubscriptionDataConfig config, string line, DateTime date, bool isLiveMode)
|
||||
{
|
||||
if (stream == null || stream.EndOfStream)
|
||||
if (string.IsNullOrEmpty(line) || line.StartsWith("#", StringComparison.InvariantCulture))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var sidStr = stream.GetString();
|
||||
var csv = line.Split(',');
|
||||
var sid = SecurityIdentifier.Parse(csv[0]);
|
||||
var symbolValue = csv[1];
|
||||
|
||||
if (sidStr.StartsWith("#", StringComparison.InvariantCulture))
|
||||
Symbol symbol;
|
||||
if (sid.HasUnderlying)
|
||||
{
|
||||
stream.ReadLine();
|
||||
return null;
|
||||
symbol = Symbol.CreateOption(sid, symbolValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
symbol = new Symbol(sid, symbolValue);
|
||||
}
|
||||
|
||||
var symbolValue = stream.GetString();
|
||||
var remainingLine = stream.ReadLine();
|
||||
|
||||
var key = $"{sidStr}:{symbolValue}";
|
||||
|
||||
if (!TryGetCachedSymbol(key, out var symbol))
|
||||
{
|
||||
var sid = SecurityIdentifier.Parse(sidStr);
|
||||
|
||||
if (sid.HasUnderlying)
|
||||
{
|
||||
// Let's try to get the underlying symbol from the cache
|
||||
SymbolRepresentation.TryDecomposeOptionTickerOSI(symbolValue, sid.SecurityType,
|
||||
out var _, out var underlyingValue, out var _, out var _, out var _);
|
||||
var underlyingKey = $"{sid.Underlying}:{underlyingValue}";
|
||||
var underlyingWasCached = TryGetCachedSymbol(underlyingKey, out var underlyingSymbol);
|
||||
|
||||
symbol = Symbol.CreateOption(sid, symbolValue, underlyingSymbol);
|
||||
|
||||
if (!underlyingWasCached)
|
||||
{
|
||||
CacheSymbol(underlyingKey, symbol.Underlying);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
symbol = new Symbol(sid, symbolValue);
|
||||
}
|
||||
|
||||
CacheSymbol(key, symbol);
|
||||
}
|
||||
|
||||
return new OptionUniverse(date, symbol, remainingLine);
|
||||
return new OptionUniverse(date, symbol, csv);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -276,24 +336,13 @@ namespace QuantConnect.Data.UniverseSelection
|
||||
return new OptionUniverse(this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the default resolution for this data and security type
|
||||
/// </summary>
|
||||
/// <remarks>This is a method and not a property so that python
|
||||
/// custom data types can override it</remarks>
|
||||
public override Resolution DefaultResolution()
|
||||
{
|
||||
return Resolution.Daily;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the CSV string representation of this universe entry
|
||||
/// </summary>
|
||||
public static string ToCsv(Symbol symbol, decimal open, decimal high, decimal low, decimal close, decimal volume, decimal? openInterest,
|
||||
decimal? impliedVolatility, BaseGreeks greeks)
|
||||
public string ToCsv()
|
||||
{
|
||||
return $"{symbol.ID},{symbol.Value},{open},{high},{low},{close},{volume},"
|
||||
+ $"{openInterest},{impliedVolatility},{greeks?.Delta},{greeks?.Gamma},{greeks?.Vega},{greeks?.Theta},{greeks?.Rho}";
|
||||
return $"{Symbol.ID},{Symbol.Value},{Open},{High},{Low},{Close},{Volume}," +
|
||||
$"{_openInterest},{_impliedVolatility},{_greeks?.Delta},{_greeks?.Gamma},{_greeks?.Vega},{_greeks?.Theta},{_greeks?.Rho}";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -319,6 +368,11 @@ namespace QuantConnect.Data.UniverseSelection
|
||||
public static string CsvHeader => "symbol_id,symbol_value,open,high,low,close,volume,open_interest,implied_volatility,delta,gamma,vega,theta,rho";
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private decimal GetDecimalFromCsvLine(int index)
|
||||
{
|
||||
return !_csvLine.IsNullOrEmpty() ? _csvLine[index].ToDecimal() : decimal.Zero;
|
||||
}
|
||||
|
||||
private void ThrowIfNotAnOption(string propertyName)
|
||||
{
|
||||
if (!Symbol.SecurityType.IsOption())
|
||||
@@ -326,64 +380,5 @@ namespace QuantConnect.Data.UniverseSelection
|
||||
throw new InvalidOperationException($"{propertyName} is only available for options.");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Pre-calculated greeks lazily parsed from csv line.
|
||||
/// It parses the greeks values from the csv line only when they are requested to avoid holding decimals in memory.
|
||||
/// </summary>
|
||||
private class PreCalculatedGreeks : BaseGreeks
|
||||
{
|
||||
private readonly string _csvLine;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override decimal Delta
|
||||
{
|
||||
get => _csvLine.GetDecimalFromCsv(StartingGreeksCsvIndex);
|
||||
protected set => throw new InvalidOperationException("Delta is read-only.");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override decimal Gamma
|
||||
{
|
||||
get => _csvLine.GetDecimalFromCsv(StartingGreeksCsvIndex + 1);
|
||||
protected set => throw new InvalidOperationException("Gamma is read-only.");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override decimal Vega
|
||||
{
|
||||
get => _csvLine.GetDecimalFromCsv(StartingGreeksCsvIndex + 2);
|
||||
protected set => throw new InvalidOperationException("Vega is read-only.");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override decimal Theta
|
||||
{
|
||||
get => _csvLine.GetDecimalFromCsv(StartingGreeksCsvIndex + 3);
|
||||
protected set => throw new InvalidOperationException("Theta is read-only.");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override decimal Rho
|
||||
{
|
||||
get => _csvLine.GetDecimalFromCsv(StartingGreeksCsvIndex + 4);
|
||||
protected set => throw new InvalidOperationException("Rho is read-only.");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override decimal Lambda
|
||||
{
|
||||
get => decimal.Zero;
|
||||
protected set => throw new InvalidOperationException("Lambda is read-only.");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new default instance of the <see cref="PreCalculatedGreeks"/> class
|
||||
/// </summary>
|
||||
public PreCalculatedGreeks(string csvLine)
|
||||
{
|
||||
_csvLine = csvLine;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -97,7 +97,17 @@ namespace QuantConnect.Data.UniverseSelection
|
||||
/// <returns>The data that passes the filter</returns>
|
||||
public override IEnumerable<Symbol> SelectSymbols(DateTime utcTime, BaseDataCollection data)
|
||||
{
|
||||
return _model.InvokeMethodAndEnumerate<Symbol>(nameof(SelectSymbols), utcTime, data);
|
||||
using (Py.GIL())
|
||||
{
|
||||
var symbols = _model.InvokeMethod(nameof(SelectSymbols), utcTime, data);
|
||||
var iterator = symbols.GetIterator();
|
||||
foreach (PyObject symbol in iterator)
|
||||
{
|
||||
yield return symbol.GetAndDispose<Symbol>();
|
||||
}
|
||||
iterator.Dispose();
|
||||
symbols.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -111,11 +121,18 @@ namespace QuantConnect.Data.UniverseSelection
|
||||
public override IEnumerable<SubscriptionRequest> GetSubscriptionRequests(Security security, DateTime currentTimeUtc, DateTime maximumEndTimeUtc,
|
||||
ISubscriptionDataConfigService subscriptionService)
|
||||
{
|
||||
var requests = _model.InvokeMethodAndEnumerate<SubscriptionRequest>(nameof(GetSubscriptionRequests), security, currentTimeUtc,
|
||||
maximumEndTimeUtc, subscriptionService);
|
||||
foreach (var subscriptionRequest in requests)
|
||||
using (Py.GIL())
|
||||
{
|
||||
yield return new SubscriptionRequest(subscriptionRequest, universe: this);
|
||||
var subscriptionRequests = _model.InvokeMethod(nameof(GetSubscriptionRequests), security, currentTimeUtc,
|
||||
maximumEndTimeUtc, subscriptionService);
|
||||
var iterator = subscriptionRequests.GetIterator();
|
||||
foreach (PyObject request in iterator)
|
||||
{
|
||||
var subscriptionRequest = request.GetAndDispose<SubscriptionRequest>();
|
||||
yield return new SubscriptionRequest(subscriptionRequest, universe:this);
|
||||
}
|
||||
iterator.Dispose();
|
||||
subscriptionRequests.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user