Compare commits
50 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d94a1d09a4 | ||
|
|
2c843cae9e | ||
|
|
039fdf7e4a | ||
|
|
2c63546c37 | ||
|
|
58682e1bbd | ||
|
|
d11a375fdb | ||
|
|
6ab91a13e1 | ||
|
|
beaa705646 | ||
|
|
4c830c8235 | ||
|
|
395c1123da | ||
|
|
8e50645640 | ||
|
|
68ca504d3a | ||
|
|
12df1c9a31 | ||
|
|
4de25b6cd4 | ||
|
|
cdef9e709a | ||
|
|
3579fecc58 | ||
|
|
3a390cfa9f | ||
|
|
58dae061e7 | ||
|
|
3f2479393f | ||
|
|
4849588c3b | ||
|
|
3d84c76abb | ||
|
|
1c3d849ad5 | ||
|
|
271220083b | ||
|
|
b29d0cbfaf | ||
|
|
27a25cd663 | ||
|
|
5ed61db2bb | ||
|
|
4a1485a291 | ||
|
|
d6072c88a5 | ||
|
|
20910ca2dc | ||
|
|
c333ccdc4a | ||
|
|
88c4a332bc | ||
|
|
5d762d16b2 | ||
|
|
e2a0873b7c | ||
|
|
31ebaaeaa9 | ||
|
|
7625e232f4 | ||
|
|
63f3af7afe | ||
|
|
87b42f6fb5 | ||
|
|
f9dc38efab | ||
|
|
5587efaadd | ||
|
|
a642d53bf9 | ||
|
|
002151eab2 | ||
|
|
4c085ff853 | ||
|
|
3aa76d4289 | ||
|
|
5236fc202d | ||
|
|
1ca4389ed2 | ||
|
|
b8397db0b7 | ||
|
|
d4ea5f7b04 | ||
|
|
458272b2ea | ||
|
|
6c7353d09a | ||
|
|
834d4a4d58 |
2
.gitignore
vendored
2
.gitignore
vendored
@@ -196,6 +196,7 @@ publish/
|
||||
|
||||
# NuGet Packages
|
||||
*.nupkg
|
||||
!LocalPackages/*
|
||||
# The packages folder can be ignored because of Package Restore
|
||||
**/packages/*
|
||||
# except build/, which is used as an MSBuild target.
|
||||
@@ -204,6 +205,7 @@ publish/
|
||||
#!**/packages/repositories.config
|
||||
# ignore sln level nuget
|
||||
.nuget/
|
||||
!.nuget/NuGet.config
|
||||
|
||||
# Windows Azure Build Output
|
||||
csx/
|
||||
|
||||
10
.nuget/NuGet.config
Normal file
10
.nuget/NuGet.config
Normal file
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration>
|
||||
<packageRestore>
|
||||
<add key="enabled" value="true" />
|
||||
<add key="automatic" value="true" />
|
||||
</packageRestore>
|
||||
<packageSources>
|
||||
<add key="LocalPackages" value="../LocalPackages" />
|
||||
</packageSources>
|
||||
</configuration>
|
||||
@@ -6,6 +6,7 @@ mono:
|
||||
solution: QuantConnect.Lean.sln
|
||||
before_install:
|
||||
- export PATH="$HOME/miniconda3/bin:$PATH"
|
||||
- export PYTHONNET_PYDLL="$HOME/miniconda3/lib/libpython3.6m.so"
|
||||
- wget -q https://cdn.quantconnect.com/miniconda/Miniconda3-4.5.12-Linux-x86_64.sh
|
||||
- bash Miniconda3-4.5.12-Linux-x86_64.sh -b
|
||||
- rm -rf Miniconda3-4.5.12-Linux-x86_64.sh
|
||||
@@ -20,6 +21,7 @@ before_install:
|
||||
install:
|
||||
- nuget install NUnit.Runners -Version 3.11.1 -OutputDirectory testrunner
|
||||
script:
|
||||
- dotnet nuget add source $TRAVIS_BUILD_DIR/LocalPackages
|
||||
- dotnet build /p:Configuration=Release /p:VbcToolExe=vbnc.exe /v:quiet /p:WarningLevel=1 QuantConnect.Lean.sln
|
||||
- mono ./testrunner/NUnit.ConsoleRunner.3.11.1/tools/nunit3-console.exe ./Tests/bin/Release/QuantConnect.Tests.dll --where "cat != TravisExclude" --labels=Off --params:log-handler=ConsoleErrorLogHandler
|
||||
- chmod +x ci_build_stubs.sh
|
||||
|
||||
@@ -94,7 +94,7 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
{"Tracking Error", "0.212"},
|
||||
{"Treynor Ratio", "-2.13"},
|
||||
{"Total Fees", "$199.00"},
|
||||
{"Estimated Strategy Capacity", "$280000000.00"},
|
||||
{"Estimated Strategy Capacity", "$23000000.00"},
|
||||
{"Fitness Score", "0.002"},
|
||||
{"Kelly Criterion Estimate", "38.64"},
|
||||
{"Kelly Criterion Probability Value", "0.229"},
|
||||
|
||||
@@ -130,7 +130,7 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
{"Tracking Error", "0.367"},
|
||||
{"Treynor Ratio", "-4.079"},
|
||||
{"Total Fees", "$14.33"},
|
||||
{"Estimated Strategy Capacity", "$29000000.00"},
|
||||
{"Estimated Strategy Capacity", "$38000000.00"},
|
||||
{"Fitness Score", "0.408"},
|
||||
{"Kelly Criterion Estimate", "16.447"},
|
||||
{"Kelly Criterion Probability Value", "0.315"},
|
||||
|
||||
@@ -139,7 +139,7 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
{"Tracking Error", "0.058"},
|
||||
{"Treynor Ratio", "2.133"},
|
||||
{"Total Fees", "$2.00"},
|
||||
{"Estimated Strategy Capacity", "$6400000.00"},
|
||||
{"Estimated Strategy Capacity", "$45000000.00"},
|
||||
{"Fitness Score", "0"},
|
||||
{"Kelly Criterion Estimate", "0"},
|
||||
{"Kelly Criterion Probability Value", "0"},
|
||||
|
||||
@@ -191,7 +191,7 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
{"Tracking Error", "0.042"},
|
||||
{"Treynor Ratio", "0.286"},
|
||||
{"Total Fees", "$2.00"},
|
||||
{"Estimated Strategy Capacity", "$1400000.00"},
|
||||
{"Estimated Strategy Capacity", "$2800000.00"},
|
||||
{"Fitness Score", "0"},
|
||||
{"Kelly Criterion Estimate", "0"},
|
||||
{"Kelly Criterion Probability Value", "0"},
|
||||
|
||||
@@ -79,19 +79,19 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
// things like manually added, auto added, internal, and any other boolean state we need to track against a single security)
|
||||
throw new Exception("The underlying equity data should NEVER be removed in this algorithm because it was manually added");
|
||||
}
|
||||
if (_expectedSecurities.AreDifferent(LinqExtensions.ToHashSet(Securities.Keys)))
|
||||
if (_expectedSecurities.AreDifferent(Securities.Keys.ToHashSet()))
|
||||
{
|
||||
var expected = string.Join(Environment.NewLine, _expectedSecurities.OrderBy(s => s.ToString()));
|
||||
var actual = string.Join(Environment.NewLine, Securities.Keys.OrderBy(s => s.ToString()));
|
||||
throw new Exception($"{Time}:: Detected differences in expected and actual securities{Environment.NewLine}Expected:{Environment.NewLine}{expected}{Environment.NewLine}Actual:{Environment.NewLine}{actual}");
|
||||
}
|
||||
if (_expectedUniverses.AreDifferent(LinqExtensions.ToHashSet(UniverseManager.Keys)))
|
||||
if (_expectedUniverses.AreDifferent(Securities.Keys.ToHashSet()))
|
||||
{
|
||||
var expected = string.Join(Environment.NewLine, _expectedUniverses.OrderBy(s => s.ToString()));
|
||||
var actual = string.Join(Environment.NewLine, UniverseManager.Keys.OrderBy(s => s.ToString()));
|
||||
throw new Exception($"{Time}:: Detected differences in expected and actual universes{Environment.NewLine}Expected:{Environment.NewLine}{expected}{Environment.NewLine}Actual:{Environment.NewLine}{actual}");
|
||||
}
|
||||
if (_expectedData.AreDifferent(LinqExtensions.ToHashSet(data.Keys)))
|
||||
if (_expectedData.AreDifferent(Securities.Keys.ToHashSet()))
|
||||
{
|
||||
var expected = string.Join(Environment.NewLine, _expectedData.OrderBy(s => s.ToString()));
|
||||
var actual = string.Join(Environment.NewLine, data.Keys.OrderBy(s => s.ToString()));
|
||||
@@ -183,7 +183,7 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
if (changes.RemovedSecurities
|
||||
.Where(x => x.Symbol.SecurityType == SecurityType.Option)
|
||||
.ToHashSet(s => s.Symbol)
|
||||
.AreDifferent(LinqExtensions.ToHashSet(_expectedContracts)))
|
||||
.AreDifferent(_expectedContracts.ToHashSet()))
|
||||
{
|
||||
throw new Exception("Expected removed securities to equal expected contracts added");
|
||||
}
|
||||
@@ -230,7 +230,7 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
{"Tracking Error", "0"},
|
||||
{"Treynor Ratio", "0"},
|
||||
{"Total Fees", "$6.00"},
|
||||
{"Estimated Strategy Capacity", "$3000.00"},
|
||||
{"Estimated Strategy Capacity", "$1500.00"},
|
||||
{"Fitness Score", "0"},
|
||||
{"Kelly Criterion Estimate", "0"},
|
||||
{"Kelly Criterion Probability Value", "0"},
|
||||
|
||||
@@ -131,7 +131,7 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
{"Tracking Error", "0.072"},
|
||||
{"Treynor Ratio", "2.933"},
|
||||
{"Total Fees", "$26.39"},
|
||||
{"Estimated Strategy Capacity", "$2200000.00"},
|
||||
{"Estimated Strategy Capacity", "$4400000.00"},
|
||||
{"Fitness Score", "0.374"},
|
||||
{"Kelly Criterion Estimate", "0"},
|
||||
{"Kelly Criterion Probability Value", "0"},
|
||||
|
||||
@@ -84,7 +84,7 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
{"Tracking Error", "0.006"},
|
||||
{"Treynor Ratio", "2.029"},
|
||||
{"Total Fees", "$9.77"},
|
||||
{"Estimated Strategy Capacity", "$28000000.00"},
|
||||
{"Estimated Strategy Capacity", "$37000000.00"},
|
||||
{"Fitness Score", "0.747"},
|
||||
{"Kelly Criterion Estimate", "38.64"},
|
||||
{"Kelly Criterion Probability Value", "0.229"},
|
||||
|
||||
@@ -103,7 +103,7 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
{"Tracking Error", "0.376"},
|
||||
{"Treynor Ratio", "-0.084"},
|
||||
{"Total Fees", "$13.98"},
|
||||
{"Estimated Strategy Capacity", "$31000000.00"},
|
||||
{"Estimated Strategy Capacity", "$61000000.00"},
|
||||
{"Fitness Score", "0.146"},
|
||||
{"Kelly Criterion Estimate", "0"},
|
||||
{"Kelly Criterion Probability Value", "1"},
|
||||
|
||||
@@ -110,7 +110,7 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
{"Tracking Error", "0.194"},
|
||||
{"Treynor Ratio", "-0.962"},
|
||||
{"Total Fees", "$25.92"},
|
||||
{"Estimated Strategy Capacity", "$16000000.00"},
|
||||
{"Estimated Strategy Capacity", "$69000000.00"},
|
||||
{"Fitness Score", "0.004"},
|
||||
{"Kelly Criterion Estimate", "0"},
|
||||
{"Kelly Criterion Probability Value", "1"},
|
||||
|
||||
@@ -211,7 +211,7 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
{"Tracking Error", "0.068"},
|
||||
{"Treynor Ratio", "1.722"},
|
||||
{"Total Fees", "$307.50"},
|
||||
{"Estimated Strategy Capacity", "$710000.00"},
|
||||
{"Estimated Strategy Capacity", "$2800000.00"},
|
||||
{"Fitness Score", "0.173"},
|
||||
{"Kelly Criterion Estimate", "0"},
|
||||
{"Kelly Criterion Probability Value", "0"},
|
||||
|
||||
@@ -98,7 +98,7 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
{"Tracking Error", "0.099"},
|
||||
{"Treynor Ratio", "-5.187"},
|
||||
{"Total Fees", "$65.00"},
|
||||
{"Estimated Strategy Capacity", "$2300000000.00"},
|
||||
{"Estimated Strategy Capacity", "$16000000000.00"},
|
||||
{"Fitness Score", "0"},
|
||||
{"Kelly Criterion Estimate", "0"},
|
||||
{"Kelly Criterion Probability Value", "0"},
|
||||
|
||||
@@ -130,7 +130,7 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
{"Tracking Error", "0.001"},
|
||||
{"Treynor Ratio", "1.922"},
|
||||
{"Total Fees", "$3.26"},
|
||||
{"Estimated Strategy Capacity", "$15000000.00"},
|
||||
{"Estimated Strategy Capacity", "$58000000.00"},
|
||||
{"Fitness Score", "0.248"},
|
||||
{"Kelly Criterion Estimate", "0"},
|
||||
{"Kelly Criterion Probability Value", "0"},
|
||||
|
||||
@@ -97,7 +97,7 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
{"Tracking Error", "0.001"},
|
||||
{"Treynor Ratio", "1.922"},
|
||||
{"Total Fees", "$3.26"},
|
||||
{"Estimated Strategy Capacity", "$15000000.00"},
|
||||
{"Estimated Strategy Capacity", "$58000000.00"},
|
||||
{"Fitness Score", "0.248"},
|
||||
{"Kelly Criterion Estimate", "0"},
|
||||
{"Kelly Criterion Probability Value", "0"},
|
||||
|
||||
@@ -88,7 +88,7 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
{"Tracking Error", "0.221"},
|
||||
{"Treynor Ratio", "-13.568"},
|
||||
{"Total Fees", "$3.26"},
|
||||
{"Estimated Strategy Capacity", "$130000000.00"},
|
||||
{"Estimated Strategy Capacity", "$890000000.00"},
|
||||
{"Fitness Score", "0.111"},
|
||||
{"Kelly Criterion Estimate", "0"},
|
||||
{"Kelly Criterion Probability Value", "0"},
|
||||
|
||||
@@ -109,7 +109,7 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
{"Tracking Error", "0.002"},
|
||||
{"Treynor Ratio", "1.839"},
|
||||
{"Total Fees", "$9.77"},
|
||||
{"Estimated Strategy Capacity", "$20000000.00"},
|
||||
{"Estimated Strategy Capacity", "$27000000.00"},
|
||||
{"Fitness Score", "0.747"},
|
||||
{"Kelly Criterion Estimate", "38.64"},
|
||||
{"Kelly Criterion Probability Value", "0.229"},
|
||||
|
||||
@@ -147,7 +147,7 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
{"Tracking Error", "0.504"},
|
||||
{"Treynor Ratio", "1.011"},
|
||||
{"Total Fees", "$15207.00"},
|
||||
{"Estimated Strategy Capacity", "$8800000.00"},
|
||||
{"Estimated Strategy Capacity", "$7700.00"},
|
||||
{"Fitness Score", "0.033"},
|
||||
{"Kelly Criterion Estimate", "0"},
|
||||
{"Kelly Criterion Probability Value", "0"},
|
||||
|
||||
@@ -155,7 +155,7 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
{"Tracking Error", "0.188"},
|
||||
{"Treynor Ratio", "-3.318"},
|
||||
{"Total Fees", "$3.70"},
|
||||
{"Estimated Strategy Capacity", "$13000000.00"},
|
||||
{"Estimated Strategy Capacity", "$52000000.00"},
|
||||
{"Fitness Score", "0.009"},
|
||||
{"Kelly Criterion Estimate", "-112.972"},
|
||||
{"Kelly Criterion Probability Value", "0.671"},
|
||||
|
||||
157
Algorithm.CSharp/BasicTemplateIndexAlgorithm.cs
Normal file
157
Algorithm.CSharp/BasicTemplateIndexAlgorithm.cs
Normal file
@@ -0,0 +1,157 @@
|
||||
/*
|
||||
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
|
||||
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
using System;
|
||||
using QuantConnect.Data;
|
||||
using System.Collections.Generic;
|
||||
using QuantConnect.Indicators;
|
||||
using QuantConnect.Interfaces;
|
||||
|
||||
namespace QuantConnect.Algorithm.CSharp
|
||||
{
|
||||
/// <summary>
|
||||
/// This example demonstrates how to add index asset types.
|
||||
/// </summary>
|
||||
/// <meta name="tag" content="using data" />
|
||||
/// <meta name="tag" content="benchmarks" />
|
||||
/// <meta name="tag" content="indexes" />
|
||||
public class BasicTemplateIndexAlgorithm : QCAlgorithm, IRegressionAlgorithmDefinition
|
||||
{
|
||||
private Symbol _spx;
|
||||
private Symbol _spxOption;
|
||||
private ExponentialMovingAverage _emaSlow;
|
||||
private ExponentialMovingAverage _emaFast;
|
||||
|
||||
/// <summary>
|
||||
/// Initialize your algorithm and add desired assets.
|
||||
/// </summary>
|
||||
public override void Initialize()
|
||||
{
|
||||
SetStartDate(2021, 1, 4);
|
||||
SetEndDate(2021, 1, 15);
|
||||
SetCash(1000000);
|
||||
|
||||
// Use indicator for signal; but it cannot be traded
|
||||
_spx = AddIndex("SPX", Resolution.Minute).Symbol;
|
||||
|
||||
// Trade on SPX ITM calls
|
||||
_spxOption = QuantConnect.Symbol.CreateOption(
|
||||
_spx,
|
||||
Market.USA,
|
||||
OptionStyle.European,
|
||||
OptionRight.Call,
|
||||
3200m,
|
||||
new DateTime(2021, 1, 15));
|
||||
|
||||
AddIndexOptionContract(_spxOption, Resolution.Minute);
|
||||
|
||||
_emaSlow = EMA(_spx, 80);
|
||||
_emaFast = EMA(_spx, 200);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Index EMA Cross trading underlying.
|
||||
/// </summary>
|
||||
public override void OnData(Slice slice)
|
||||
{
|
||||
if (!slice.Bars.ContainsKey(_spx) || !slice.Bars.ContainsKey(_spxOption))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Warm up indicators
|
||||
if (!_emaSlow.IsReady)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (_emaFast > _emaSlow)
|
||||
{
|
||||
SetHoldings(_spxOption, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
Liquidate();
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnEndOfAlgorithm()
|
||||
{
|
||||
if (Portfolio[_spx].TotalSaleVolume > 0)
|
||||
{
|
||||
throw new Exception("Index is not tradable.");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This is used by the regression test system to indicate if the open source Lean repository has the required data to run this algorithm.
|
||||
/// </summary>
|
||||
public bool CanRunLocally { get; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// This is used by the regression test system to indicate which languages this algorithm is written in.
|
||||
/// </summary>
|
||||
public Language[] Languages { get; } = { Language.CSharp, Language.Python };
|
||||
|
||||
/// <summary>
|
||||
/// This is used by the regression test system to indicate what the expected statistics are from running the algorithm
|
||||
/// </summary>
|
||||
public Dictionary<string, string> ExpectedStatistics => new Dictionary<string, string>
|
||||
{
|
||||
{"Total Trades", "4"},
|
||||
{"Average Win", "0%"},
|
||||
{"Average Loss", "-53.10%"},
|
||||
{"Compounding Annual Return", "-96.172%"},
|
||||
{"Drawdown", "10.100%"},
|
||||
{"Expectancy", "-1"},
|
||||
{"Net Profit", "-9.915%"},
|
||||
{"Sharpe Ratio", "-4.217"},
|
||||
{"Probabilistic Sharpe Ratio", "0.052%"},
|
||||
{"Loss Rate", "100%"},
|
||||
{"Win Rate", "0%"},
|
||||
{"Profit-Loss Ratio", "0"},
|
||||
{"Alpha", "0"},
|
||||
{"Beta", "0"},
|
||||
{"Annual Standard Deviation", "0.139"},
|
||||
{"Annual Variance", "0.019"},
|
||||
{"Information Ratio", "-4.217"},
|
||||
{"Tracking Error", "0.139"},
|
||||
{"Treynor Ratio", "0"},
|
||||
{"Total Fees", "$0.00"},
|
||||
{"Estimated Strategy Capacity", "$14000000.00"},
|
||||
{"Fitness Score", "0.044"},
|
||||
{"Kelly Criterion Estimate", "0"},
|
||||
{"Kelly Criterion Probability Value", "0"},
|
||||
{"Sortino Ratio", "-1.96"},
|
||||
{"Return Over Maximum Drawdown", "-10.171"},
|
||||
{"Portfolio Turnover", "0.34"},
|
||||
{"Total Insights Generated", "0"},
|
||||
{"Total Insights Closed", "0"},
|
||||
{"Total Insights Analysis Completed", "0"},
|
||||
{"Long Insight Count", "0"},
|
||||
{"Short Insight Count", "0"},
|
||||
{"Long/Short Ratio", "100%"},
|
||||
{"Estimated Monthly Alpha Value", "$0"},
|
||||
{"Total Accumulated Estimated Alpha Value", "$0"},
|
||||
{"Mean Population Estimated Insight Value", "$0"},
|
||||
{"Mean Population Direction", "0%"},
|
||||
{"Mean Population Magnitude", "0%"},
|
||||
{"Rolling Averaged Population Direction", "0%"},
|
||||
{"Rolling Averaged Population Magnitude", "0%"},
|
||||
{"OrderListHash", "52521ab779446daf4d38a7c9bbbdd893"}
|
||||
};
|
||||
}
|
||||
}
|
||||
180
Algorithm.CSharp/BasicTemplateIndexOptionsAlgorithm.cs
Normal file
180
Algorithm.CSharp/BasicTemplateIndexOptionsAlgorithm.cs
Normal file
@@ -0,0 +1,180 @@
|
||||
/*
|
||||
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
|
||||
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
using System;
|
||||
using QuantConnect.Data;
|
||||
using System.Collections.Generic;
|
||||
using QuantConnect.Indicators;
|
||||
using QuantConnect.Interfaces;
|
||||
|
||||
namespace QuantConnect.Algorithm.CSharp
|
||||
{
|
||||
/// <summary>
|
||||
/// This example demonstrates how to add index asset types and trade index options on SPX.
|
||||
/// </summary>
|
||||
public class BasicTemplateIndexOptionsAlgorithm : QCAlgorithm, IRegressionAlgorithmDefinition
|
||||
{
|
||||
private Symbol _spx;
|
||||
private ExponentialMovingAverage _emaSlow;
|
||||
private ExponentialMovingAverage _emaFast;
|
||||
|
||||
/// <summary>
|
||||
/// Initialize your algorithm and add desired assets.
|
||||
/// </summary>
|
||||
public override void Initialize()
|
||||
{
|
||||
SetStartDate(2021, 1, 4);
|
||||
SetEndDate(2021, 2, 1);
|
||||
SetCash(1000000);
|
||||
|
||||
// Use indicator for signal; but it cannot be traded.
|
||||
// We will instead trade on SPX options
|
||||
_spx = AddIndex("SPX", Resolution.Minute).Symbol;
|
||||
var spxOptions = AddIndexOption(_spx, Resolution.Minute);
|
||||
spxOptions.SetFilter(filterFunc => filterFunc.CallsOnly());
|
||||
|
||||
_emaSlow = EMA(_spx, 80);
|
||||
_emaFast = EMA(_spx, 200);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Index EMA Cross trading index options of the index.
|
||||
/// </summary>
|
||||
public override void OnData(Slice slice)
|
||||
{
|
||||
if (!slice.Bars.ContainsKey(_spx))
|
||||
{
|
||||
Debug($"No SPX on {Time}");
|
||||
return;
|
||||
}
|
||||
|
||||
// Warm up indicators
|
||||
if (!_emaSlow.IsReady)
|
||||
{
|
||||
Debug($"EMA slow not ready on {Time}");
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var chain in slice.OptionChains.Values)
|
||||
{
|
||||
foreach (var contract in chain.Contracts.Values)
|
||||
{
|
||||
if (contract.Expiry.Month == 3 && contract.Symbol.ID.StrikePrice == 3700m && contract.Right == OptionRight.Call && slice.QuoteBars.ContainsKey(contract.Symbol))
|
||||
{
|
||||
Log($"{Time} {contract.Strike}{(contract.Right == OptionRight.Call ? 'C' : 'P')} -- {slice.QuoteBars[contract.Symbol]}");
|
||||
}
|
||||
|
||||
if (Portfolio.Invested)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (_emaFast > _emaSlow && contract.Right == OptionRight.Call)
|
||||
{
|
||||
Liquidate(InvertOption(contract.Symbol));
|
||||
MarketOrder(contract.Symbol, 1);
|
||||
}
|
||||
else if (_emaFast < _emaSlow && contract.Right == OptionRight.Put)
|
||||
{
|
||||
Liquidate(InvertOption(contract.Symbol));
|
||||
MarketOrder(contract.Symbol, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnEndOfAlgorithm()
|
||||
{
|
||||
if (Portfolio[_spx].TotalSaleVolume > 0)
|
||||
{
|
||||
throw new Exception("Index is not tradable.");
|
||||
}
|
||||
if (Portfolio.TotalSaleVolume == 0)
|
||||
{
|
||||
throw new Exception("Trade volume should be greater than zero by the end of this algorithm");
|
||||
}
|
||||
}
|
||||
|
||||
public Symbol InvertOption(Symbol symbol)
|
||||
{
|
||||
return QuantConnect.Symbol.CreateOption(
|
||||
symbol.Underlying,
|
||||
symbol.ID.Market,
|
||||
symbol.ID.OptionStyle,
|
||||
symbol.ID.OptionRight == OptionRight.Call ? OptionRight.Put : OptionRight.Call,
|
||||
symbol.ID.StrikePrice,
|
||||
symbol.ID.Date);
|
||||
}
|
||||
|
||||
/// <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; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// This is used by the regression test system to indicate which languages this algorithm is written in.
|
||||
/// </summary>
|
||||
public Language[] Languages { get; } = { Language.CSharp, Language.Python };
|
||||
|
||||
/// <summary>
|
||||
/// This is used by the regression test system to indicate what the expected statistics are from running the algorithm
|
||||
/// </summary>
|
||||
public Dictionary<string, string> ExpectedStatistics => new Dictionary<string, string>
|
||||
{
|
||||
{"Total Trades", "8220"},
|
||||
{"Average Win", "0.00%"},
|
||||
{"Average Loss", "0.00%"},
|
||||
{"Compounding Annual Return", "-100.000%"},
|
||||
{"Drawdown", "13.500%"},
|
||||
{"Expectancy", "-0.818"},
|
||||
{"Net Profit", "-13.517%"},
|
||||
{"Sharpe Ratio", "-2.678"},
|
||||
{"Probabilistic Sharpe Ratio", "0%"},
|
||||
{"Loss Rate", "89%"},
|
||||
{"Win Rate", "11%"},
|
||||
{"Profit-Loss Ratio", "0.69"},
|
||||
{"Alpha", "4.398"},
|
||||
{"Beta", "-0.989"},
|
||||
{"Annual Standard Deviation", "0.373"},
|
||||
{"Annual Variance", "0.139"},
|
||||
{"Information Ratio", "-12.816"},
|
||||
{"Tracking Error", "0.504"},
|
||||
{"Treynor Ratio", "1.011"},
|
||||
{"Total Fees", "$15207.00"},
|
||||
{"Estimated Strategy Capacity", "$8800000.00"},
|
||||
{"Fitness Score", "0.033"},
|
||||
{"Kelly Criterion Estimate", "0"},
|
||||
{"Kelly Criterion Probability Value", "0"},
|
||||
{"Sortino Ratio", "-8.62"},
|
||||
{"Return Over Maximum Drawdown", "-7.81"},
|
||||
{"Portfolio Turnover", "302.321"},
|
||||
{"Total Insights Generated", "0"},
|
||||
{"Total Insights Closed", "0"},
|
||||
{"Total Insights Analysis Completed", "0"},
|
||||
{"Long Insight Count", "0"},
|
||||
{"Short Insight Count", "0"},
|
||||
{"Long/Short Ratio", "100%"},
|
||||
{"Estimated Monthly Alpha Value", "$0"},
|
||||
{"Total Accumulated Estimated Alpha Value", "$0"},
|
||||
{"Mean Population Estimated Insight Value", "$0"},
|
||||
{"Mean Population Direction", "0%"},
|
||||
{"Mean Population Magnitude", "0%"},
|
||||
{"Rolling Averaged Population Direction", "0%"},
|
||||
{"Rolling Averaged Population Magnitude", "0%"},
|
||||
{"OrderListHash", "35b3f4b7a225468d42ca085386a2383e"}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -134,7 +134,7 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
{"Tracking Error", "0"},
|
||||
{"Treynor Ratio", "0"},
|
||||
{"Total Fees", "$778.00"},
|
||||
{"Estimated Strategy Capacity", "$180000.00"},
|
||||
{"Estimated Strategy Capacity", "$720.00"},
|
||||
{"Fitness Score", "0"},
|
||||
{"Kelly Criterion Estimate", "0"},
|
||||
{"Kelly Criterion Probability Value", "0"},
|
||||
|
||||
@@ -131,7 +131,7 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
{"Tracking Error", "0"},
|
||||
{"Treynor Ratio", "0"},
|
||||
{"Total Fees", "$2.00"},
|
||||
{"Estimated Strategy Capacity", "$2600000.00"},
|
||||
{"Estimated Strategy Capacity", "$1300000.00"},
|
||||
{"Fitness Score", "0"},
|
||||
{"Kelly Criterion Estimate", "0"},
|
||||
{"Kelly Criterion Probability Value", "0"},
|
||||
|
||||
@@ -28,11 +28,11 @@ namespace QuantConnect.Algorithm.CSharp.Benchmarks
|
||||
_symbol = AddEquity("SPY").Symbol;
|
||||
}
|
||||
|
||||
public override void OnEndOfDay()
|
||||
public override void OnEndOfDay(Symbol symbol)
|
||||
{
|
||||
var minuteHistory = History(_symbol, 60, Resolution.Minute);
|
||||
var minuteHistory = History(symbol, 60, Resolution.Minute);
|
||||
var lastHourHigh = minuteHistory.Select(minuteBar => minuteBar.High).DefaultIfEmpty(0).Max();
|
||||
var dailyHistory = History(_symbol, 1, Resolution.Daily).First();
|
||||
var dailyHistory = History(symbol, 1, Resolution.Daily).First();
|
||||
var dailyHigh = dailyHistory.High;
|
||||
var dailyLow = dailyHistory.Low;
|
||||
var dailyOpen = dailyHistory.Open;
|
||||
|
||||
@@ -94,7 +94,7 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
{"Tracking Error", "0.09"},
|
||||
{"Treynor Ratio", "0.82"},
|
||||
{"Total Fees", "$41.70"},
|
||||
{"Estimated Strategy Capacity", "$2000000.00"},
|
||||
{"Estimated Strategy Capacity", "$3000000.00"},
|
||||
{"Fitness Score", "0.634"},
|
||||
{"Kelly Criterion Estimate", "13.656"},
|
||||
{"Kelly Criterion Probability Value", "0.228"},
|
||||
|
||||
@@ -181,7 +181,7 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
{"Tracking Error", "0.149"},
|
||||
{"Treynor Ratio", "-1.405"},
|
||||
{"Total Fees", "$2.00"},
|
||||
{"Estimated Strategy Capacity", "$6000000.00"},
|
||||
{"Estimated Strategy Capacity", "$42000000.00"},
|
||||
{"Fitness Score", "0.076"},
|
||||
{"Kelly Criterion Estimate", "0"},
|
||||
{"Kelly Criterion Probability Value", "0"},
|
||||
|
||||
@@ -136,7 +136,7 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
{"Tracking Error", "0.126"},
|
||||
{"Treynor Ratio", "-0.607"},
|
||||
{"Total Fees", "$11.63"},
|
||||
{"Estimated Strategy Capacity", "$13000000.00"},
|
||||
{"Estimated Strategy Capacity", "$46000000.00"},
|
||||
{"Fitness Score", "0.013"},
|
||||
{"Kelly Criterion Estimate", "0"},
|
||||
{"Kelly Criterion Probability Value", "0"},
|
||||
|
||||
@@ -120,7 +120,7 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
{"Tracking Error", "0.105"},
|
||||
{"Treynor Ratio", "1.667"},
|
||||
{"Total Fees", "$2.91"},
|
||||
{"Estimated Strategy Capacity", "$96000000.00"},
|
||||
{"Estimated Strategy Capacity", "$670000000.00"},
|
||||
{"Fitness Score", "0.141"},
|
||||
{"Kelly Criterion Estimate", "0"},
|
||||
{"Kelly Criterion Probability Value", "0"},
|
||||
|
||||
@@ -91,7 +91,7 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
{"Tracking Error", "0.101"},
|
||||
{"Treynor Ratio", "5.409"},
|
||||
{"Total Fees", "$67.00"},
|
||||
{"Estimated Strategy Capacity", "$2400000.00"},
|
||||
{"Estimated Strategy Capacity", "$3200000.00"},
|
||||
{"Fitness Score", "0.501"},
|
||||
{"Kelly Criterion Estimate", "0"},
|
||||
{"Kelly Criterion Probability Value", "0"},
|
||||
|
||||
@@ -85,7 +85,7 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
{"Tracking Error", "0.009"},
|
||||
{"Treynor Ratio", "1.575"},
|
||||
{"Total Fees", "$22.77"},
|
||||
{"Estimated Strategy Capacity", "$19000000.00"},
|
||||
{"Estimated Strategy Capacity", "$22000000.00"},
|
||||
{"Fitness Score", "0.999"},
|
||||
{"Kelly Criterion Estimate", "38.64"},
|
||||
{"Kelly Criterion Probability Value", "0.229"},
|
||||
|
||||
@@ -94,7 +94,7 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
{"Tracking Error", "0.165"},
|
||||
{"Treynor Ratio", "1.212"},
|
||||
{"Total Fees", "$6.00"},
|
||||
{"Estimated Strategy Capacity", "$32000000.00"},
|
||||
{"Estimated Strategy Capacity", "$42000000.00"},
|
||||
{"Fitness Score", "0.063"},
|
||||
{"Kelly Criterion Estimate", "38.64"},
|
||||
{"Kelly Criterion Probability Value", "0.229"},
|
||||
|
||||
@@ -190,7 +190,7 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
{"Tracking Error", "0.176"},
|
||||
{"Treynor Ratio", "-1.46"},
|
||||
{"Total Fees", "$7.82"},
|
||||
{"Estimated Strategy Capacity", "$6000000.00"},
|
||||
{"Estimated Strategy Capacity", "$12000000.00"},
|
||||
{"Fitness Score", "0.1"},
|
||||
{"Kelly Criterion Estimate", "0"},
|
||||
{"Kelly Criterion Probability Value", "0"},
|
||||
|
||||
@@ -146,7 +146,7 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
{"Tracking Error", "0.239"},
|
||||
{"Treynor Ratio", "-1.435"},
|
||||
{"Total Fees", "$755.29"},
|
||||
{"Estimated Strategy Capacity", "$150000000.00"},
|
||||
{"Estimated Strategy Capacity", "$1100000000.00"},
|
||||
{"Fitness Score", "0.024"},
|
||||
{"Kelly Criterion Estimate", "-0.84"},
|
||||
{"Kelly Criterion Probability Value", "0.53"},
|
||||
|
||||
@@ -99,7 +99,7 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
{"Tracking Error", "0.168"},
|
||||
{"Treynor Ratio", "2.38"},
|
||||
{"Total Fees", "$3.26"},
|
||||
{"Estimated Strategy Capacity", "$75000000.00"},
|
||||
{"Estimated Strategy Capacity", "$300000000.00"},
|
||||
{"Fitness Score", "0.245"},
|
||||
{"Kelly Criterion Estimate", "0"},
|
||||
{"Kelly Criterion Probability Value", "0"},
|
||||
|
||||
@@ -96,7 +96,7 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
{"Tracking Error", "0"},
|
||||
{"Treynor Ratio", "0.988"},
|
||||
{"Total Fees", "$7.78"},
|
||||
{"Estimated Strategy Capacity", "$2200000.00"},
|
||||
{"Estimated Strategy Capacity", "$8700000.00"},
|
||||
{"Fitness Score", "0.031"},
|
||||
{"Kelly Criterion Estimate", "0"},
|
||||
{"Kelly Criterion Probability Value", "0"},
|
||||
|
||||
@@ -43,7 +43,7 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
security.SetBuyingPowerModel(new CustomBuyingPowerModel());
|
||||
}
|
||||
|
||||
public void OnData(Slice slice)
|
||||
public override void OnData(Slice slice)
|
||||
{
|
||||
if (Portfolio.Invested)
|
||||
{
|
||||
@@ -113,7 +113,7 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
{"Tracking Error", "1.04"},
|
||||
{"Treynor Ratio", "5.073"},
|
||||
{"Total Fees", "$30.00"},
|
||||
{"Estimated Strategy Capacity", "$2800000.00"},
|
||||
{"Estimated Strategy Capacity", "$20000000.00"},
|
||||
{"Fitness Score", "0.418"},
|
||||
{"Kelly Criterion Estimate", "0"},
|
||||
{"Kelly Criterion Probability Value", "0"},
|
||||
|
||||
@@ -80,7 +80,7 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
/// OnEndOfDay Event Handler - At the end of each trading day we fire this code.
|
||||
/// To avoid flooding, we recommend running your plotting at the end of each day.
|
||||
/// </summary>
|
||||
public override void OnEndOfDay()
|
||||
public override void OnEndOfDay(Symbol symbol)
|
||||
{
|
||||
//Log the end of day prices:
|
||||
Plot("Trade Plot", "Price", _lastPrice);
|
||||
|
||||
@@ -119,7 +119,7 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
{"Tracking Error", "0.112"},
|
||||
{"Treynor Ratio", "-6.121"},
|
||||
{"Total Fees", "$3.50"},
|
||||
{"Estimated Strategy Capacity", "$6900000.00"},
|
||||
{"Estimated Strategy Capacity", "$48000000.00"},
|
||||
{"Fitness Score", "0"},
|
||||
{"Kelly Criterion Estimate", "0"},
|
||||
{"Kelly Criterion Probability Value", "0"},
|
||||
|
||||
@@ -124,7 +124,7 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
{"Tracking Error", "0.112"},
|
||||
{"Treynor Ratio", "-6.121"},
|
||||
{"Total Fees", "$3.50"},
|
||||
{"Estimated Strategy Capacity", "$6900000.00"},
|
||||
{"Estimated Strategy Capacity", "$48000000.00"},
|
||||
{"Fitness Score", "0"},
|
||||
{"Kelly Criterion Estimate", "0"},
|
||||
{"Kelly Criterion Probability Value", "0"},
|
||||
|
||||
@@ -131,7 +131,7 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
{"Tracking Error", "0.19"},
|
||||
{"Treynor Ratio", "2.159"},
|
||||
{"Total Fees", "$1.00"},
|
||||
{"Estimated Strategy Capacity", "$14000000.00"},
|
||||
{"Estimated Strategy Capacity", "$58000000.00"},
|
||||
{"Fitness Score", "0.1"},
|
||||
{"Kelly Criterion Estimate", "0"},
|
||||
{"Kelly Criterion Probability Value", "0"},
|
||||
|
||||
@@ -58,7 +58,9 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
//Weather used as a tradable asset, like stocks, futures etc.
|
||||
if (data.Close != 0)
|
||||
{
|
||||
Order("BTC", (Portfolio.MarginRemaining / Math.Abs(data.Close + 1)));
|
||||
// It's only OK to use SetHoldings with crypto when using custom data. When trading with built-in crypto data,
|
||||
// use the cashbook. Reference https://github.com/QuantConnect/Lean/blob/master/Algorithm.Python/BasicTemplateCryptoAlgorithm.py
|
||||
SetHoldings("BTC", 1);
|
||||
}
|
||||
Console.WriteLine("Buying BTC 'Shares': BTC: " + data.Close);
|
||||
}
|
||||
@@ -117,7 +119,7 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
|
||||
//return "http://my-ftp-server.com/futures-data-" + date.ToString("Ymd") + ".zip";
|
||||
// OR simply return a fixed small data file. Large files will slow down your backtest
|
||||
return new SubscriptionDataSource("https://www.quandl.com/api/v3/datasets/BCHARTS/BITSTAMPUSD.csv?order=asc", SubscriptionTransportMedium.RemoteFile);
|
||||
return new SubscriptionDataSource("https://www.quantconnect.com/api/v2/proxy/quandl/api/v3/datasets/BCHARTS/BITSTAMPUSD.csv?order=asc&api_key=WyAazVXnq7ATy_fefTqm", SubscriptionTransportMedium.RemoteFile);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -154,6 +156,7 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
{
|
||||
string[] data = line.Split(',');
|
||||
coin.Time = DateTime.Parse(data[0], CultureInfo.InvariantCulture);
|
||||
coin.EndTime = coin.Time.AddDays(1);
|
||||
coin.Open = Convert.ToDecimal(data[1], CultureInfo.InvariantCulture);
|
||||
coin.High = Convert.ToDecimal(data[2], CultureInfo.InvariantCulture);
|
||||
coin.Low = Convert.ToDecimal(data[3], CultureInfo.InvariantCulture);
|
||||
|
||||
@@ -61,7 +61,7 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
/// "Nifty" type below and fired into this event handler.
|
||||
/// </summary>
|
||||
/// <param name="data">One(1) Nifty Object, streamed into our algorithm synchronised in time with our other data streams</param>
|
||||
public void OnData(Slice data)
|
||||
public override void OnData(Slice data)
|
||||
{
|
||||
if (data.ContainsKey("USDINR"))
|
||||
{
|
||||
@@ -77,7 +77,7 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
{
|
||||
|
||||
_today.NiftyPrice = Convert.ToDouble(data["NIFTY"].Close);
|
||||
if (_today.Date == data["NIFTY"].EndTime)
|
||||
if (_today.Date == data["NIFTY"].Time)
|
||||
{
|
||||
_prices.Add(_today);
|
||||
|
||||
@@ -91,7 +91,7 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
var quantity = (int)(Portfolio.MarginRemaining * 0.9m / data["NIFTY"].Close);
|
||||
var highestNifty = (from pair in _prices select pair.NiftyPrice).Max();
|
||||
var lowestNifty = (from pair in _prices select pair.NiftyPrice).Min();
|
||||
|
||||
|
||||
if (Time.DayOfWeek == DayOfWeek.Wednesday) //prices.Count >= minimumCorrelationHistory &&
|
||||
{
|
||||
//List<double> niftyPrices = (from pair in prices select pair.NiftyPrice).ToList();
|
||||
@@ -121,7 +121,7 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
/// End of a trading day event handler. This method is called at the end of the algorithm day (or multiple times if trading multiple assets).
|
||||
/// </summary>
|
||||
/// <remarks>Method is called 10 minutes before closing to allow user to close out position.</remarks>
|
||||
public override void OnEndOfDay()
|
||||
public override void OnEndOfDay(Symbol symbol)
|
||||
{
|
||||
Plot("Nifty Closing Price", _today.NiftyPrice);
|
||||
}
|
||||
@@ -181,6 +181,7 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
//2011-09-13 7792.9 7799.9 7722.65 7748.7 116534670 6107.78
|
||||
var data = line.Split(',');
|
||||
index.Time = DateTime.Parse(data[0], CultureInfo.InvariantCulture);
|
||||
index.EndTime = index.Time.AddDays(1);
|
||||
index.Open = Convert.ToDecimal(data[1], CultureInfo.InvariantCulture);
|
||||
index.High = Convert.ToDecimal(data[2], CultureInfo.InvariantCulture);
|
||||
index.Low = Convert.ToDecimal(data[3], CultureInfo.InvariantCulture);
|
||||
@@ -247,6 +248,7 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
{
|
||||
var data = line.Split(',');
|
||||
currency.Time = DateTime.Parse(data[0], CultureInfo.InvariantCulture);
|
||||
currency.EndTime = currency.Time.AddDays(1);
|
||||
currency.Close = Convert.ToDecimal(data[1], CultureInfo.InvariantCulture);
|
||||
currency.Symbol = "USDINR";
|
||||
currency.Value = currency.Close;
|
||||
|
||||
@@ -114,29 +114,29 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
{"Total Trades", "1"},
|
||||
{"Average Win", "0%"},
|
||||
{"Average Loss", "0%"},
|
||||
{"Compounding Annual Return", "155.262%"},
|
||||
{"Compounding Annual Return", "157.498%"},
|
||||
{"Drawdown", "84.800%"},
|
||||
{"Expectancy", "0"},
|
||||
{"Net Profit", "5123.242%"},
|
||||
{"Sharpe Ratio", "2.067"},
|
||||
{"Probabilistic Sharpe Ratio", "68.833%"},
|
||||
{"Net Profit", "5319.081%"},
|
||||
{"Sharpe Ratio", "2.086"},
|
||||
{"Probabilistic Sharpe Ratio", "69.456%"},
|
||||
{"Loss Rate", "0%"},
|
||||
{"Win Rate", "0%"},
|
||||
{"Profit-Loss Ratio", "0"},
|
||||
{"Alpha", "1.732"},
|
||||
{"Beta", "0.037"},
|
||||
{"Annual Standard Deviation", "0.841"},
|
||||
{"Annual Variance", "0.707"},
|
||||
{"Information Ratio", "1.902"},
|
||||
{"Tracking Error", "0.848"},
|
||||
{"Treynor Ratio", "46.992"},
|
||||
{"Alpha", "1.736"},
|
||||
{"Beta", "0.136"},
|
||||
{"Annual Standard Deviation", "0.84"},
|
||||
{"Annual Variance", "0.706"},
|
||||
{"Information Ratio", "1.925"},
|
||||
{"Tracking Error", "0.846"},
|
||||
{"Treynor Ratio", "12.904"},
|
||||
{"Total Fees", "$0.00"},
|
||||
{"Estimated Strategy Capacity", "$0"},
|
||||
{"Fitness Score", "0"},
|
||||
{"Kelly Criterion Estimate", "0"},
|
||||
{"Kelly Criterion Probability Value", "0"},
|
||||
{"Sortino Ratio", "2.238"},
|
||||
{"Return Over Maximum Drawdown", "1.832"},
|
||||
{"Sortino Ratio", "2.269"},
|
||||
{"Return Over Maximum Drawdown", "1.858"},
|
||||
{"Portfolio Turnover", "0"},
|
||||
{"Total Insights Generated", "0"},
|
||||
{"Total Insights Closed", "0"},
|
||||
@@ -151,7 +151,7 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
{"Mean Population Magnitude", "0%"},
|
||||
{"Rolling Averaged Population Direction", "0%"},
|
||||
{"Rolling Averaged Population Magnitude", "0%"},
|
||||
{"OrderListHash", "1f54fb75ebcc0daafa5d45bfbaa4fbcb"}
|
||||
{"OrderListHash", "0d80bb47bd16b5bc6989a4c1c7aa8349"}
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
@@ -243,6 +243,7 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
{
|
||||
string[] data = line.Split(',');
|
||||
coin.Time = DateTime.Parse(data[0], CultureInfo.InvariantCulture);
|
||||
coin.EndTime = coin.Time.AddDays(1);
|
||||
coin.Open = Convert.ToDecimal(data[1], CultureInfo.InvariantCulture);
|
||||
coin.High = Convert.ToDecimal(data[2], CultureInfo.InvariantCulture);
|
||||
coin.Low = Convert.ToDecimal(data[3], CultureInfo.InvariantCulture);
|
||||
@@ -258,4 +259,4 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -84,29 +84,29 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
{"Total Trades", "1"},
|
||||
{"Average Win", "0%"},
|
||||
{"Average Loss", "0%"},
|
||||
{"Compounding Annual Return", "155.262%"},
|
||||
{"Compounding Annual Return", "157.497%"},
|
||||
{"Drawdown", "84.800%"},
|
||||
{"Expectancy", "0"},
|
||||
{"Net Profit", "5123.170%"},
|
||||
{"Sharpe Ratio", "2.066"},
|
||||
{"Probabilistic Sharpe Ratio", "68.832%"},
|
||||
{"Net Profit", "5319.007%"},
|
||||
{"Sharpe Ratio", "2.086"},
|
||||
{"Probabilistic Sharpe Ratio", "69.456%"},
|
||||
{"Loss Rate", "0%"},
|
||||
{"Win Rate", "0%"},
|
||||
{"Profit-Loss Ratio", "0"},
|
||||
{"Alpha", "1.732"},
|
||||
{"Beta", "0.037"},
|
||||
{"Annual Standard Deviation", "0.841"},
|
||||
{"Annual Variance", "0.707"},
|
||||
{"Information Ratio", "1.902"},
|
||||
{"Tracking Error", "0.848"},
|
||||
{"Treynor Ratio", "46.996"},
|
||||
{"Alpha", "1.736"},
|
||||
{"Beta", "0.136"},
|
||||
{"Annual Standard Deviation", "0.84"},
|
||||
{"Annual Variance", "0.706"},
|
||||
{"Information Ratio", "1.925"},
|
||||
{"Tracking Error", "0.846"},
|
||||
{"Treynor Ratio", "12.903"},
|
||||
{"Total Fees", "$0.00"},
|
||||
{"Estimated Strategy Capacity", "$0"},
|
||||
{"Fitness Score", "0"},
|
||||
{"Kelly Criterion Estimate", "0"},
|
||||
{"Kelly Criterion Probability Value", "0"},
|
||||
{"Sortino Ratio", "2.238"},
|
||||
{"Return Over Maximum Drawdown", "1.832"},
|
||||
{"Sortino Ratio", "2.269"},
|
||||
{"Return Over Maximum Drawdown", "1.858"},
|
||||
{"Portfolio Turnover", "0"},
|
||||
{"Total Insights Generated", "0"},
|
||||
{"Total Insights Closed", "0"},
|
||||
@@ -121,7 +121,7 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
{"Mean Population Magnitude", "0%"},
|
||||
{"Rolling Averaged Population Direction", "0%"},
|
||||
{"Rolling Averaged Population Magnitude", "0%"},
|
||||
{"OrderListHash", "0e7d560d0db2829adb19d3e403c30d97"}
|
||||
{"OrderListHash", "50faa37f15732bf5c24ad1eeaa335bc7"}
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
@@ -213,6 +213,7 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
{
|
||||
string[] data = line.Split(',');
|
||||
coin.Time = DateTime.Parse(data[0], CultureInfo.InvariantCulture);
|
||||
coin.EndTime = coin.Time.AddDays(1);
|
||||
coin.Open = Convert.ToDecimal(data[1], CultureInfo.InvariantCulture);
|
||||
coin.High = Convert.ToDecimal(data[2], CultureInfo.InvariantCulture);
|
||||
coin.Low = Convert.ToDecimal(data[3], CultureInfo.InvariantCulture);
|
||||
@@ -228,4 +229,4 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -212,7 +212,7 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
{"Tracking Error", "0.118"},
|
||||
{"Treynor Ratio", "-0.591"},
|
||||
{"Total Fees", "$62.24"},
|
||||
{"Estimated Strategy Capacity", "$100000000.00"},
|
||||
{"Estimated Strategy Capacity", "$49000000.00"},
|
||||
{"Fitness Score", "0.147"},
|
||||
{"Kelly Criterion Estimate", "0"},
|
||||
{"Kelly Criterion Probability Value", "0"},
|
||||
|
||||
@@ -103,7 +103,7 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
{"Tracking Error", "0.251"},
|
||||
{"Treynor Ratio", "9.323"},
|
||||
{"Total Fees", "$3.26"},
|
||||
{"Estimated Strategy Capacity", "$220000000.00"},
|
||||
{"Estimated Strategy Capacity", "$890000000.00"},
|
||||
{"Fitness Score", "0.201"},
|
||||
{"Kelly Criterion Estimate", "0"},
|
||||
{"Kelly Criterion Probability Value", "0"},
|
||||
|
||||
@@ -113,7 +113,7 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
{"Tracking Error", "0.08"},
|
||||
{"Treynor Ratio", "0.517"},
|
||||
{"Total Fees", "$3.70"},
|
||||
{"Estimated Strategy Capacity", "$38000000.00"},
|
||||
{"Estimated Strategy Capacity", "$270000000.00"},
|
||||
{"Fitness Score", "0.019"},
|
||||
{"Kelly Criterion Estimate", "0"},
|
||||
{"Kelly Criterion Probability Value", "0"},
|
||||
|
||||
@@ -123,7 +123,7 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
{"Tracking Error", "0.115"},
|
||||
{"Treynor Ratio", "1.545"},
|
||||
{"Total Fees", "$37.00"},
|
||||
{"Estimated Strategy Capacity", "$58000.00"},
|
||||
{"Estimated Strategy Capacity", "$400000.00"},
|
||||
{"Fitness Score", "0"},
|
||||
{"Kelly Criterion Estimate", "0"},
|
||||
{"Kelly Criterion Probability Value", "0"},
|
||||
|
||||
@@ -186,7 +186,7 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
{"Tracking Error", "0.204"},
|
||||
{"Treynor Ratio", "-8.165"},
|
||||
{"Total Fees", "$46.75"},
|
||||
{"Estimated Strategy Capacity", "$96000000.00"},
|
||||
{"Estimated Strategy Capacity", "$670000000.00"},
|
||||
{"Fitness Score", "0.002"},
|
||||
{"Kelly Criterion Estimate", "0"},
|
||||
{"Kelly Criterion Probability Value", "0"},
|
||||
|
||||
@@ -204,7 +204,7 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
{"Tracking Error", "0.171"},
|
||||
{"Treynor Ratio", "-1.761"},
|
||||
{"Total Fees", "$8669.41"},
|
||||
{"Estimated Strategy Capacity", "$170000.00"},
|
||||
{"Estimated Strategy Capacity", "$320000.00"},
|
||||
{"Fitness Score", "0.675"},
|
||||
{"Kelly Criterion Estimate", "0"},
|
||||
{"Kelly Criterion Probability Value", "0"},
|
||||
|
||||
@@ -177,7 +177,7 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
{"Tracking Error", "0.171"},
|
||||
{"Treynor Ratio", "-1.971"},
|
||||
{"Total Fees", "$6806.67"},
|
||||
{"Estimated Strategy Capacity", "$150000.00"},
|
||||
{"Estimated Strategy Capacity", "$320000.00"},
|
||||
{"Fitness Score", "0.694"},
|
||||
{"Kelly Criterion Estimate", "0"},
|
||||
{"Kelly Criterion Probability Value", "0"},
|
||||
|
||||
@@ -131,7 +131,7 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
{"Tracking Error", "0.29"},
|
||||
{"Treynor Ratio", "4.005"},
|
||||
{"Total Fees", "$18.28"},
|
||||
{"Estimated Strategy Capacity", "$200000000.00"},
|
||||
{"Estimated Strategy Capacity", "$500000000.00"},
|
||||
{"Fitness Score", "0.052"},
|
||||
{"Kelly Criterion Estimate", "0"},
|
||||
{"Kelly Criterion Probability Value", "0"},
|
||||
|
||||
@@ -127,7 +127,7 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
{"Tracking Error", "0.204"},
|
||||
{"Treynor Ratio", "-1.424"},
|
||||
{"Total Fees", "$16.26"},
|
||||
{"Estimated Strategy Capacity", "$250000000.00"},
|
||||
{"Estimated Strategy Capacity", "$590000000.00"},
|
||||
{"Fitness Score", "0.003"},
|
||||
{"Kelly Criterion Estimate", "12.539"},
|
||||
{"Kelly Criterion Probability Value", "0.367"},
|
||||
|
||||
@@ -148,7 +148,7 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
{"Tracking Error", "1.441"},
|
||||
{"Treynor Ratio", "-0.15"},
|
||||
{"Total Fees", "$33.30"},
|
||||
{"Estimated Strategy Capacity", "$4200000.00"},
|
||||
{"Estimated Strategy Capacity", "$17000000.00"},
|
||||
{"Fitness Score", "0.079"},
|
||||
{"Kelly Criterion Estimate", "-9.366"},
|
||||
{"Kelly Criterion Probability Value", "0.607"},
|
||||
|
||||
@@ -184,7 +184,7 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
{"Tracking Error", "0.123"},
|
||||
{"Treynor Ratio", "-1.288"},
|
||||
{"Total Fees", "$669.76"},
|
||||
{"Estimated Strategy Capacity", "$8100000.00"},
|
||||
{"Estimated Strategy Capacity", "$210000.00"},
|
||||
{"Fitness Score", "0.021"},
|
||||
{"Kelly Criterion Estimate", "0"},
|
||||
{"Kelly Criterion Probability Value", "0"},
|
||||
|
||||
@@ -147,7 +147,7 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
{"Tracking Error", "0.049"},
|
||||
{"Treynor Ratio", "-0.934"},
|
||||
{"Total Fees", "$22.26"},
|
||||
{"Estimated Strategy Capacity", "$3600000.00"},
|
||||
{"Estimated Strategy Capacity", "$360000.00"},
|
||||
{"Fitness Score", "0.002"},
|
||||
{"Kelly Criterion Estimate", "0"},
|
||||
{"Kelly Criterion Probability Value", "0"},
|
||||
|
||||
@@ -122,7 +122,7 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
{"Tracking Error", "0.186"},
|
||||
{"Treynor Ratio", "1.557"},
|
||||
{"Total Fees", "$4.00"},
|
||||
{"Estimated Strategy Capacity", "$1400000.00"},
|
||||
{"Estimated Strategy Capacity", "$5200000.00"},
|
||||
{"Fitness Score", "0.012"},
|
||||
{"Kelly Criterion Estimate", "0"},
|
||||
{"Kelly Criterion Probability Value", "0"},
|
||||
|
||||
@@ -174,7 +174,7 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
{"Tracking Error", "0"},
|
||||
{"Treynor Ratio", "0"},
|
||||
{"Total Fees", "$804.33"},
|
||||
{"Estimated Strategy Capacity", "$21000.00"},
|
||||
{"Estimated Strategy Capacity", "$11000.00"},
|
||||
{"Fitness Score", "0.504"},
|
||||
{"Kelly Criterion Estimate", "0"},
|
||||
{"Kelly Criterion Probability Value", "0"},
|
||||
|
||||
@@ -98,7 +98,7 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
{"Tracking Error", "0"},
|
||||
{"Treynor Ratio", "0"},
|
||||
{"Total Fees", "$5.93"},
|
||||
{"Estimated Strategy Capacity", "$200000.00"},
|
||||
{"Estimated Strategy Capacity", "$590000.00"},
|
||||
{"Fitness Score", "0.499"},
|
||||
{"Kelly Criterion Estimate", "0"},
|
||||
{"Kelly Criterion Probability Value", "0"},
|
||||
|
||||
@@ -105,7 +105,7 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
{"Tracking Error", "0.394"},
|
||||
{"Treynor Ratio", "-5.313"},
|
||||
{"Total Fees", "$5.40"},
|
||||
{"Estimated Strategy Capacity", "$59000000.00"},
|
||||
{"Estimated Strategy Capacity", "$230000000.00"},
|
||||
{"Fitness Score", "0.244"},
|
||||
{"Kelly Criterion Estimate", "0"},
|
||||
{"Kelly Criterion Probability Value", "0"},
|
||||
|
||||
@@ -118,7 +118,7 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
{"Tracking Error", "0.507"},
|
||||
{"Treynor Ratio", "0"},
|
||||
{"Total Fees", "$2651.01"},
|
||||
{"Estimated Strategy Capacity", "$9800.00"},
|
||||
{"Estimated Strategy Capacity", "$30000.00"},
|
||||
{"Fitness Score", "0.467"},
|
||||
{"Kelly Criterion Estimate", "0"},
|
||||
{"Kelly Criterion Probability Value", "0"},
|
||||
|
||||
@@ -99,7 +99,7 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
{"Tracking Error", "0.267"},
|
||||
{"Treynor Ratio", "-0.847"},
|
||||
{"Total Fees", "$41.17"},
|
||||
{"Estimated Strategy Capacity", "$98000000.00"},
|
||||
{"Estimated Strategy Capacity", "$340000000.00"},
|
||||
{"Fitness Score", "0"},
|
||||
{"Kelly Criterion Estimate", "38.884"},
|
||||
{"Kelly Criterion Probability Value", "0.009"},
|
||||
|
||||
@@ -138,7 +138,7 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
{"Tracking Error", "0.195"},
|
||||
{"Treynor Ratio", "55.977"},
|
||||
{"Total Fees", "$14.80"},
|
||||
{"Estimated Strategy Capacity", "$2100000.00"},
|
||||
{"Estimated Strategy Capacity", "$15000000.00"},
|
||||
{"Fitness Score", "0.018"},
|
||||
{"Kelly Criterion Estimate", "0"},
|
||||
{"Kelly Criterion Probability Value", "0"},
|
||||
|
||||
@@ -222,7 +222,7 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
{"Tracking Error", "0.191"},
|
||||
{"Treynor Ratio", "33.18"},
|
||||
{"Total Fees", "$7.40"},
|
||||
{"Estimated Strategy Capacity", "$1300000.00"},
|
||||
{"Estimated Strategy Capacity", "$9000000.00"},
|
||||
{"Fitness Score", "0.008"},
|
||||
{"Kelly Criterion Estimate", "0"},
|
||||
{"Kelly Criterion Probability Value", "0"},
|
||||
|
||||
@@ -180,7 +180,7 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
{"Tracking Error", "0.718"},
|
||||
{"Treynor Ratio", "18.473"},
|
||||
{"Total Fees", "$66.60"},
|
||||
{"Estimated Strategy Capacity", "$1200000.00"},
|
||||
{"Estimated Strategy Capacity", "$8300000.00"},
|
||||
{"Fitness Score", "0.162"},
|
||||
{"Kelly Criterion Estimate", "0"},
|
||||
{"Kelly Criterion Probability Value", "0"},
|
||||
|
||||
@@ -197,7 +197,7 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
{"Tracking Error", "0.182"},
|
||||
{"Treynor Ratio", "28.46"},
|
||||
{"Total Fees", "$3.70"},
|
||||
{"Estimated Strategy Capacity", "$830000.00"},
|
||||
{"Estimated Strategy Capacity", "$5800000.00"},
|
||||
{"Fitness Score", "0"},
|
||||
{"Kelly Criterion Estimate", "0"},
|
||||
{"Kelly Criterion Probability Value", "0"},
|
||||
|
||||
@@ -223,7 +223,7 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
{"Tracking Error", "0.183"},
|
||||
{"Treynor Ratio", "37.798"},
|
||||
{"Total Fees", "$7.40"},
|
||||
{"Estimated Strategy Capacity", "$1400000.00"},
|
||||
{"Estimated Strategy Capacity", "$9900000.00"},
|
||||
{"Fitness Score", "0.008"},
|
||||
{"Kelly Criterion Estimate", "0"},
|
||||
{"Kelly Criterion Probability Value", "0"},
|
||||
|
||||
@@ -196,7 +196,7 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
{"Tracking Error", "0.187"},
|
||||
{"Treynor Ratio", "28.078"},
|
||||
{"Total Fees", "$3.70"},
|
||||
{"Estimated Strategy Capacity", "$1200000.00"},
|
||||
{"Estimated Strategy Capacity", "$8700000.00"},
|
||||
{"Fitness Score", "0"},
|
||||
{"Kelly Criterion Estimate", "0"},
|
||||
{"Kelly Criterion Probability Value", "0"},
|
||||
|
||||
@@ -207,7 +207,7 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
{"Tracking Error", "0.183"},
|
||||
{"Treynor Ratio", "22.266"},
|
||||
{"Total Fees", "$7.40"},
|
||||
{"Estimated Strategy Capacity", "$1900000.00"},
|
||||
{"Estimated Strategy Capacity", "$13000000.00"},
|
||||
{"Fitness Score", "0.021"},
|
||||
{"Kelly Criterion Estimate", "0"},
|
||||
{"Kelly Criterion Probability Value", "0"},
|
||||
|
||||
@@ -190,7 +190,7 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
{"Tracking Error", "0.176"},
|
||||
{"Treynor Ratio", "27.339"},
|
||||
{"Total Fees", "$3.70"},
|
||||
{"Estimated Strategy Capacity", "$460000.00"},
|
||||
{"Estimated Strategy Capacity", "$3200000.00"},
|
||||
{"Fitness Score", "0"},
|
||||
{"Kelly Criterion Estimate", "0"},
|
||||
{"Kelly Criterion Probability Value", "0"},
|
||||
|
||||
@@ -204,7 +204,7 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
{"Tracking Error", "0.176"},
|
||||
{"Treynor Ratio", "14.729"},
|
||||
{"Total Fees", "$7.40"},
|
||||
{"Estimated Strategy Capacity", "$1900000.00"},
|
||||
{"Estimated Strategy Capacity", "$14000000.00"},
|
||||
{"Fitness Score", "0.022"},
|
||||
{"Kelly Criterion Estimate", "0"},
|
||||
{"Kelly Criterion Probability Value", "0"},
|
||||
|
||||
@@ -189,7 +189,7 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
{"Tracking Error", "0.179"},
|
||||
{"Treynor Ratio", "28.253"},
|
||||
{"Total Fees", "$3.70"},
|
||||
{"Estimated Strategy Capacity", "$770000.00"},
|
||||
{"Estimated Strategy Capacity", "$5400000.00"},
|
||||
{"Fitness Score", "0"},
|
||||
{"Kelly Criterion Estimate", "0"},
|
||||
{"Kelly Criterion Probability Value", "0"},
|
||||
|
||||
@@ -102,7 +102,7 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
{"Tracking Error", "0.332"},
|
||||
{"Treynor Ratio", "2.021"},
|
||||
{"Total Fees", "$1.85"},
|
||||
{"Estimated Strategy Capacity", "$47000000.00"},
|
||||
{"Estimated Strategy Capacity", "$93000000.00"},
|
||||
{"Fitness Score", "0.005"},
|
||||
{"Kelly Criterion Estimate", "0"},
|
||||
{"Kelly Criterion Probability Value", "0"},
|
||||
|
||||
@@ -173,7 +173,7 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
{"Tracking Error", "0.176"},
|
||||
{"Treynor Ratio", "29.128"},
|
||||
{"Total Fees", "$7.40"},
|
||||
{"Estimated Strategy Capacity", "$10000000.00"},
|
||||
{"Estimated Strategy Capacity", "$71000000.00"},
|
||||
{"Fitness Score", "0.007"},
|
||||
{"Kelly Criterion Estimate", "0"},
|
||||
{"Kelly Criterion Probability Value", "0"},
|
||||
|
||||
@@ -92,7 +92,7 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnEndOfDay()
|
||||
public override void OnEndOfDay(Symbol symbol)
|
||||
{
|
||||
Plot("Indicator Signal", "EOD", IsDownTrend ? -1 : IsUpTrend ? 1 : 0);
|
||||
}
|
||||
|
||||
@@ -41,7 +41,9 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
// Without this, consuming projects would need to hard reference the Accord dlls,
|
||||
// which is less than perfect. This seems to be the better of two evils
|
||||
//
|
||||
#pragma warning disable 0414
|
||||
Accord.Math.Matrix3x3 _matrix = new Accord.Math.Matrix3x3();
|
||||
#pragma warning restore 0414
|
||||
|
||||
//Fuzzy Engine
|
||||
private FuzzyEngine _engine;
|
||||
|
||||
@@ -317,7 +317,7 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
{"Tracking Error", "0.264"},
|
||||
{"Treynor Ratio", "26.924"},
|
||||
{"Total Fees", "$3.26"},
|
||||
{"Estimated Strategy Capacity", "$300000000.00"},
|
||||
{"Estimated Strategy Capacity", "$890000000.00"},
|
||||
{"Fitness Score", "0.251"},
|
||||
{"Kelly Criterion Estimate", "0"},
|
||||
{"Kelly Criterion Probability Value", "0"},
|
||||
|
||||
@@ -106,7 +106,7 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
{"Tracking Error", "0.866"},
|
||||
{"Treynor Ratio", "-0.286"},
|
||||
{"Total Fees", "$5.40"},
|
||||
{"Estimated Strategy Capacity", "$350000.00"},
|
||||
{"Estimated Strategy Capacity", "$2400000.00"},
|
||||
{"Fitness Score", "0.008"},
|
||||
{"Kelly Criterion Estimate", "0"},
|
||||
{"Kelly Criterion Probability Value", "0"},
|
||||
|
||||
@@ -128,7 +128,7 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
{"Tracking Error", "0"},
|
||||
{"Treynor Ratio", "0"},
|
||||
{"Total Fees", "$1.00"},
|
||||
{"Estimated Strategy Capacity", "$12000000000.00"},
|
||||
{"Estimated Strategy Capacity", "$36000000000.00"},
|
||||
{"Fitness Score", "0"},
|
||||
{"Kelly Criterion Estimate", "0"},
|
||||
{"Kelly Criterion Probability Value", "0"},
|
||||
|
||||
@@ -116,7 +116,7 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
{"Tracking Error", "0.073"},
|
||||
{"Treynor Ratio", "0.573"},
|
||||
{"Total Fees", "$14.75"},
|
||||
{"Estimated Strategy Capacity", "$1300000.00"},
|
||||
{"Estimated Strategy Capacity", "$6300000.00"},
|
||||
{"Fitness Score", "0.2"},
|
||||
{"Kelly Criterion Estimate", "0"},
|
||||
{"Kelly Criterion Probability Value", "0"},
|
||||
|
||||
@@ -0,0 +1,167 @@
|
||||
/*
|
||||
* 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 System.Reflection;
|
||||
using QuantConnect.Interfaces;
|
||||
using QuantConnect.Securities;
|
||||
|
||||
namespace QuantConnect.Algorithm.CSharp
|
||||
{
|
||||
/// <summary>
|
||||
/// This regression algorithm tests In The Money (ITM) index option calls across different strike prices.
|
||||
/// We expect 4* orders from the algorithm, which are:
|
||||
///
|
||||
/// * (1) Initial entry, buy SPX Call Option (SPXF21 expiring ITM)
|
||||
/// * (2) Initial entry, sell SPX Call Option at different strike (SPXF21 expiring ITM)
|
||||
/// * [2] Option assignment, settle into cash
|
||||
/// * [1] Option exercise, settle into cash
|
||||
///
|
||||
/// Additionally, we test delistings for index options and assert that our
|
||||
/// portfolio holdings reflect the orders the algorithm has submitted.
|
||||
///
|
||||
/// * Assignments are counted as orders
|
||||
/// </summary>
|
||||
public class IndexOptionBuySellCallIntradayRegressionAlgorithm : QCAlgorithm, IRegressionAlgorithmDefinition
|
||||
{
|
||||
public override void Initialize()
|
||||
{
|
||||
SetStartDate(2021, 1, 4);
|
||||
SetEndDate(2021, 1, 31);
|
||||
|
||||
var spx = AddIndex("SPX", Resolution.Minute).Symbol;
|
||||
|
||||
// Select a index option expiring ITM, and adds it to the algorithm.
|
||||
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)
|
||||
.ToList();
|
||||
|
||||
var expectedContract3700 = QuantConnect.Symbol.CreateOption(
|
||||
spx,
|
||||
Market.USA,
|
||||
OptionStyle.European,
|
||||
OptionRight.Call,
|
||||
3700m,
|
||||
new DateTime(2021, 1, 15));
|
||||
|
||||
var expectedContract3800 = QuantConnect.Symbol.CreateOption(
|
||||
spx,
|
||||
Market.USA,
|
||||
OptionStyle.European,
|
||||
OptionRight.Call,
|
||||
3800m,
|
||||
new DateTime(2021, 1, 15));
|
||||
|
||||
if (spxOptions.Count != 2)
|
||||
{
|
||||
throw new Exception($"Expected 2 index options symbols from chain provider, found {spxOptions.Count}");
|
||||
}
|
||||
|
||||
if (spxOptions[0] != expectedContract3700)
|
||||
{
|
||||
throw new Exception($"Contract {expectedContract3700} was not found in the chain, found instead: {spxOptions[0]}");
|
||||
}
|
||||
if (spxOptions[1] != expectedContract3800)
|
||||
{
|
||||
throw new Exception($"Contract {expectedContract3800} was not found in the chain, found instead: {spxOptions[1]}");
|
||||
}
|
||||
|
||||
Schedule.On(DateRules.Tomorrow, TimeRules.AfterMarketOpen(spx, 1), () =>
|
||||
{
|
||||
MarketOrder(spxOptions[0], 1);
|
||||
MarketOrder(spxOptions[1], -1);
|
||||
});
|
||||
Schedule.On(DateRules.Tomorrow, TimeRules.Noon, () =>
|
||||
{
|
||||
Liquidate();
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ran at the end of the algorithm to ensure the algorithm has no holdings
|
||||
/// </summary>
|
||||
/// <exception cref="Exception">The algorithm has holdings</exception>
|
||||
public override void OnEndOfAlgorithm()
|
||||
{
|
||||
if (Portfolio.Invested)
|
||||
{
|
||||
throw new Exception($"Expected no holdings at end of algorithm, but are invested in: {string.Join(", ", Portfolio.Keys)}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This is used by the regression test system to indicate if the open source Lean repository has the required data to run this algorithm.
|
||||
/// </summary>
|
||||
public bool CanRunLocally { get; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// This is used by the regression test system to indicate which languages this algorithm is written in.
|
||||
/// </summary>
|
||||
public Language[] Languages { get; } = { Language.CSharp, Language.Python };
|
||||
|
||||
/// <summary>
|
||||
/// This is used by the regression test system to indicate what the expected statistics are from running the algorithm
|
||||
/// </summary>
|
||||
public Dictionary<string, string> ExpectedStatistics => new Dictionary<string, string>
|
||||
{
|
||||
{"Total Trades", "4"},
|
||||
{"Average Win", "0%"},
|
||||
{"Average Loss", "-0.06%"},
|
||||
{"Compounding Annual Return", "-1.552%"},
|
||||
{"Drawdown", "0.100%"},
|
||||
{"Expectancy", "-1"},
|
||||
{"Net Profit", "-0.110%"},
|
||||
{"Sharpe Ratio", "-3.525"},
|
||||
{"Probabilistic Sharpe Ratio", "0.518%"},
|
||||
{"Loss Rate", "100%"},
|
||||
{"Win Rate", "0%"},
|
||||
{"Profit-Loss Ratio", "0"},
|
||||
{"Alpha", "0"},
|
||||
{"Beta", "0"},
|
||||
{"Annual Standard Deviation", "0.004"},
|
||||
{"Annual Variance", "0"},
|
||||
{"Information Ratio", "-3.525"},
|
||||
{"Tracking Error", "0.004"},
|
||||
{"Treynor Ratio", "0"},
|
||||
{"Total Fees", "$0.00"},
|
||||
{"Estimated Strategy Capacity", "$0"},
|
||||
{"Fitness Score", "0"},
|
||||
{"Kelly Criterion Estimate", "0"},
|
||||
{"Kelly Criterion Probability Value", "0"},
|
||||
{"Sortino Ratio", "-4619.237"},
|
||||
{"Return Over Maximum Drawdown", "-14.266"},
|
||||
{"Portfolio Turnover", "0.005"},
|
||||
{"Total Insights Generated", "0"},
|
||||
{"Total Insights Closed", "0"},
|
||||
{"Total Insights Analysis Completed", "0"},
|
||||
{"Long Insight Count", "0"},
|
||||
{"Short Insight Count", "0"},
|
||||
{"Long/Short Ratio", "100%"},
|
||||
{"Estimated Monthly Alpha Value", "$0"},
|
||||
{"Total Accumulated Estimated Alpha Value", "$0"},
|
||||
{"Mean Population Estimated Insight Value", "$0"},
|
||||
{"Mean Population Direction", "0%"},
|
||||
{"Mean Population Magnitude", "0%"},
|
||||
{"Rolling Averaged Population Direction", "0%"},
|
||||
{"Rolling Averaged Population Magnitude", "0%"},
|
||||
{"OrderListHash", "7d15f56731d38768ea81afac627f0657"}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
229
Algorithm.CSharp/IndexOptionCallITMExpiryRegressionAlgorithm.cs
Normal file
229
Algorithm.CSharp/IndexOptionCallITMExpiryRegressionAlgorithm.cs
Normal file
@@ -0,0 +1,229 @@
|
||||
/*
|
||||
* 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.Orders;
|
||||
using QuantConnect.Securities;
|
||||
|
||||
namespace QuantConnect.Algorithm.CSharp
|
||||
{
|
||||
/// <summary>
|
||||
/// This regression algorithm tests In The Money (ITM) index option expiry for calls.
|
||||
/// We expect 2 orders from the algorithm, which are:
|
||||
///
|
||||
/// * Initial entry, buy SPX Call Option (expiring ITM)
|
||||
/// * Option exercise, settles into cash
|
||||
///
|
||||
/// Additionally, we test delistings for index options and assert that our
|
||||
/// portfolio holdings reflect the orders the algorithm has submitted.
|
||||
/// </summary>
|
||||
public class IndexOptionCallITMExpiryRegressionAlgorithm : QCAlgorithm, IRegressionAlgorithmDefinition
|
||||
{
|
||||
private Symbol _spx;
|
||||
private Symbol _spxOption;
|
||||
private Symbol _expectedOptionContract;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
SetStartDate(2021, 1, 4);
|
||||
SetEndDate(2021, 1, 31);
|
||||
SetCash(100000);
|
||||
|
||||
_spx = AddIndex("SPX", Resolution.Minute).Symbol;
|
||||
|
||||
// Select an index option expiring ITM, and adds it to the algorithm.
|
||||
_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)
|
||||
.Single(), Resolution.Minute).Symbol;
|
||||
|
||||
_expectedOptionContract = QuantConnect.Symbol.CreateOption(_spx, Market.USA, OptionStyle.European, OptionRight.Call, 3200m, new DateTime(2021, 1, 15));
|
||||
if (_spxOption != _expectedOptionContract)
|
||||
{
|
||||
throw new Exception($"Contract {_expectedOptionContract} was not found in the chain");
|
||||
}
|
||||
|
||||
Schedule.On(DateRules.Tomorrow, TimeRules.AfterMarketOpen(_spx, 1), () =>
|
||||
{
|
||||
MarketOrder(_spxOption, 1);
|
||||
});
|
||||
}
|
||||
|
||||
public override void OnData(Slice data)
|
||||
{
|
||||
// Assert delistings, so that we can make sure that we receive the delisting warnings at
|
||||
// the expected time. These assertions detect bug #4872
|
||||
foreach (var delisting in data.Delistings.Values)
|
||||
{
|
||||
if (delisting.Type == DelistingType.Warning)
|
||||
{
|
||||
if (delisting.Time != new DateTime(2021, 1, 15))
|
||||
{
|
||||
throw new Exception($"Delisting warning issued at unexpected date: {delisting.Time}");
|
||||
}
|
||||
}
|
||||
if (delisting.Type == DelistingType.Delisted)
|
||||
{
|
||||
if (delisting.Time != new DateTime(2021, 1, 16))
|
||||
{
|
||||
throw new Exception($"Delisting happened at unexpected date: {delisting.Time}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnOrderEvent(OrderEvent orderEvent)
|
||||
{
|
||||
if (orderEvent.Status != OrderStatus.Filled)
|
||||
{
|
||||
// There's lots of noise with OnOrderEvent, but we're only interested in fills.
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Securities.ContainsKey(orderEvent.Symbol))
|
||||
{
|
||||
throw new Exception($"Order event Symbol not found in Securities collection: {orderEvent.Symbol}");
|
||||
}
|
||||
|
||||
var security = Securities[orderEvent.Symbol];
|
||||
if (security.Symbol == _spx)
|
||||
{
|
||||
AssertIndexOptionOrderExercise(orderEvent, security, Securities[_expectedOptionContract]);
|
||||
}
|
||||
else if (security.Symbol == _expectedOptionContract)
|
||||
{
|
||||
AssertIndexOptionContractOrder(orderEvent, security);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception($"Received order event for unknown Symbol: {orderEvent.Symbol}");
|
||||
}
|
||||
|
||||
Log($"{Time:yyyy-MM-dd HH:mm:ss} -- {orderEvent.Symbol} :: Price: {Securities[orderEvent.Symbol].Holdings.Price} Qty: {Securities[orderEvent.Symbol].Holdings.Quantity} Direction: {orderEvent.Direction} Msg: {orderEvent.Message}");
|
||||
}
|
||||
|
||||
private void AssertIndexOptionOrderExercise(OrderEvent orderEvent, Security index, Security optionContract)
|
||||
{
|
||||
var expectedLiquidationTimeUtc = new DateTime(2021, 1, 16, 3, 0, 0);
|
||||
|
||||
// No way to detect option exercise orders or any other kind of special orders
|
||||
// other than matching strings, for now.
|
||||
if (orderEvent.Message.Contains("Option Exercise"))
|
||||
{
|
||||
if (orderEvent.FillPrice != 3200m)
|
||||
{
|
||||
throw new Exception("Option did not exercise at expected strike price (3200)");
|
||||
}
|
||||
|
||||
if (optionContract.Holdings.Quantity != 0)
|
||||
{
|
||||
throw new Exception($"Exercised option contract, but we have holdings for Option contract {optionContract.Symbol}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void AssertIndexOptionContractOrder(OrderEvent orderEvent, Security option)
|
||||
{
|
||||
if (orderEvent.Direction == OrderDirection.Buy && option.Holdings.Quantity != 1)
|
||||
{
|
||||
throw new Exception($"No holdings were created for option contract {option.Symbol}");
|
||||
}
|
||||
if (orderEvent.Direction == OrderDirection.Sell && option.Holdings.Quantity != 0)
|
||||
{
|
||||
throw new Exception($"Holdings were found after a filled option exercise");
|
||||
}
|
||||
if (orderEvent.Message.Contains("Exercise") && option.Holdings.Quantity != 0)
|
||||
{
|
||||
throw new Exception($"Holdings were found after exercising option contract {option.Symbol}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ran at the end of the algorithm to ensure the algorithm has no holdings
|
||||
/// </summary>
|
||||
/// <exception cref="Exception">The algorithm has holdings</exception>
|
||||
public override void OnEndOfAlgorithm()
|
||||
{
|
||||
if (Portfolio.Invested)
|
||||
{
|
||||
throw new Exception($"Expected no holdings at end of algorithm, but are invested in: {string.Join(", ", Portfolio.Keys)}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This is used by the regression test system to indicate if the open source Lean repository has the required data to run this algorithm.
|
||||
/// </summary>
|
||||
public bool CanRunLocally { get; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// This is used by the regression test system to indicate which languages this algorithm is written in.
|
||||
/// </summary>
|
||||
public Language[] Languages { get; } = { Language.CSharp, Language.Python };
|
||||
|
||||
/// <summary>
|
||||
/// This is used by the regression test system to indicate what the expected statistics are from running the algorithm
|
||||
/// </summary>
|
||||
public Dictionary<string, string> ExpectedStatistics => new Dictionary<string, string>
|
||||
{
|
||||
{"Total Trades", "2"},
|
||||
{"Average Win", "0%"},
|
||||
{"Average Loss", "-49.28%"},
|
||||
{"Compounding Annual Return", "301.490%"},
|
||||
{"Drawdown", "2.300%"},
|
||||
{"Expectancy", "-1"},
|
||||
{"Net Profit", "10.274%"},
|
||||
{"Sharpe Ratio", "6.904"},
|
||||
{"Probabilistic Sharpe Ratio", "89.741%"},
|
||||
{"Loss Rate", "100%"},
|
||||
{"Win Rate", "0%"},
|
||||
{"Profit-Loss Ratio", "0"},
|
||||
{"Alpha", "0"},
|
||||
{"Beta", "0"},
|
||||
{"Annual Standard Deviation", "0.386"},
|
||||
{"Annual Variance", "0.149"},
|
||||
{"Information Ratio", "6.904"},
|
||||
{"Tracking Error", "0.386"},
|
||||
{"Treynor Ratio", "0"},
|
||||
{"Total Fees", "$0.00"},
|
||||
{"Estimated Strategy Capacity", "$0"},
|
||||
{"Fitness Score", "0.024"},
|
||||
{"Kelly Criterion Estimate", "0"},
|
||||
{"Kelly Criterion Probability Value", "0"},
|
||||
{"Sortino Ratio", "649.537"},
|
||||
{"Return Over Maximum Drawdown", "1130.655"},
|
||||
{"Portfolio Turnover", "0.024"},
|
||||
{"Total Insights Generated", "0"},
|
||||
{"Total Insights Closed", "0"},
|
||||
{"Total Insights Analysis Completed", "0"},
|
||||
{"Long Insight Count", "0"},
|
||||
{"Short Insight Count", "0"},
|
||||
{"Long/Short Ratio", "100%"},
|
||||
{"Estimated Monthly Alpha Value", "$0"},
|
||||
{"Total Accumulated Estimated Alpha Value", "$0"},
|
||||
{"Mean Population Estimated Insight Value", "$0"},
|
||||
{"Mean Population Direction", "0%"},
|
||||
{"Mean Population Magnitude", "0%"},
|
||||
{"Rolling Averaged Population Direction", "0%"},
|
||||
{"Rolling Averaged Population Magnitude", "0%"},
|
||||
{"OrderListHash", "6dda4f153b0be9fdf55026da439f90f6"}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,202 @@
|
||||
/*
|
||||
* 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 System.Reflection;
|
||||
using QuantConnect.Data;
|
||||
using QuantConnect.Interfaces;
|
||||
using QuantConnect.Orders;
|
||||
using QuantConnect.Securities;
|
||||
using QuantConnect.Securities.Option;
|
||||
|
||||
namespace QuantConnect.Algorithm.CSharp
|
||||
{
|
||||
/// <summary>
|
||||
/// This regression algorithm tests In The Money (ITM) index option expiry for calls.
|
||||
/// We test to make sure that index options have greeks enabled, same as equity options.
|
||||
/// </summary>
|
||||
public class IndexOptionCallITMGreeksExpiryRegressionAlgorithm : QCAlgorithm, IRegressionAlgorithmDefinition
|
||||
{
|
||||
private bool _invested;
|
||||
private int _onDataCalls;
|
||||
private Symbol _spx;
|
||||
private Option _spxOption;
|
||||
private Symbol _expectedOptionContract;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
SetStartDate(2021, 1, 4);
|
||||
SetEndDate(2021, 1, 31);
|
||||
|
||||
_spx = AddIndex("SPX", Resolution.Minute).Symbol;
|
||||
|
||||
// Select an index option expiring ITM, and adds it to the algorithm.
|
||||
_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)
|
||||
.Single(), Resolution.Minute);
|
||||
|
||||
_spxOption.PriceModel = OptionPriceModels.BlackScholes();
|
||||
|
||||
_expectedOptionContract = QuantConnect.Symbol.CreateOption(_spx, Market.USA, OptionStyle.European, OptionRight.Call, 3200m, new DateTime(2021, 1, 15));
|
||||
if (_spxOption.Symbol != _expectedOptionContract)
|
||||
{
|
||||
throw new Exception($"Contract {_expectedOptionContract} was not found in the chain");
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnData(Slice data)
|
||||
{
|
||||
// Let the algo warmup, but without using SetWarmup. Otherwise, we get
|
||||
// no contracts in the option chain
|
||||
if (_invested || _onDataCalls++ < 40)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (data.OptionChains.Count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (data.OptionChains.Values.All(o => o.Contracts.Values.Any(c => !data.ContainsKey(c.Symbol))))
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (data.OptionChains.Values.First().Contracts.Count == 0)
|
||||
{
|
||||
throw new Exception($"No contracts found in the option {data.OptionChains.Keys.First()}");
|
||||
}
|
||||
|
||||
var deltas = data.OptionChains.Values.OrderByDescending(y => y.Contracts.Values.Sum(x => x.Volume)).First().Contracts.Values.Select(x => x.Greeks.Delta).ToList();
|
||||
var gammas = data.OptionChains.Values.OrderByDescending(y => y.Contracts.Values.Sum(x => x.Volume)).First().Contracts.Values.Select(x => x.Greeks.Gamma).ToList();
|
||||
var lambda = data.OptionChains.Values.OrderByDescending(y => y.Contracts.Values.Sum(x => x.Volume)).First().Contracts.Values.Select(x => x.Greeks.Lambda).ToList();
|
||||
var rho = data.OptionChains.Values.OrderByDescending(y => y.Contracts.Values.Sum(x => x.Volume)).First().Contracts.Values.Select(x => x.Greeks.Rho).ToList();
|
||||
var theta = data.OptionChains.Values.OrderByDescending(y => y.Contracts.Values.Sum(x => x.Volume)).First().Contracts.Values.Select(x => x.Greeks.Theta).ToList();
|
||||
var vega = data.OptionChains.Values.OrderByDescending(y => y.Contracts.Values.Sum(x => x.Volume)).First().Contracts.Values.Select(x => x.Greeks.Vega).ToList();
|
||||
|
||||
// The commented out test cases all return zero.
|
||||
// This is because of failure to evaluate the greeks in the option pricing model, most likely
|
||||
// due to us not clearing the default 30 day requirement for the volatility model to start being updated.
|
||||
if (deltas.Any(d => d == 0))
|
||||
{
|
||||
throw new AggregateException("Option contract Delta was equal to zero");
|
||||
}
|
||||
//if (gammas.Any(g => g == 0))
|
||||
//{
|
||||
// throw new AggregateException("Option contract Gamma was equal to zero");
|
||||
//}
|
||||
//if (lambda.Any(l => l == 0))
|
||||
//{
|
||||
// throw new AggregateException("Option contract Lambda was equal to zero");
|
||||
//}
|
||||
if (rho.Any(r => r == 0))
|
||||
{
|
||||
throw new AggregateException("Option contract Rho was equal to zero");
|
||||
}
|
||||
if (theta.Any(t => t == 0))
|
||||
{
|
||||
throw new AggregateException("Option contract Theta was equal to zero");
|
||||
}
|
||||
//if (vega.Any(v => v == 0))
|
||||
//{
|
||||
// throw new AggregateException("Option contract Vega was equal to zero");
|
||||
//}
|
||||
|
||||
if (!_invested)
|
||||
{
|
||||
SetHoldings(data.OptionChains.Values.First().Contracts.Values.First().Symbol, 1);
|
||||
_invested = true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ran at the end of the algorithm to ensure the algorithm has no holdings
|
||||
/// </summary>
|
||||
/// <exception cref="Exception">The algorithm has holdings</exception>
|
||||
public override void OnEndOfAlgorithm()
|
||||
{
|
||||
if (Portfolio.Invested)
|
||||
{
|
||||
throw new Exception($"Expected no holdings at end of algorithm, but are invested in: {string.Join(", ", Portfolio.Keys)}");
|
||||
}
|
||||
if (!_invested)
|
||||
{
|
||||
throw new Exception($"Never checked greeks, maybe we have no option data?");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This is used by the regression test system to indicate if the open source Lean repository has the required data to run this algorithm.
|
||||
/// </summary>
|
||||
public bool CanRunLocally { get; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// This is used by the regression test system to indicate which languages this algorithm is written in.
|
||||
/// </summary>
|
||||
public Language[] Languages { get; } = { Language.CSharp, Language.Python };
|
||||
|
||||
/// <summary>
|
||||
/// This is used by the regression test system to indicate what the expected statistics are from running the algorithm
|
||||
/// </summary>
|
||||
public Dictionary<string, string> ExpectedStatistics => new Dictionary<string, string>
|
||||
{
|
||||
{"Total Trades", "2"},
|
||||
{"Average Win", "0%"},
|
||||
{"Average Loss", "-56.91%"},
|
||||
{"Compounding Annual Return", "44.906%"},
|
||||
{"Drawdown", "9.800%"},
|
||||
{"Expectancy", "-1"},
|
||||
{"Net Profit", "2.644%"},
|
||||
{"Sharpe Ratio", "7.691"},
|
||||
{"Probabilistic Sharpe Ratio", "91.027%"},
|
||||
{"Loss Rate", "100%"},
|
||||
{"Win Rate", "0%"},
|
||||
{"Profit-Loss Ratio", "0"},
|
||||
{"Alpha", "0"},
|
||||
{"Beta", "0"},
|
||||
{"Annual Standard Deviation", "0.417"},
|
||||
{"Annual Variance", "0.174"},
|
||||
{"Information Ratio", "7.691"},
|
||||
{"Tracking Error", "0.417"},
|
||||
{"Treynor Ratio", "0"},
|
||||
{"Total Fees", "$0.00"},
|
||||
{"Estimated Strategy Capacity", "$46000000.00"},
|
||||
{"Fitness Score", "0.023"},
|
||||
{"Kelly Criterion Estimate", "0"},
|
||||
{"Kelly Criterion Probability Value", "0"},
|
||||
{"Sortino Ratio", "0.535"},
|
||||
{"Return Over Maximum Drawdown", "5.789"},
|
||||
{"Portfolio Turnover", "0.03"},
|
||||
{"Total Insights Generated", "0"},
|
||||
{"Total Insights Closed", "0"},
|
||||
{"Total Insights Analysis Completed", "0"},
|
||||
{"Long Insight Count", "0"},
|
||||
{"Short Insight Count", "0"},
|
||||
{"Long/Short Ratio", "100%"},
|
||||
{"Estimated Monthly Alpha Value", "$0"},
|
||||
{"Total Accumulated Estimated Alpha Value", "$0"},
|
||||
{"Mean Population Estimated Insight Value", "$0"},
|
||||
{"Mean Population Direction", "0%"},
|
||||
{"Mean Population Magnitude", "0%"},
|
||||
{"Rolling Averaged Population Direction", "0%"},
|
||||
{"Rolling Averaged Population Magnitude", "0%"},
|
||||
{"OrderListHash", "3cccf8c2409ee8a9020ba79a6c45742a"}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
219
Algorithm.CSharp/IndexOptionCallOTMExpiryRegressionAlgorithm.cs
Normal file
219
Algorithm.CSharp/IndexOptionCallOTMExpiryRegressionAlgorithm.cs
Normal file
@@ -0,0 +1,219 @@
|
||||
/*
|
||||
* 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 System.Reflection;
|
||||
using QuantConnect.Data;
|
||||
using QuantConnect.Interfaces;
|
||||
using QuantConnect.Orders;
|
||||
using QuantConnect.Securities;
|
||||
|
||||
namespace QuantConnect.Algorithm.CSharp
|
||||
{
|
||||
/// <summary>
|
||||
/// This regression algorithm tests Out of The Money (OTM) index option expiry for calls.
|
||||
/// We expect 2 orders from the algorithm, which are:
|
||||
///
|
||||
/// * Initial entry, buy SPX Call Option (expiring OTM)
|
||||
/// - contract expires worthless, not exercised, so never opened a position in the underlying
|
||||
///
|
||||
/// * Liquidation of worthless SPX call option (expiring OTM)
|
||||
///
|
||||
/// Additionally, we test delistings for index options and assert that our
|
||||
/// portfolio holdings reflect the orders the algorithm has submitted.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Total Trades in regression algorithm should be 1, but expiration is counted as a trade.
|
||||
/// See related issue: https://github.com/QuantConnect/Lean/issues/4854
|
||||
/// </remarks>
|
||||
public class IndexOptionCallOTMExpiryRegressionAlgorithm : QCAlgorithm, IRegressionAlgorithmDefinition
|
||||
{
|
||||
private Symbol _spx;
|
||||
private Symbol _spxOption;
|
||||
private Symbol _expectedContract;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
SetStartDate(2021, 1, 4);
|
||||
SetEndDate(2021, 1, 31);
|
||||
|
||||
_spx = AddIndex("SPX", Resolution.Minute).Symbol;
|
||||
|
||||
// Select a index option call expiring OTM, and adds it to the algorithm.
|
||||
_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)
|
||||
.Single(), Resolution.Minute).Symbol;
|
||||
|
||||
_expectedContract = QuantConnect.Symbol.CreateOption(_spx, Market.USA, OptionStyle.European, OptionRight.Call, 4250m, new DateTime(2021, 1, 15));
|
||||
if (_spxOption != _expectedContract)
|
||||
{
|
||||
throw new Exception($"Contract {_expectedContract} was not found in the chain");
|
||||
}
|
||||
|
||||
Schedule.On(DateRules.Tomorrow, TimeRules.AfterMarketOpen(_spx, 1), () =>
|
||||
{
|
||||
MarketOrder(_spxOption, 1);
|
||||
});
|
||||
}
|
||||
|
||||
public override void OnData(Slice data)
|
||||
{
|
||||
// Assert delistings, so that we can make sure that we receive the delisting warnings at
|
||||
// the expected time. These assertions detect bug #4872
|
||||
foreach (var delisting in data.Delistings.Values)
|
||||
{
|
||||
if (delisting.Type == DelistingType.Warning)
|
||||
{
|
||||
if (delisting.Time != new DateTime(2021, 1, 15))
|
||||
{
|
||||
throw new Exception($"Delisting warning issued at unexpected date: {delisting.Time}");
|
||||
}
|
||||
}
|
||||
if (delisting.Type == DelistingType.Delisted)
|
||||
{
|
||||
if (delisting.Time != new DateTime(2021, 1, 16))
|
||||
{
|
||||
throw new Exception($"Delisting happened at unexpected date: {delisting.Time}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnOrderEvent(OrderEvent orderEvent)
|
||||
{
|
||||
if (orderEvent.Status != OrderStatus.Filled)
|
||||
{
|
||||
// There's lots of noise with OnOrderEvent, but we're only interested in fills.
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Securities.ContainsKey(orderEvent.Symbol))
|
||||
{
|
||||
throw new Exception($"Order event Symbol not found in Securities collection: {orderEvent.Symbol}");
|
||||
}
|
||||
|
||||
var security = Securities[orderEvent.Symbol];
|
||||
if (security.Symbol == _spx)
|
||||
{
|
||||
throw new Exception("Invalid state: did not expect a position for the underlying to be opened, since this contract expires OTM");
|
||||
}
|
||||
if (security.Symbol == _expectedContract)
|
||||
{
|
||||
AssertIndexOptionContractOrder(orderEvent, security);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception($"Received order event for unknown Symbol: {orderEvent.Symbol}");
|
||||
}
|
||||
|
||||
Log($"{orderEvent}");
|
||||
}
|
||||
|
||||
private void AssertIndexOptionContractOrder(OrderEvent orderEvent, Security option)
|
||||
{
|
||||
if (orderEvent.Direction == OrderDirection.Buy && option.Holdings.Quantity != 1)
|
||||
{
|
||||
throw new Exception($"No holdings were created for option contract {option.Symbol}");
|
||||
}
|
||||
if (orderEvent.Direction == OrderDirection.Sell && option.Holdings.Quantity != 0)
|
||||
{
|
||||
throw new Exception("Holdings were found after a filled option exercise");
|
||||
}
|
||||
if (orderEvent.Direction == OrderDirection.Sell && !orderEvent.Message.Contains("OTM"))
|
||||
{
|
||||
throw new Exception("Contract did not expire OTM");
|
||||
}
|
||||
if (orderEvent.Message.Contains("Exercise"))
|
||||
{
|
||||
throw new Exception("Exercised option, even though it expires OTM");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ran at the end of the algorithm to ensure the algorithm has no holdings
|
||||
/// </summary>
|
||||
/// <exception cref="Exception">The algorithm has holdings</exception>
|
||||
public override void OnEndOfAlgorithm()
|
||||
{
|
||||
if (Portfolio.Invested)
|
||||
{
|
||||
throw new Exception($"Expected no holdings at end of algorithm, but are invested in: {string.Join(", ", Portfolio.Keys)}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This is used by the regression test system to indicate if the open source Lean repository has the required data to run this algorithm.
|
||||
/// </summary>
|
||||
public bool CanRunLocally { get; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// This is used by the regression test system to indicate which languages this algorithm is written in.
|
||||
/// </summary>
|
||||
public Language[] Languages { get; } = { Language.CSharp, Language.Python };
|
||||
|
||||
/// <summary>
|
||||
/// This is used by the regression test system to indicate what the expected statistics are from running the algorithm
|
||||
/// </summary>
|
||||
public Dictionary<string, string> ExpectedStatistics => new Dictionary<string, string>
|
||||
{
|
||||
{"Total Trades", "2"},
|
||||
{"Average Win", "0%"},
|
||||
{"Average Loss", "-0.01%"},
|
||||
{"Compounding Annual Return", "-0.142%"},
|
||||
{"Drawdown", "0.000%"},
|
||||
{"Expectancy", "-1"},
|
||||
{"Net Profit", "-0.010%"},
|
||||
{"Sharpe Ratio", "-5.154"},
|
||||
{"Probabilistic Sharpe Ratio", "0.016%"},
|
||||
{"Loss Rate", "100%"},
|
||||
{"Win Rate", "0%"},
|
||||
{"Profit-Loss Ratio", "0"},
|
||||
{"Alpha", "0"},
|
||||
{"Beta", "0"},
|
||||
{"Annual Standard Deviation", "0"},
|
||||
{"Annual Variance", "0"},
|
||||
{"Information Ratio", "-5.154"},
|
||||
{"Tracking Error", "0"},
|
||||
{"Treynor Ratio", "0"},
|
||||
{"Total Fees", "$0.00"},
|
||||
{"Estimated Strategy Capacity", "$23000.00"},
|
||||
{"Fitness Score", "0"},
|
||||
{"Kelly Criterion Estimate", "0"},
|
||||
{"Kelly Criterion Probability Value", "0"},
|
||||
{"Sortino Ratio", "-51177.748"},
|
||||
{"Return Over Maximum Drawdown", "-14.362"},
|
||||
{"Portfolio Turnover", "0"},
|
||||
{"Total Insights Generated", "0"},
|
||||
{"Total Insights Closed", "0"},
|
||||
{"Total Insights Analysis Completed", "0"},
|
||||
{"Long Insight Count", "0"},
|
||||
{"Short Insight Count", "0"},
|
||||
{"Long/Short Ratio", "100%"},
|
||||
{"Estimated Monthly Alpha Value", "$0"},
|
||||
{"Total Accumulated Estimated Alpha Value", "$0"},
|
||||
{"Mean Population Estimated Insight Value", "$0"},
|
||||
{"Mean Population Direction", "0%"},
|
||||
{"Mean Population Magnitude", "0%"},
|
||||
{"Rolling Averaged Population Direction", "0%"},
|
||||
{"Rolling Averaged Population Magnitude", "0%"},
|
||||
{"OrderListHash", "177477b78d9264384a09f1607e8c7d11"}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
234
Algorithm.CSharp/IndexOptionPutITMExpiryRegressionAlgorithm.cs
Normal file
234
Algorithm.CSharp/IndexOptionPutITMExpiryRegressionAlgorithm.cs
Normal file
@@ -0,0 +1,234 @@
|
||||
/*
|
||||
* 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 System.Reflection;
|
||||
using QuantConnect.Data;
|
||||
using QuantConnect.Interfaces;
|
||||
using QuantConnect.Orders;
|
||||
using QuantConnect.Securities;
|
||||
|
||||
namespace QuantConnect.Algorithm.CSharp
|
||||
{
|
||||
/// <summary>
|
||||
/// This regression algorithm tests In The Money (ITM) index option expiry for puts.
|
||||
/// We expect 2 orders from the algorithm, which are:
|
||||
///
|
||||
/// * Initial entry, buy ES Put Option (expiring ITM) (buy, qty 1)
|
||||
/// * Option exercise, receiving cash (sell, qty -1)
|
||||
///
|
||||
/// Additionally, we test delistings for index options and assert that our
|
||||
/// portfolio holdings reflect the orders the algorithm has submitted.
|
||||
/// </summary>
|
||||
public class IndexOptionPutITMExpiryRegressionAlgorithm : QCAlgorithm, IRegressionAlgorithmDefinition
|
||||
{
|
||||
private Symbol _spx;
|
||||
private Symbol _spxOption;
|
||||
private Symbol _expectedContract;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
SetStartDate(2021, 1, 4);
|
||||
SetEndDate(2021, 1, 31);
|
||||
|
||||
_spx = AddIndex("SPX", Resolution.Minute).Symbol;
|
||||
|
||||
// Select a index option expiring ITM, and adds it to the algorithm.
|
||||
_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)
|
||||
.Single(), Resolution.Minute).Symbol;
|
||||
|
||||
_expectedContract = QuantConnect.Symbol.CreateOption(_spx, Market.USA, OptionStyle.European, OptionRight.Put, 4200m, new DateTime(2021, 1, 15));
|
||||
if (_spxOption != _expectedContract)
|
||||
{
|
||||
throw new Exception($"Contract {_expectedContract} was not found in the chain");
|
||||
}
|
||||
|
||||
Schedule.On(DateRules.Tomorrow, TimeRules.AfterMarketOpen(_spx, 1), () =>
|
||||
{
|
||||
MarketOrder(_spxOption, 1);
|
||||
});
|
||||
}
|
||||
|
||||
public override void OnData(Slice data)
|
||||
{
|
||||
// Assert delistings, so that we can make sure that we receive the delisting warnings at
|
||||
// the expected time. These assertions detect bug #4872
|
||||
foreach (var delisting in data.Delistings.Values)
|
||||
{
|
||||
if (delisting.Type == DelistingType.Warning)
|
||||
{
|
||||
if (delisting.Time != new DateTime(2021, 1, 15))
|
||||
{
|
||||
throw new Exception($"Delisting warning issued at unexpected date: {delisting.Time}");
|
||||
}
|
||||
}
|
||||
if (delisting.Type == DelistingType.Delisted)
|
||||
{
|
||||
if (delisting.Time != new DateTime(2021, 1, 16))
|
||||
{
|
||||
throw new Exception($"Delisting happened at unexpected date: {delisting.Time}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnOrderEvent(OrderEvent orderEvent)
|
||||
{
|
||||
if (orderEvent.Status != OrderStatus.Filled)
|
||||
{
|
||||
// There's lots of noise with OnOrderEvent, but we're only interested in fills.
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Securities.ContainsKey(orderEvent.Symbol))
|
||||
{
|
||||
throw new Exception($"Order event Symbol not found in Securities collection: {orderEvent.Symbol}");
|
||||
}
|
||||
|
||||
var security = Securities[orderEvent.Symbol];
|
||||
if (security.Symbol == _spx)
|
||||
{
|
||||
AssertIndexOptionOrderExercise(orderEvent, security, Securities[_expectedContract]);
|
||||
}
|
||||
else if (security.Symbol == _expectedContract)
|
||||
{
|
||||
AssertIndexOptionContractOrder(orderEvent, security);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception($"Received order event for unknown Symbol: {orderEvent.Symbol}");
|
||||
}
|
||||
|
||||
Log($"{Time:yyyy-MM-dd HH:mm:ss} -- {orderEvent.Symbol} :: Price: {Securities[orderEvent.Symbol].Holdings.Price} Qty: {Securities[orderEvent.Symbol].Holdings.Quantity} Direction: {orderEvent.Direction} Msg: {orderEvent.Message}");
|
||||
}
|
||||
|
||||
private void AssertIndexOptionOrderExercise(OrderEvent orderEvent, Security index, Security optionContract)
|
||||
{
|
||||
var expectedLiquidationTimeUtc = new DateTime(2021, 1, 15);
|
||||
|
||||
if (orderEvent.Direction == OrderDirection.Buy && orderEvent.UtcTime != expectedLiquidationTimeUtc)
|
||||
{
|
||||
throw new Exception($"Liquidated index option contract, but not at the expected time. Expected: {expectedLiquidationTimeUtc:yyyy-MM-dd HH:mm:ss} - found {orderEvent.UtcTime:yyyy-MM-dd HH:mm:ss}");
|
||||
}
|
||||
|
||||
// No way to detect option exercise orders or any other kind of special orders
|
||||
// other than matching strings, for now.
|
||||
if (orderEvent.Message.Contains("Option Exercise"))
|
||||
{
|
||||
if (orderEvent.FillPrice != 3300m)
|
||||
{
|
||||
throw new Exception("Option did not exercise at expected strike price (3300)");
|
||||
}
|
||||
|
||||
if (optionContract.Holdings.Quantity != 0)
|
||||
{
|
||||
throw new Exception($"Exercised option contract, but we have holdings for Option contract {optionContract.Symbol}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void AssertIndexOptionContractOrder(OrderEvent orderEvent, Security option)
|
||||
{
|
||||
if (orderEvent.Direction == OrderDirection.Buy && option.Holdings.Quantity != 1)
|
||||
{
|
||||
throw new Exception($"No holdings were created for option contract {option.Symbol}");
|
||||
}
|
||||
if (orderEvent.Direction == OrderDirection.Sell && option.Holdings.Quantity != 0)
|
||||
{
|
||||
throw new Exception($"Holdings were found after a filled option exercise");
|
||||
}
|
||||
if (orderEvent.Message.Contains("Exercise") && option.Holdings.Quantity != 0)
|
||||
{
|
||||
throw new Exception($"Holdings were found after exercising option contract {option.Symbol}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ran at the end of the algorithm to ensure the algorithm has no holdings
|
||||
/// </summary>
|
||||
/// <exception cref="Exception">The algorithm has holdings</exception>
|
||||
public override void OnEndOfAlgorithm()
|
||||
{
|
||||
if (Portfolio.Invested)
|
||||
{
|
||||
throw new Exception($"Expected no holdings at end of algorithm, but are invested in: {string.Join(", ", Portfolio.Keys)}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This is used by the regression test system to indicate if the open source Lean repository has the required data to run this algorithm.
|
||||
/// </summary>
|
||||
public bool CanRunLocally { get; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// This is used by the regression test system to indicate which languages this algorithm is written in.
|
||||
/// </summary>
|
||||
public Language[] Languages { get; } = { Language.CSharp, Language.Python };
|
||||
|
||||
/// <summary>
|
||||
/// This is used by the regression test system to indicate what the expected statistics are from running the algorithm
|
||||
/// </summary>
|
||||
public Dictionary<string, string> ExpectedStatistics => new Dictionary<string, string>
|
||||
{
|
||||
{"Total Trades", "2"},
|
||||
{"Average Win", "0%"},
|
||||
{"Average Loss", "-51.53%"},
|
||||
{"Compounding Annual Return", "-81.170%"},
|
||||
{"Drawdown", "13.800%"},
|
||||
{"Expectancy", "-1"},
|
||||
{"Net Profit", "-11.084%"},
|
||||
{"Sharpe Ratio", "-1.894"},
|
||||
{"Probabilistic Sharpe Ratio", "0.621%"},
|
||||
{"Loss Rate", "100%"},
|
||||
{"Win Rate", "0%"},
|
||||
{"Profit-Loss Ratio", "0"},
|
||||
{"Alpha", "0"},
|
||||
{"Beta", "0"},
|
||||
{"Annual Standard Deviation", "0.398"},
|
||||
{"Annual Variance", "0.158"},
|
||||
{"Information Ratio", "-1.894"},
|
||||
{"Tracking Error", "0.398"},
|
||||
{"Treynor Ratio", "0"},
|
||||
{"Total Fees", "$0.00"},
|
||||
{"Estimated Strategy Capacity", "$0"},
|
||||
{"Fitness Score", "0.005"},
|
||||
{"Kelly Criterion Estimate", "0"},
|
||||
{"Kelly Criterion Probability Value", "0"},
|
||||
{"Sortino Ratio", "-0.662"},
|
||||
{"Return Over Maximum Drawdown", "-7.157"},
|
||||
{"Portfolio Turnover", "0.025"},
|
||||
{"Total Insights Generated", "0"},
|
||||
{"Total Insights Closed", "0"},
|
||||
{"Total Insights Analysis Completed", "0"},
|
||||
{"Long Insight Count", "0"},
|
||||
{"Short Insight Count", "0"},
|
||||
{"Long/Short Ratio", "100%"},
|
||||
{"Estimated Monthly Alpha Value", "$0"},
|
||||
{"Total Accumulated Estimated Alpha Value", "$0"},
|
||||
{"Mean Population Estimated Insight Value", "$0"},
|
||||
{"Mean Population Direction", "0%"},
|
||||
{"Mean Population Magnitude", "0%"},
|
||||
{"Rolling Averaged Population Direction", "0%"},
|
||||
{"Rolling Averaged Population Magnitude", "0%"},
|
||||
{"OrderListHash", "f2d98f952cc0b54fb620795018682105"}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
218
Algorithm.CSharp/IndexOptionPutOTMExpiryRegressionAlgorithm.cs
Normal file
218
Algorithm.CSharp/IndexOptionPutOTMExpiryRegressionAlgorithm.cs
Normal file
@@ -0,0 +1,218 @@
|
||||
/*
|
||||
* 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 System.Reflection;
|
||||
using QuantConnect.Data;
|
||||
using QuantConnect.Interfaces;
|
||||
using QuantConnect.Orders;
|
||||
using QuantConnect.Securities;
|
||||
|
||||
namespace QuantConnect.Algorithm.CSharp
|
||||
{
|
||||
/// <summary>
|
||||
/// This regression algorithm tests Out of The Money (OTM) index option expiry for puts.
|
||||
/// We expect 2 orders from the algorithm, which are:
|
||||
///
|
||||
/// * Initial entry, buy SPX Put Option (expiring OTM)
|
||||
/// - contract expires worthless, not exercised, so never opened a position in the underlying
|
||||
///
|
||||
/// * Liquidation of worthless SPX Put OTM contract
|
||||
///
|
||||
/// Additionally, we test delistings for index options and assert that our
|
||||
/// portfolio holdings reflect the orders the algorithm has submitted.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Total Trades in regression algorithm should be 1, but expiration is counted as a trade.
|
||||
/// </remarks>
|
||||
public class IndexOptionPutOTMExpiryRegressionAlgorithm : QCAlgorithm, IRegressionAlgorithmDefinition
|
||||
{
|
||||
private Symbol _spx;
|
||||
private Symbol _spxOption;
|
||||
private Symbol _expectedContract;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
SetStartDate(2021, 1, 4);
|
||||
SetEndDate(2021, 1, 31);
|
||||
|
||||
_spx = AddIndex("SPX", Resolution.Minute).Symbol;
|
||||
|
||||
// Select a index option expiring ITM, and adds it to the algorithm.
|
||||
_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)
|
||||
.Single(), Resolution.Minute).Symbol;
|
||||
|
||||
_expectedContract = QuantConnect.Symbol.CreateOption(_spx, Market.USA, OptionStyle.European, OptionRight.Put, 3200m, new DateTime(2021, 1, 15));
|
||||
if (_spxOption != _expectedContract)
|
||||
{
|
||||
throw new Exception($"Contract {_expectedContract} was not found in the chain");
|
||||
}
|
||||
|
||||
Schedule.On(DateRules.Tomorrow, TimeRules.AfterMarketOpen(_spx, 1), () =>
|
||||
{
|
||||
MarketOrder(_spxOption, 1);
|
||||
});
|
||||
}
|
||||
|
||||
public override void OnData(Slice data)
|
||||
{
|
||||
// Assert delistings, so that we can make sure that we receive the delisting warnings at
|
||||
// the expected time. These assertions detect bug #4872
|
||||
foreach (var delisting in data.Delistings.Values)
|
||||
{
|
||||
if (delisting.Type == DelistingType.Warning)
|
||||
{
|
||||
if (delisting.Time != new DateTime(2021, 1, 15))
|
||||
{
|
||||
throw new Exception($"Delisting warning issued at unexpected date: {delisting.Time}");
|
||||
}
|
||||
}
|
||||
if (delisting.Type == DelistingType.Delisted)
|
||||
{
|
||||
if (delisting.Time != new DateTime(2021, 1, 16))
|
||||
{
|
||||
throw new Exception($"Delisting happened at unexpected date: {delisting.Time}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnOrderEvent(OrderEvent orderEvent)
|
||||
{
|
||||
if (orderEvent.Status != OrderStatus.Filled)
|
||||
{
|
||||
// There's lots of noise with OnOrderEvent, but we're only interested in fills.
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Securities.ContainsKey(orderEvent.Symbol))
|
||||
{
|
||||
throw new Exception($"Order event Symbol not found in Securities collection: {orderEvent.Symbol}");
|
||||
}
|
||||
|
||||
var security = Securities[orderEvent.Symbol];
|
||||
if (security.Symbol == _spx)
|
||||
{
|
||||
throw new Exception("Invalid state: did not expect a position for the underlying to be opened, since this contract expires OTM and is not tradable");
|
||||
}
|
||||
if (security.Symbol == _expectedContract)
|
||||
{
|
||||
AssertIndexOptionContractOrder(orderEvent, security);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception($"Received order event for unknown Symbol: {orderEvent.Symbol}");
|
||||
}
|
||||
|
||||
Log($"{orderEvent}");
|
||||
}
|
||||
|
||||
private void AssertIndexOptionContractOrder(OrderEvent orderEvent, Security option)
|
||||
{
|
||||
if (orderEvent.Direction == OrderDirection.Buy && option.Holdings.Quantity != 1)
|
||||
{
|
||||
throw new Exception($"No holdings were created for option contract {option.Symbol}");
|
||||
}
|
||||
if (orderEvent.Direction == OrderDirection.Sell && option.Holdings.Quantity != 0)
|
||||
{
|
||||
throw new Exception("Holdings were found after a filled option exercise");
|
||||
}
|
||||
if (orderEvent.Direction == OrderDirection.Sell && !orderEvent.Message.Contains("OTM"))
|
||||
{
|
||||
throw new Exception("Contract did not expire OTM");
|
||||
}
|
||||
if (orderEvent.Message.Contains("Exercise"))
|
||||
{
|
||||
throw new Exception("Exercised option, even though it expires OTM");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ran at the end of the algorithm to ensure the algorithm has no holdings
|
||||
/// </summary>
|
||||
/// <exception cref="Exception">The algorithm has holdings</exception>
|
||||
public override void OnEndOfAlgorithm()
|
||||
{
|
||||
if (Portfolio.Invested)
|
||||
{
|
||||
throw new Exception($"Expected no holdings at end of algorithm, but are invested in: {string.Join(", ", Portfolio.Keys)}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This is used by the regression test system to indicate if the open source Lean repository has the required data to run this algorithm.
|
||||
/// </summary>
|
||||
public bool CanRunLocally { get; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// This is used by the regression test system to indicate which languages this algorithm is written in.
|
||||
/// </summary>
|
||||
public Language[] Languages { get; } = { Language.CSharp, Language.Python };
|
||||
|
||||
/// <summary>
|
||||
/// This is used by the regression test system to indicate what the expected statistics are from running the algorithm
|
||||
/// </summary>
|
||||
public Dictionary<string, string> ExpectedStatistics => new Dictionary<string, string>
|
||||
{
|
||||
{"Total Trades", "2"},
|
||||
{"Average Win", "0%"},
|
||||
{"Average Loss", "-0.37%"},
|
||||
{"Compounding Annual Return", "-5.132%"},
|
||||
{"Drawdown", "0.400%"},
|
||||
{"Expectancy", "-1"},
|
||||
{"Net Profit", "-0.370%"},
|
||||
{"Sharpe Ratio", "-3.622"},
|
||||
{"Probabilistic Sharpe Ratio", "0.270%"},
|
||||
{"Loss Rate", "100%"},
|
||||
{"Win Rate", "0%"},
|
||||
{"Profit-Loss Ratio", "0"},
|
||||
{"Alpha", "0"},
|
||||
{"Beta", "0"},
|
||||
{"Annual Standard Deviation", "0.013"},
|
||||
{"Annual Variance", "0"},
|
||||
{"Information Ratio", "-3.622"},
|
||||
{"Tracking Error", "0.013"},
|
||||
{"Treynor Ratio", "0"},
|
||||
{"Total Fees", "$0.00"},
|
||||
{"Estimated Strategy Capacity", "$0"},
|
||||
{"Fitness Score", "0"},
|
||||
{"Kelly Criterion Estimate", "0"},
|
||||
{"Kelly Criterion Probability Value", "0"},
|
||||
{"Sortino Ratio", "-1.628"},
|
||||
{"Return Over Maximum Drawdown", "-14.021"},
|
||||
{"Portfolio Turnover", "0"},
|
||||
{"Total Insights Generated", "0"},
|
||||
{"Total Insights Closed", "0"},
|
||||
{"Total Insights Analysis Completed", "0"},
|
||||
{"Long Insight Count", "0"},
|
||||
{"Short Insight Count", "0"},
|
||||
{"Long/Short Ratio", "100%"},
|
||||
{"Estimated Monthly Alpha Value", "$0"},
|
||||
{"Total Accumulated Estimated Alpha Value", "$0"},
|
||||
{"Mean Population Estimated Insight Value", "$0"},
|
||||
{"Mean Population Direction", "0%"},
|
||||
{"Mean Population Magnitude", "0%"},
|
||||
{"Rolling Averaged Population Direction", "0%"},
|
||||
{"Rolling Averaged Population Magnitude", "0%"},
|
||||
{"OrderListHash", "6faffe52c64c2148458af1d2deb68a6f"}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,220 @@
|
||||
/*
|
||||
* 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 System.Reflection;
|
||||
using QuantConnect.Data;
|
||||
using QuantConnect.Interfaces;
|
||||
using QuantConnect.Orders;
|
||||
using QuantConnect.Securities;
|
||||
|
||||
namespace QuantConnect.Algorithm.CSharp
|
||||
{
|
||||
/// <summary>
|
||||
/// This regression algorithm tests In The Money (ITM) index option expiry for short calls.
|
||||
/// We expect 2 orders from the algorithm, which are:
|
||||
///
|
||||
/// * Initial entry, sell SPX Call Option (expiring ITM)
|
||||
/// * Option assignment
|
||||
///
|
||||
/// Additionally, we test delistings for index options and assert that our
|
||||
/// portfolio holdings reflect the orders the algorithm has submitted.
|
||||
/// </summary>
|
||||
public class IndexOptionShortCallITMExpiryRegressionAlgorithm : QCAlgorithm, IRegressionAlgorithmDefinition
|
||||
{
|
||||
private Symbol _spx;
|
||||
private Symbol _esOption;
|
||||
private Symbol _expectedContract;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
SetStartDate(2021, 1, 4);
|
||||
SetEndDate(2021, 1, 31);
|
||||
|
||||
_spx = AddIndex("SPX", Resolution.Minute).Symbol;
|
||||
|
||||
// Select a index option expiring ITM, and adds it to the algorithm.
|
||||
_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;
|
||||
|
||||
_expectedContract = QuantConnect.Symbol.CreateOption(_spx, Market.USA, OptionStyle.European, OptionRight.Call, 3200m, new DateTime(2021, 1, 15));
|
||||
if (_esOption != _expectedContract)
|
||||
{
|
||||
throw new Exception($"Contract {_expectedContract} was not found in the chain");
|
||||
}
|
||||
|
||||
Schedule.On(DateRules.Tomorrow, TimeRules.AfterMarketOpen(_spx, 1), () =>
|
||||
{
|
||||
MarketOrder(_esOption, -1);
|
||||
});
|
||||
}
|
||||
|
||||
public override void OnData(Slice data)
|
||||
{
|
||||
// Assert delistings, so that we can make sure that we receive the delisting warnings at
|
||||
// the expected time. These assertions detect bug #4872
|
||||
foreach (var delisting in data.Delistings.Values)
|
||||
{
|
||||
if (delisting.Type == DelistingType.Warning)
|
||||
{
|
||||
if (delisting.Time != new DateTime(2021, 1, 15))
|
||||
{
|
||||
throw new Exception($"Delisting warning issued at unexpected date: {delisting.Time}");
|
||||
}
|
||||
}
|
||||
if (delisting.Type == DelistingType.Delisted)
|
||||
{
|
||||
if (delisting.Time != new DateTime(2021, 1, 16))
|
||||
{
|
||||
throw new Exception($"Delisting happened at unexpected date: {delisting.Time}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnOrderEvent(OrderEvent orderEvent)
|
||||
{
|
||||
if (orderEvent.Status != OrderStatus.Filled)
|
||||
{
|
||||
// There's lots of noise with OnOrderEvent, but we're only interested in fills.
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Securities.ContainsKey(orderEvent.Symbol))
|
||||
{
|
||||
throw new Exception($"Order event Symbol not found in Securities collection: {orderEvent.Symbol}");
|
||||
}
|
||||
|
||||
var security = Securities[orderEvent.Symbol];
|
||||
if (security.Symbol == _spx)
|
||||
{
|
||||
AssertIndexOptionOrderExercise(orderEvent, security, Securities[_expectedContract]);
|
||||
}
|
||||
else if (security.Symbol == _expectedContract)
|
||||
{
|
||||
AssertIndexOptionContractOrder(orderEvent, security);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception($"Received order event for unknown Symbol: {orderEvent.Symbol}");
|
||||
}
|
||||
|
||||
Log($"{orderEvent}");
|
||||
}
|
||||
|
||||
private void AssertIndexOptionOrderExercise(OrderEvent orderEvent, Security index, Security optionContract)
|
||||
{
|
||||
if (orderEvent.Message.Contains("Assignment"))
|
||||
{
|
||||
if (orderEvent.FillPrice != 3200m)
|
||||
{
|
||||
throw new Exception("Option was not assigned at expected strike price (3200)");
|
||||
}
|
||||
if (orderEvent.Direction != OrderDirection.Sell || index.Holdings.Quantity != 0)
|
||||
{
|
||||
throw new Exception($"Expected Qty: 0 index holdings for assigned index option {index.Symbol}, found {index.Holdings.Quantity}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void AssertIndexOptionContractOrder(OrderEvent orderEvent, Security option)
|
||||
{
|
||||
if (orderEvent.Direction == OrderDirection.Sell && option.Holdings.Quantity != -1)
|
||||
{
|
||||
throw new Exception($"No holdings were created for option contract {option.Symbol}");
|
||||
}
|
||||
if (orderEvent.IsAssignment && option.Holdings.Quantity != 0)
|
||||
{
|
||||
throw new Exception($"Holdings were found after option contract was assigned: {option.Symbol}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ran at the end of the algorithm to ensure the algorithm has no holdings
|
||||
/// </summary>
|
||||
/// <exception cref="Exception">The algorithm has holdings</exception>
|
||||
public override void OnEndOfAlgorithm()
|
||||
{
|
||||
if (Portfolio.Invested)
|
||||
{
|
||||
throw new Exception($"Expected no holdings at end of algorithm, but are invested in: {string.Join(", ", Portfolio.Keys)}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This is used by the regression test system to indicate if the open source Lean repository has the required data to run this algorithm.
|
||||
/// </summary>
|
||||
public bool CanRunLocally { get; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// This is used by the regression test system to indicate which languages this algorithm is written in.
|
||||
/// </summary>
|
||||
public Language[] Languages { get; } = { Language.CSharp, Language.Python };
|
||||
|
||||
/// <summary>
|
||||
/// This is used by the regression test system to indicate what the expected statistics are from running the algorithm
|
||||
/// </summary>
|
||||
public Dictionary<string, string> ExpectedStatistics => new Dictionary<string, string>
|
||||
{
|
||||
{"Total Trades", "2"},
|
||||
{"Average Win", "48.82%"},
|
||||
{"Average Loss", "0%"},
|
||||
{"Compounding Annual Return", "-80.089%"},
|
||||
{"Drawdown", "13.400%"},
|
||||
{"Expectancy", "0"},
|
||||
{"Net Profit", "-10.734%"},
|
||||
{"Sharpe Ratio", "-1.928"},
|
||||
{"Probabilistic Sharpe Ratio", "0.619%"},
|
||||
{"Loss Rate", "0%"},
|
||||
{"Win Rate", "100%"},
|
||||
{"Profit-Loss Ratio", "0"},
|
||||
{"Alpha", "0"},
|
||||
{"Beta", "0"},
|
||||
{"Annual Standard Deviation", "0.385"},
|
||||
{"Annual Variance", "0.148"},
|
||||
{"Information Ratio", "-1.928"},
|
||||
{"Tracking Error", "0.385"},
|
||||
{"Treynor Ratio", "0"},
|
||||
{"Total Fees", "$0.00"},
|
||||
{"Estimated Strategy Capacity", "$0"},
|
||||
{"Fitness Score", "0.005"},
|
||||
{"Kelly Criterion Estimate", "0"},
|
||||
{"Kelly Criterion Probability Value", "0"},
|
||||
{"Sortino Ratio", "-0.676"},
|
||||
{"Return Over Maximum Drawdown", "-7.289"},
|
||||
{"Portfolio Turnover", "0.024"},
|
||||
{"Total Insights Generated", "0"},
|
||||
{"Total Insights Closed", "0"},
|
||||
{"Total Insights Analysis Completed", "0"},
|
||||
{"Long Insight Count", "0"},
|
||||
{"Short Insight Count", "0"},
|
||||
{"Long/Short Ratio", "100%"},
|
||||
{"Estimated Monthly Alpha Value", "$0"},
|
||||
{"Total Accumulated Estimated Alpha Value", "$0"},
|
||||
{"Mean Population Estimated Insight Value", "$0"},
|
||||
{"Mean Population Direction", "0%"},
|
||||
{"Mean Population Magnitude", "0%"},
|
||||
{"Rolling Averaged Population Direction", "0%"},
|
||||
{"Rolling Averaged Population Magnitude", "0%"},
|
||||
{"OrderListHash", "439042b39981ea246e50728cc57c31c7"}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,212 @@
|
||||
/*
|
||||
* 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 System.Reflection;
|
||||
using QuantConnect.Data;
|
||||
using QuantConnect.Interfaces;
|
||||
using QuantConnect.Orders;
|
||||
using QuantConnect.Securities;
|
||||
|
||||
namespace QuantConnect.Algorithm.CSharp
|
||||
{
|
||||
/// <summary>
|
||||
/// This regression algorithm tests Out of The Money (OTM) index option expiry for short calls.
|
||||
/// We expect 2 orders from the algorithm, which are:
|
||||
///
|
||||
/// * Initial entry, sell SPX Call Option (expiring OTM)
|
||||
/// - Profit the option premium, since the option was not assigned.
|
||||
///
|
||||
/// * Liquidation of SPX call OTM contract on the last trade date
|
||||
///
|
||||
/// Additionally, we test delistings for index options and assert that our
|
||||
/// portfolio holdings reflect the orders the algorithm has submitted.
|
||||
/// </summary>
|
||||
public class IndexOptionShortCallOTMExpiryRegressionAlgorithm : QCAlgorithm, IRegressionAlgorithmDefinition
|
||||
{
|
||||
private Symbol _spx;
|
||||
private Symbol _spxOption;
|
||||
private Symbol _expectedContract;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
SetStartDate(2021, 1, 4);
|
||||
SetEndDate(2021, 1, 31);
|
||||
|
||||
_spx = AddIndex("SPX", Resolution.Minute).Symbol;
|
||||
|
||||
// Select a index option expiring ITM, and adds it to the algorithm.
|
||||
_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)
|
||||
.Single(), Resolution.Minute).Symbol;
|
||||
|
||||
_expectedContract = QuantConnect.Symbol.CreateOption(_spx, Market.USA, OptionStyle.European, OptionRight.Call, 4250m, new DateTime(2021, 1, 15));
|
||||
if (_spxOption != _expectedContract)
|
||||
{
|
||||
throw new Exception($"Contract {_expectedContract} was not found in the chain");
|
||||
}
|
||||
|
||||
Schedule.On(DateRules.Tomorrow, TimeRules.AfterMarketOpen(_spx, 1), () =>
|
||||
{
|
||||
MarketOrder(_spxOption, -1);
|
||||
});
|
||||
}
|
||||
|
||||
public override void OnData(Slice data)
|
||||
{
|
||||
// Assert delistings, so that we can make sure that we receive the delisting warnings at
|
||||
// the expected time. These assertions detect bug #4872
|
||||
foreach (var delisting in data.Delistings.Values)
|
||||
{
|
||||
if (delisting.Type == DelistingType.Warning)
|
||||
{
|
||||
if (delisting.Time != new DateTime(2021, 1, 15))
|
||||
{
|
||||
throw new Exception($"Delisting warning issued at unexpected date: {delisting.Time}");
|
||||
}
|
||||
}
|
||||
if (delisting.Type == DelistingType.Delisted)
|
||||
{
|
||||
if (delisting.Time != new DateTime(2021, 1, 16))
|
||||
{
|
||||
throw new Exception($"Delisting happened at unexpected date: {delisting.Time}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnOrderEvent(OrderEvent orderEvent)
|
||||
{
|
||||
if (orderEvent.Status != OrderStatus.Filled)
|
||||
{
|
||||
// There's lots of noise with OnOrderEvent, but we're only interested in fills.
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Securities.ContainsKey(orderEvent.Symbol))
|
||||
{
|
||||
throw new Exception($"Order event Symbol not found in Securities collection: {orderEvent.Symbol}");
|
||||
}
|
||||
|
||||
var security = Securities[orderEvent.Symbol];
|
||||
if (security.Symbol == _spx)
|
||||
{
|
||||
throw new Exception($"Expected no order events for underlying Symbol {security.Symbol}");
|
||||
}
|
||||
|
||||
if (security.Symbol == _expectedContract)
|
||||
{
|
||||
AssertIndexOptionContractOrder(orderEvent, security);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception($"Received order event for unknown Symbol: {orderEvent.Symbol}");
|
||||
}
|
||||
|
||||
Log($"{orderEvent}");
|
||||
}
|
||||
|
||||
private void AssertIndexOptionContractOrder(OrderEvent orderEvent, Security optionContract)
|
||||
{
|
||||
if (orderEvent.Direction == OrderDirection.Sell && optionContract.Holdings.Quantity != -1)
|
||||
{
|
||||
throw new Exception($"No holdings were created for option contract {optionContract.Symbol}");
|
||||
}
|
||||
if (orderEvent.Direction == OrderDirection.Buy && optionContract.Holdings.Quantity != 0)
|
||||
{
|
||||
throw new Exception("Expected no options holdings after closing position");
|
||||
}
|
||||
if (orderEvent.IsAssignment)
|
||||
{
|
||||
throw new Exception($"Assignment was not expected for {orderEvent.Symbol}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ran at the end of the algorithm to ensure the algorithm has no holdings
|
||||
/// </summary>
|
||||
/// <exception cref="Exception">The algorithm has holdings</exception>
|
||||
public override void OnEndOfAlgorithm()
|
||||
{
|
||||
if (Portfolio.Invested)
|
||||
{
|
||||
throw new Exception($"Expected no holdings at end of algorithm, but are invested in: {string.Join(", ", Portfolio.Keys)}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This is used by the regression test system to indicate if the open source Lean repository has the required data to run this algorithm.
|
||||
/// </summary>
|
||||
public bool CanRunLocally { get; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// This is used by the regression test system to indicate which languages this algorithm is written in.
|
||||
/// </summary>
|
||||
public Language[] Languages { get; } = { Language.CSharp, Language.Python };
|
||||
|
||||
/// <summary>
|
||||
/// This is used by the regression test system to indicate what the expected statistics are from running the algorithm
|
||||
/// </summary>
|
||||
public Dictionary<string, string> ExpectedStatistics => new Dictionary<string, string>
|
||||
{
|
||||
{"Total Trades", "2"},
|
||||
{"Average Win", "0.01%"},
|
||||
{"Average Loss", "0%"},
|
||||
{"Compounding Annual Return", "0.142%"},
|
||||
{"Drawdown", "0%"},
|
||||
{"Expectancy", "0"},
|
||||
{"Net Profit", "0.010%"},
|
||||
{"Sharpe Ratio", "5.161"},
|
||||
{"Probabilistic Sharpe Ratio", "99.241%"},
|
||||
{"Loss Rate", "0%"},
|
||||
{"Win Rate", "100%"},
|
||||
{"Profit-Loss Ratio", "0"},
|
||||
{"Alpha", "0"},
|
||||
{"Beta", "0"},
|
||||
{"Annual Standard Deviation", "0"},
|
||||
{"Annual Variance", "0"},
|
||||
{"Information Ratio", "5.161"},
|
||||
{"Tracking Error", "0"},
|
||||
{"Treynor Ratio", "0"},
|
||||
{"Total Fees", "$0.00"},
|
||||
{"Estimated Strategy Capacity", "$23000.00"},
|
||||
{"Fitness Score", "0"},
|
||||
{"Kelly Criterion Estimate", "0"},
|
||||
{"Kelly Criterion Probability Value", "0"},
|
||||
{"Sortino Ratio", "79228162514264337593543950335"},
|
||||
{"Return Over Maximum Drawdown", "79228162514264337593543950335"},
|
||||
{"Portfolio Turnover", "0"},
|
||||
{"Total Insights Generated", "0"},
|
||||
{"Total Insights Closed", "0"},
|
||||
{"Total Insights Analysis Completed", "0"},
|
||||
{"Long Insight Count", "0"},
|
||||
{"Short Insight Count", "0"},
|
||||
{"Long/Short Ratio", "100%"},
|
||||
{"Estimated Monthly Alpha Value", "$0"},
|
||||
{"Total Accumulated Estimated Alpha Value", "$0"},
|
||||
{"Mean Population Estimated Insight Value", "$0"},
|
||||
{"Mean Population Direction", "0%"},
|
||||
{"Mean Population Magnitude", "0%"},
|
||||
{"Rolling Averaged Population Direction", "0%"},
|
||||
{"Rolling Averaged Population Magnitude", "0%"},
|
||||
{"OrderListHash", "b55e2b2bd35bc3200e228b4e6e77dd90"}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,224 @@
|
||||
/*
|
||||
* 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 System.Reflection;
|
||||
using QuantConnect.Data;
|
||||
using QuantConnect.Interfaces;
|
||||
using QuantConnect.Orders;
|
||||
using QuantConnect.Securities;
|
||||
|
||||
namespace QuantConnect.Algorithm.CSharp
|
||||
{
|
||||
/// <summary>
|
||||
/// This regression algorithm tests In The Money (ITM) index option expiry for short puts.
|
||||
/// We expect 2 orders from the algorithm, which are:
|
||||
///
|
||||
/// * Initial entry, sell SPX Put Option (expiring ITM)
|
||||
/// * Option assignment
|
||||
///
|
||||
/// Additionally, we test delistings for index options and assert that our
|
||||
/// portfolio holdings reflect the orders the algorithm has submitted.
|
||||
/// </summary>
|
||||
public class IndexOptionShortPutITMExpiryRegressionAlgorithm : QCAlgorithm, IRegressionAlgorithmDefinition
|
||||
{
|
||||
private Symbol _spx;
|
||||
private Symbol _spxOption;
|
||||
private Symbol _expectedContract;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
SetStartDate(2021, 1, 4);
|
||||
SetEndDate(2021, 1, 31);
|
||||
|
||||
_spx = AddIndex("SPX", Resolution.Minute).Symbol;
|
||||
|
||||
// Select a index option expiring ITM, and adds it to the algorithm.
|
||||
_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;
|
||||
|
||||
_expectedContract = QuantConnect.Symbol.CreateOption(_spx, Market.USA, OptionStyle.European, OptionRight.Put, 4200m, new DateTime(2021, 1, 15));
|
||||
if (_spxOption != _expectedContract)
|
||||
{
|
||||
throw new Exception($"Contract {_expectedContract} was not found in the chain");
|
||||
}
|
||||
|
||||
Schedule.On(DateRules.Tomorrow, TimeRules.AfterMarketOpen(_spx, 1), () =>
|
||||
{
|
||||
MarketOrder(_spxOption, -1);
|
||||
});
|
||||
}
|
||||
|
||||
public override void OnData(Slice data)
|
||||
{
|
||||
// Assert delistings, so that we can make sure that we receive the delisting warnings at
|
||||
// the expected time. These assertions detect bug #4872
|
||||
foreach (var delisting in data.Delistings.Values)
|
||||
{
|
||||
if (delisting.Type == DelistingType.Warning)
|
||||
{
|
||||
if (delisting.Time != new DateTime(2021, 1, 15))
|
||||
{
|
||||
throw new Exception($"Delisting warning issued at unexpected date: {delisting.Time}");
|
||||
}
|
||||
}
|
||||
if (delisting.Type == DelistingType.Delisted)
|
||||
{
|
||||
if (delisting.Time != new DateTime(2021, 1, 16))
|
||||
{
|
||||
throw new Exception($"Delisting happened at unexpected date: {delisting.Time}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnOrderEvent(OrderEvent orderEvent)
|
||||
{
|
||||
if (orderEvent.Status != OrderStatus.Filled)
|
||||
{
|
||||
// There's lots of noise with OnOrderEvent, but we're only interested in fills.
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Securities.ContainsKey(orderEvent.Symbol))
|
||||
{
|
||||
throw new Exception($"Order event Symbol not found in Securities collection: {orderEvent.Symbol}");
|
||||
}
|
||||
|
||||
var security = Securities[orderEvent.Symbol];
|
||||
if (security.Symbol == _spx)
|
||||
{
|
||||
AssertIndexOptionOrderExercise(orderEvent, security, Securities[_expectedContract]);
|
||||
}
|
||||
else if (security.Symbol == _expectedContract)
|
||||
{
|
||||
AssertIndexOptionContractOrder(orderEvent, security);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception($"Received order event for unknown Symbol: {orderEvent.Symbol}");
|
||||
}
|
||||
|
||||
Log($"{orderEvent}");
|
||||
}
|
||||
|
||||
private void AssertIndexOptionOrderExercise(OrderEvent orderEvent, Security index, Security optionContract)
|
||||
{
|
||||
if (orderEvent.Message.Contains("Assignment"))
|
||||
{
|
||||
if (orderEvent.FillPrice != 4200)
|
||||
{
|
||||
throw new Exception("Option was not assigned at expected strike price (4200)");
|
||||
}
|
||||
if (orderEvent.Direction != OrderDirection.Buy || index.Holdings.Quantity != 0)
|
||||
{
|
||||
throw new Exception($"Expected Qty: 0 index holdings for assigned index option {index.Symbol}, found {index.Holdings.Quantity}");
|
||||
}
|
||||
}
|
||||
else if (index.Holdings.Quantity != 0)
|
||||
{
|
||||
throw new Exception($"Expected no holdings in index: {index.Symbol}");
|
||||
}
|
||||
}
|
||||
|
||||
private void AssertIndexOptionContractOrder(OrderEvent orderEvent, Security option)
|
||||
{
|
||||
if (orderEvent.Direction == OrderDirection.Sell && option.Holdings.Quantity != -1)
|
||||
{
|
||||
throw new Exception($"No holdings were created for option contract {option.Symbol}");
|
||||
}
|
||||
if (orderEvent.IsAssignment && option.Holdings.Quantity != 0)
|
||||
{
|
||||
throw new Exception($"Holdings were found after option contract was assigned: {option.Symbol}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ran at the end of the algorithm to ensure the algorithm has no holdings
|
||||
/// </summary>
|
||||
/// <exception cref="Exception">The algorithm has holdings</exception>
|
||||
public override void OnEndOfAlgorithm()
|
||||
{
|
||||
if (Portfolio.Invested)
|
||||
{
|
||||
throw new Exception($"Expected no holdings at end of algorithm, but are invested in: {string.Join(", ", Portfolio.Keys)}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This is used by the regression test system to indicate if the open source Lean repository has the required data to run this algorithm.
|
||||
/// </summary>
|
||||
public bool CanRunLocally { get; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// This is used by the regression test system to indicate which languages this algorithm is written in.
|
||||
/// </summary>
|
||||
public Language[] Languages { get; } = { Language.CSharp, Language.Python };
|
||||
|
||||
/// <summary>
|
||||
/// This is used by the regression test system to indicate what the expected statistics are from running the algorithm
|
||||
/// </summary>
|
||||
public Dictionary<string, string> ExpectedStatistics => new Dictionary<string, string>
|
||||
{
|
||||
{"Total Trades", "2"},
|
||||
{"Average Win", "51.07%"},
|
||||
{"Average Loss", "0%"},
|
||||
{"Compounding Annual Return", "319.986%"},
|
||||
{"Drawdown", "2.400%"},
|
||||
{"Expectancy", "0"},
|
||||
{"Net Profit", "10.624%"},
|
||||
{"Sharpe Ratio", "7.1"},
|
||||
{"Probabilistic Sharpe Ratio", "89.813%"},
|
||||
{"Loss Rate", "0%"},
|
||||
{"Win Rate", "100%"},
|
||||
{"Profit-Loss Ratio", "0"},
|
||||
{"Alpha", "0"},
|
||||
{"Beta", "0"},
|
||||
{"Annual Standard Deviation", "0.398"},
|
||||
{"Annual Variance", "0.159"},
|
||||
{"Information Ratio", "7.1"},
|
||||
{"Tracking Error", "0.398"},
|
||||
{"Treynor Ratio", "0"},
|
||||
{"Total Fees", "$0.00"},
|
||||
{"Estimated Strategy Capacity", "$0"},
|
||||
{"Fitness Score", "0.025"},
|
||||
{"Kelly Criterion Estimate", "0"},
|
||||
{"Kelly Criterion Probability Value", "0"},
|
||||
{"Sortino Ratio", "634.943"},
|
||||
{"Return Over Maximum Drawdown", "1184.633"},
|
||||
{"Portfolio Turnover", "0.025"},
|
||||
{"Total Insights Generated", "0"},
|
||||
{"Total Insights Closed", "0"},
|
||||
{"Total Insights Analysis Completed", "0"},
|
||||
{"Long Insight Count", "0"},
|
||||
{"Short Insight Count", "0"},
|
||||
{"Long/Short Ratio", "100%"},
|
||||
{"Estimated Monthly Alpha Value", "$0"},
|
||||
{"Total Accumulated Estimated Alpha Value", "$0"},
|
||||
{"Mean Population Estimated Insight Value", "$0"},
|
||||
{"Mean Population Direction", "0%"},
|
||||
{"Mean Population Magnitude", "0%"},
|
||||
{"Rolling Averaged Population Direction", "0%"},
|
||||
{"Rolling Averaged Population Magnitude", "0%"},
|
||||
{"OrderListHash", "f243341674cb1486d7cf009d74d4e6ff"}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,211 @@
|
||||
/*
|
||||
* 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 System.Reflection;
|
||||
using QuantConnect.Data;
|
||||
using QuantConnect.Interfaces;
|
||||
using QuantConnect.Orders;
|
||||
using QuantConnect.Securities;
|
||||
|
||||
namespace QuantConnect.Algorithm.CSharp
|
||||
{
|
||||
/// <summary>
|
||||
/// This regression algorithm tests Out of The Money (OTM) index option expiry for short puts.
|
||||
/// We expect 2 order from the algorithm, which are:
|
||||
///
|
||||
/// * Initial entry, sell SPX Put Option (expiring OTM)
|
||||
/// - Profit the option premium, since the option was not assigned.
|
||||
///
|
||||
/// * Liquidation of SPX put OTM contract on the last trade date
|
||||
///
|
||||
/// Additionally, we test delistings for index options and assert that our
|
||||
/// portfolio holdings reflect the orders the algorithm has submitted.
|
||||
/// </summary>
|
||||
public class IndexOptionShortPutOTMExpiryRegressionAlgorithm : QCAlgorithm, IRegressionAlgorithmDefinition
|
||||
{
|
||||
private Symbol _spx;
|
||||
private Symbol _spxOption;
|
||||
private Symbol _expectedContract;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
SetStartDate(2021, 1, 4);
|
||||
SetEndDate(2021, 1, 31);
|
||||
|
||||
_spx = AddIndex("SPX", Resolution.Minute).Symbol;
|
||||
|
||||
// Select a index option expiring ITM, and adds it to the algorithm.
|
||||
_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)
|
||||
.Single(), Resolution.Minute).Symbol;
|
||||
|
||||
_expectedContract = QuantConnect.Symbol.CreateOption(_spx, Market.USA, OptionStyle.European, OptionRight.Put, 3200m, new DateTime(2021, 1, 15));
|
||||
if (_spxOption != _expectedContract)
|
||||
{
|
||||
throw new Exception($"Contract {_expectedContract} was not found in the chain");
|
||||
}
|
||||
|
||||
Schedule.On(DateRules.Tomorrow, TimeRules.AfterMarketOpen(_spx, 1), () =>
|
||||
{
|
||||
MarketOrder(_spxOption, -1);
|
||||
});
|
||||
}
|
||||
|
||||
public override void OnData(Slice data)
|
||||
{
|
||||
// Assert delistings, so that we can make sure that we receive the delisting warnings at
|
||||
// the expected time. These assertions detect bug #4872
|
||||
foreach (var delisting in data.Delistings.Values)
|
||||
{
|
||||
if (delisting.Type == DelistingType.Warning)
|
||||
{
|
||||
if (delisting.Time != new DateTime(2021, 1, 15))
|
||||
{
|
||||
throw new Exception($"Delisting warning issued at unexpected date: {delisting.Time}");
|
||||
}
|
||||
}
|
||||
if (delisting.Type == DelistingType.Delisted)
|
||||
{
|
||||
if (delisting.Time != new DateTime(2021, 1, 16))
|
||||
{
|
||||
throw new Exception($"Delisting happened at unexpected date: {delisting.Time}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnOrderEvent(OrderEvent orderEvent)
|
||||
{
|
||||
if (orderEvent.Status != OrderStatus.Filled)
|
||||
{
|
||||
// There's lots of noise with OnOrderEvent, but we're only interested in fills.
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Securities.ContainsKey(orderEvent.Symbol))
|
||||
{
|
||||
throw new Exception($"Order event Symbol not found in Securities collection: {orderEvent.Symbol}");
|
||||
}
|
||||
|
||||
var security = Securities[orderEvent.Symbol];
|
||||
if (security.Symbol == _spx)
|
||||
{
|
||||
throw new Exception($"Expected no order events for underlying Symbol {security.Symbol}");
|
||||
}
|
||||
if (security.Symbol == _expectedContract)
|
||||
{
|
||||
AssertIndexOptionContractOrder(orderEvent, security);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception($"Received order event for unknown Symbol: {orderEvent.Symbol}");
|
||||
}
|
||||
|
||||
Log($"{orderEvent}");
|
||||
}
|
||||
|
||||
private void AssertIndexOptionContractOrder(OrderEvent orderEvent, Security option)
|
||||
{
|
||||
if (orderEvent.Direction == OrderDirection.Sell && option.Holdings.Quantity != -1)
|
||||
{
|
||||
throw new Exception($"No holdings were created for option contract {option.Symbol}");
|
||||
}
|
||||
if (orderEvent.Direction == OrderDirection.Buy && option.Holdings.Quantity != 0)
|
||||
{
|
||||
throw new Exception("Expected no options holdings after closing position");
|
||||
}
|
||||
if (orderEvent.IsAssignment)
|
||||
{
|
||||
throw new Exception($"Assignment was not expected for {orderEvent.Symbol}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ran at the end of the algorithm to ensure the algorithm has no holdings
|
||||
/// </summary>
|
||||
/// <exception cref="Exception">The algorithm has holdings</exception>
|
||||
public override void OnEndOfAlgorithm()
|
||||
{
|
||||
if (Portfolio.Invested)
|
||||
{
|
||||
throw new Exception($"Expected no holdings at end of algorithm, but are invested in: {string.Join(", ", Portfolio.Keys)}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This is used by the regression test system to indicate if the open source Lean repository has the required data to run this algorithm.
|
||||
/// </summary>
|
||||
public bool CanRunLocally { get; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// This is used by the regression test system to indicate which languages this algorithm is written in.
|
||||
/// </summary>
|
||||
public Language[] Languages { get; } = { Language.CSharp, Language.Python };
|
||||
|
||||
/// <summary>
|
||||
/// This is used by the regression test system to indicate what the expected statistics are from running the algorithm
|
||||
/// </summary>
|
||||
public Dictionary<string, string> ExpectedStatistics => new Dictionary<string, string>
|
||||
{
|
||||
{"Total Trades", "2"},
|
||||
{"Average Win", "0.35%"},
|
||||
{"Average Loss", "0%"},
|
||||
{"Compounding Annual Return", "5.091%"},
|
||||
{"Drawdown", "0.000%"},
|
||||
{"Expectancy", "0"},
|
||||
{"Net Profit", "0.350%"},
|
||||
{"Sharpe Ratio", "3.573"},
|
||||
{"Probabilistic Sharpe Ratio", "91.608%"},
|
||||
{"Loss Rate", "0%"},
|
||||
{"Win Rate", "100%"},
|
||||
{"Profit-Loss Ratio", "0"},
|
||||
{"Alpha", "0"},
|
||||
{"Beta", "0"},
|
||||
{"Annual Standard Deviation", "0.013"},
|
||||
{"Annual Variance", "0"},
|
||||
{"Information Ratio", "3.573"},
|
||||
{"Tracking Error", "0.013"},
|
||||
{"Treynor Ratio", "0"},
|
||||
{"Total Fees", "$0.00"},
|
||||
{"Estimated Strategy Capacity", "$0"},
|
||||
{"Fitness Score", "0"},
|
||||
{"Kelly Criterion Estimate", "0"},
|
||||
{"Kelly Criterion Probability Value", "0"},
|
||||
{"Sortino Ratio", "79228162514264337593543950335"},
|
||||
{"Return Over Maximum Drawdown", "514.964"},
|
||||
{"Portfolio Turnover", "0"},
|
||||
{"Total Insights Generated", "0"},
|
||||
{"Total Insights Closed", "0"},
|
||||
{"Total Insights Analysis Completed", "0"},
|
||||
{"Long Insight Count", "0"},
|
||||
{"Short Insight Count", "0"},
|
||||
{"Long/Short Ratio", "100%"},
|
||||
{"Estimated Monthly Alpha Value", "$0"},
|
||||
{"Total Accumulated Estimated Alpha Value", "$0"},
|
||||
{"Mean Population Estimated Insight Value", "$0"},
|
||||
{"Mean Population Direction", "0%"},
|
||||
{"Mean Population Magnitude", "0%"},
|
||||
{"Rolling Averaged Population Direction", "0%"},
|
||||
{"Rolling Averaged Population Magnitude", "0%"},
|
||||
{"OrderListHash", "636b79bb5bf3db20eeda02ccf1064d07"}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -158,8 +158,10 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
/// <summary>
|
||||
/// Fire plotting events once per day.
|
||||
/// </summary>
|
||||
public override void OnEndOfDay()
|
||||
public override void OnEndOfDay(Symbol symbol)
|
||||
{
|
||||
if (symbol != _symbol) return;
|
||||
|
||||
if (!_indicators.BB.IsReady) return;
|
||||
|
||||
Plot("BB", "Price", _price);
|
||||
@@ -261,7 +263,7 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
{"Tracking Error", "0.146"},
|
||||
{"Treynor Ratio", "-2.677"},
|
||||
{"Total Fees", "$1.00"},
|
||||
{"Estimated Strategy Capacity", "$75000000.00"},
|
||||
{"Estimated Strategy Capacity", "$530000000.00"},
|
||||
{"Fitness Score", "0.001"},
|
||||
{"Kelly Criterion Estimate", "0"},
|
||||
{"Kelly Criterion Probability Value", "0"},
|
||||
|
||||
@@ -94,7 +94,7 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
{"Tracking Error", "0.165"},
|
||||
{"Treynor Ratio", "1.212"},
|
||||
{"Total Fees", "$6.00"},
|
||||
{"Estimated Strategy Capacity", "$32000000.00"},
|
||||
{"Estimated Strategy Capacity", "$42000000.00"},
|
||||
{"Fitness Score", "0.063"},
|
||||
{"Kelly Criterion Estimate", "38.64"},
|
||||
{"Kelly Criterion Probability Value", "0.229"},
|
||||
|
||||
@@ -102,7 +102,7 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
{"Tracking Error", "0"},
|
||||
{"Treynor Ratio", "1.925"},
|
||||
{"Total Fees", "$61.90"},
|
||||
{"Estimated Strategy Capacity", "$2900000.00"},
|
||||
{"Estimated Strategy Capacity", "$5800000.00"},
|
||||
{"Fitness Score", "0.979"},
|
||||
{"Kelly Criterion Estimate", "38.64"},
|
||||
{"Kelly Criterion Probability Value", "0.229"},
|
||||
|
||||
@@ -100,7 +100,7 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
{"Tracking Error", "0.196"},
|
||||
{"Treynor Ratio", "-0.169"},
|
||||
{"Total Fees", "$34.00"},
|
||||
{"Estimated Strategy Capacity", "$460000000.00"},
|
||||
{"Estimated Strategy Capacity", "$180000000.00"},
|
||||
{"Fitness Score", "0.008"},
|
||||
{"Kelly Criterion Estimate", "0"},
|
||||
{"Kelly Criterion Probability Value", "0"},
|
||||
|
||||
@@ -145,7 +145,7 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
{"Tracking Error", "0.22"},
|
||||
{"Treynor Ratio", "3.431"},
|
||||
{"Total Fees", "$3.00"},
|
||||
{"Estimated Strategy Capacity", "$480000000.00"},
|
||||
{"Estimated Strategy Capacity", "$1900000000.00"},
|
||||
{"Fitness Score", "0"},
|
||||
{"Kelly Criterion Estimate", "0"},
|
||||
{"Kelly Criterion Probability Value", "0"},
|
||||
|
||||
@@ -118,7 +118,7 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
{"Tracking Error", "0.004"},
|
||||
{"Treynor Ratio", "1.577"},
|
||||
{"Total Fees", "$293.06"},
|
||||
{"Estimated Strategy Capacity", "$19000000.00"},
|
||||
{"Estimated Strategy Capacity", "$14000000.00"},
|
||||
{"Fitness Score", "0.999"},
|
||||
{"Kelly Criterion Estimate", "-6.994"},
|
||||
{"Kelly Criterion Probability Value", "0.593"},
|
||||
|
||||
@@ -118,7 +118,7 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
{"Tracking Error", "0.214"},
|
||||
{"Treynor Ratio", "-0.774"},
|
||||
{"Total Fees", "$443.74"},
|
||||
{"Estimated Strategy Capacity", "$110000000.00"},
|
||||
{"Estimated Strategy Capacity", "$750000000.00"},
|
||||
{"Fitness Score", "0.013"},
|
||||
{"Kelly Criterion Estimate", "0"},
|
||||
{"Kelly Criterion Probability Value", "0"},
|
||||
|
||||
@@ -135,7 +135,7 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
{"Tracking Error", "0.224"},
|
||||
{"Treynor Ratio", "3.851"},
|
||||
{"Total Fees", "$26.01"},
|
||||
{"Estimated Strategy Capacity", "$11000000.00"},
|
||||
{"Estimated Strategy Capacity", "$22000000.00"},
|
||||
{"Fitness Score", "0.999"},
|
||||
{"Kelly Criterion Estimate", "0"},
|
||||
{"Kelly Criterion Probability Value", "0"},
|
||||
|
||||
@@ -105,7 +105,7 @@ namespace QuantConnect.Algorithm.CSharp
|
||||
{"Tracking Error", "0.346"},
|
||||
{"Treynor Ratio", "-0.863"},
|
||||
{"Total Fees", "$13.69"},
|
||||
{"Estimated Strategy Capacity", "$1800000.00"},
|
||||
{"Estimated Strategy Capacity", "$13000000.00"},
|
||||
{"Fitness Score", "0"},
|
||||
{"Kelly Criterion Estimate", "0"},
|
||||
{"Kelly Criterion Probability Value", "0"},
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user