chore: import upstream snapshot with attribution

This commit is contained in:
wehub-resource-sync
2026-07-13 13:02:50 +08:00
commit 0fc60fdcb1
5008 changed files with 910633 additions and 0 deletions
+8
View File
@@ -0,0 +1,8 @@
# Use QuantConnect Research as the base
FROM quantconnect/research:latest
# Install dos2unix utility for converting pesky windows formatting when needed
RUN apt-get update && apt-get install -y dos2unix
# Install QuantConnect Stubs for Python Autocomplete
RUN pip install --no-cache-dir quantconnect-stubs
+44
View File
@@ -0,0 +1,44 @@
{
"name": "Lean Development Container",
"workspaceMount": "source=${localWorkspaceFolder},target=/Lean,type=bind",
"workspaceFolder": "/Lean",
// Use devcontainer Dockerfile that is based on Lean foundation image
"build": {
"dockerfile": "Dockerfile"
},
//See https://containers.dev/implementors/json_reference/ for a comprehensive json schema used to define this file.
"customizations": {
"vscode": {
// Add the IDs of extensions you want installed when the container is created.
"extensions": [
"ms-dotnettools.csdevkit",
"ms-python.python",
"eamodio.gitlens",
"yzhang.markdown-all-in-one",
"SonarSource.sonarlint-vscode"
],
// Set *default* vscode specific settings.json values on container create.
"settings": {
"terminal.integrated.profiles.linux": {
"bash": {
"path": "bash",
"icon": "terminal-bash"
}
}
}
}
},
//use the same network configuration as the host machine, ensuring no problems with firewalls, proxies etc.
"runArgs": [
"--network=host"
],
// Use 'forwardPorts' to make a list of ports inside the container available locally.
// "forwardPorts": [],
// Uncomment the next line to run commands after the container is created - for example installing curl.
"postCreateCommand": "dotnet nuget add source /Lean/LocalPackages;chmod u+x /Lean/.vscode/launch_research.sh;dos2unix /Lean/.vscode/launch_research.sh",
// Add mounts to docker container
"mounts": [
// Example data mount from local machine, must use target directory in Config.json
// "source=C:/Users/XXXXXXXXXXXX/Lean/Data,target=/Data,type=bind,consistency=cached"
]
}
+6
View File
@@ -0,0 +1,6 @@
packages/*
.git/*
.github/*
.vs/*
.nuget/*
Tests/*
+13
View File
@@ -0,0 +1,13 @@
root = true
[*]
charset = utf-8
indent_size = 4
indent_style = space
insert_final_newline = true
[*.{js,yml,json,config,csproj}]
indent_size = 2
[*.sh]
end_of_line = lf
+66
View File
@@ -0,0 +1,66 @@
###############################################################################
# Set default behavior to automatically normalize line endings.
###############################################################################
* text=auto
###############################################################################
# Set default behavior for command prompt diff.
#
# This is need for earlier builds of msysgit that does not have it on by
# default for csharp files.
# Note: This is only used by command line
###############################################################################
#*.cs diff=csharp
###############################################################################
# Set the merge driver for project and solution files
#
# Merging from the command prompt will add diff markers to the files if there
# are conflicts (Merging from VS is not affected by the settings below, in VS
# the diff markers are never inserted). Diff markers may cause the following
# file extensions to fail to load in VS. An alternative would be to treat
# these files as binary and thus will always conflict and require user
# intervention with every merge. To do so, just uncomment the entries below
###############################################################################
#*.sln merge=binary
#*.csproj merge=binary
#*.vbproj merge=binary
#*.vcxproj merge=binary
#*.vcproj merge=binary
#*.dbproj merge=binary
#*.fsproj merge=binary
#*.lsproj merge=binary
#*.wixproj merge=binary
#*.modelproj merge=binary
#*.sqlproj merge=binary
#*.wwaproj merge=binary
###############################################################################
# behavior for image files
#
# image files are treated as binary by default.
###############################################################################
#*.jpg binary
#*.png binary
#*.gif binary
###############################################################################
# diff behavior for common document formats
#
# Convert binary document formats to text before diffing them. This feature
# is only available from the command line. Turn it on by uncommenting the
# entries below.
###############################################################################
#*.doc diff=astextplain
#*.DOC diff=astextplain
#*.docx diff=astextplain
#*.DOCX diff=astextplain
#*.dot diff=astextplain
#*.DOT diff=astextplain
#*.pdf diff=astextplain
#*.PDF diff=astextplain
#*.rtf diff=astextplain
#*.RTF diff=astextplain
#these files are used in linux, so use just LF
*.sh lf
+34
View File
@@ -0,0 +1,34 @@
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: ''
assignees: ''
---
#### Expected Behavior
<!--- Required. Describe the behavior you expect to see for your case. -->
#### Actual Behavior
<!--- Required. Describe the actual behavior for your case. -->
#### Potential Solution
<!--- Optional. Describe any potential solutions and/or thoughts as to what may be causing the difference between expected and actual behavior. -->
#### Reproducing the Problem
<!--- Required for Bugs. Describe how to reproduce the problem. This can be via a failing unit test or a simplified algorithm that reliably demonstrates this issue. -->
#### System Information
<!--- Required for Bugs. Include any system specific information, such as OS. -->
#### Checklist
<!--- Confirm that you've provided all the required information. -->
<!--- Required fields --->
- [ ] I have completely filled out this template
- [ ] I have confirmed that this issue exists on the current `master` branch
- [ ] I have confirmed that this is not a duplicate issue by searching [issues](https://github.com/QuantConnect/Lean/issues)
<!--- Required for Bugs, feature request can delete the line below. -->
- [ ] I have provided detailed steps to reproduce the issue
<!--- Template inspired by https://github.com/stevemao/github-issue-templates -->
+1
View File
@@ -0,0 +1 @@
blank_issues_enabled: false
+26
View File
@@ -0,0 +1,26 @@
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: ''
assignees: ''
---
#### Expected Behavior
<!--- Required. Describe the behavior you expect to see for your case. -->
#### Actual Behavior
<!--- Required. Describe the actual behavior for your case. -->
#### Potential Solution
<!--- Optional. Describe any potential solutions and/or thoughts as to what may be causing the difference between expected and actual behavior. -->
#### Checklist
<!--- Confirm that you've provided all the required information. -->
<!--- Required fields --->
- [ ] I have completely filled out this template
- [ ] I have confirmed that this issue exists on the current `master` branch
- [ ] I have confirmed that this is not a duplicate issue by searching [issues](https://github.com/QuantConnect/Lean/issues)
<!--- Template inspired by https://github.com/stevemao/github-issue-templates -->
+4
View File
@@ -0,0 +1,4 @@
# These are supported funding model platforms
github: quantconnect
#custom: ['https://github.com/sponsors/QuantConnect']
+42
View File
@@ -0,0 +1,42 @@
<!--- Provide a general summary of your changes in the Title above -->
#### Description
<!--- Describe your changes in detail -->
#### Related Issue
<!--- This project only accepts pull requests related to open issues -->
<!--- If suggesting a new feature or change, please discuss it in an issue first -->
<!--- If fixing a bug, there should be an issue describing it with steps to reproduce -->
<!--- Please link to the issue here: -->
#### Motivation and Context
<!--- Why is this change required? What problem does it solve? -->
#### Requires Documentation Change
<!--- Please indicate if these changes will require updates to documentation, and if so, specify what changes are required -->
#### How Has This Been Tested?
<!--- Please describe in detail how you tested your changes. -->
<!--- Include details of your testing environment, and the tests you ran to -->
<!--- see how your change affects other areas of the code, etc. -->
#### Types of changes
<!--- What types of changes does your code introduce? Put an `x` in all the boxes that apply: -->
- [ ] Bug fix (non-breaking change which fixes an issue)
- [ ] Refactor (non-breaking change which improves implementation)
- [ ] Performance (non-breaking change which improves performance. Please add associated performance test and results)
- [ ] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing functionality to change)
- [ ] Non-functional change (xml comments/documentation/etc)
#### Checklist:
<!--- The following is a checklist of items that MUST be completed before a PR is accepted -->
<!--- If you're unsure about any of these, don't hesitate to ask. We're here to help! -->
- [ ] My code follows the code style of this project.
- [ ] I have read the **CONTRIBUTING** [document](https://github.com/QuantConnect/Lean/blob/master/CONTRIBUTING.md).
- [ ] I have added tests to cover my changes. <!--- If not applicable, please explain why -->
- [ ] All new and existing tests passed.
- [ ] My branch follows the naming convention `bug-<issue#>-<description>` or `feature-<issue#>-<description>`
<!--- Template inspired by https://www.talater.com/open-source-templates/#/page/99 -->
+36
View File
@@ -0,0 +1,36 @@
name: API Tests
on:
push:
branches: ['*']
tags: ['*']
pull_request:
branches: [master]
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
build:
runs-on: self-hosted
container:
image: quantconnect/lean:foundation
options: --cpus 12 --memory 12g
env:
QC_JOB_USER_ID: ${{ secrets.QC_JOB_USER_ID }}
QC_API_ACCESS_TOKEN: ${{ secrets.QC_API_ACCESS_TOKEN }}
QC_JOB_ORGANIZATION_ID: ${{ secrets.QC_JOB_ORGANIZATION_ID }}
# Only run on push events (not on pull_request) for security reasons in order to be able to use secrets
if: ${{ github.event_name == 'push' }}
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Run API Tests
run: |
# Build
dotnet build /p:Configuration=Release /v:quiet /p:WarningLevel=1 QuantConnect.Lean.sln
# Run Projects tests
dotnet test ./Tests/bin/Release/QuantConnect.Tests.dll --blame-hang-timeout 7minutes --blame-crash --logger "console;verbosity=detailed" --filter "FullyQualifiedName=QuantConnect.Tests.API.ProjectTests|FullyQualifiedName=QuantConnect.Tests.API.ObjectStoreTests" -- TestRunParameters.Parameter\(name=\"log-handler\", value=\"ConsoleErrorLogHandler\"\)
+44
View File
@@ -0,0 +1,44 @@
name: Benchmarks
on:
push:
branches: ['*']
tags: ['*']
pull_request:
branches: [master]
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
build:
runs-on: [self-hosted, benchmark]
container:
image: quantconnect/lean:foundation
options: --cpus 12 --memory 12g
volumes:
- /nas:/Data:ro
steps:
- uses: actions/checkout@v2
- name: Checkout Lean Master
uses: actions/checkout@v2
with:
repository: QuantConnect/Lean
path: LeanMaster
ref: 'master'
- name: Build Lean Master
run: dotnet build --verbosity q /p:Configuration=Release /p:WarningLevel=1 LeanMaster/QuantConnect.Lean.sln
- name: Run Benchmarks Master
run: cp run_benchmarks.py LeanMaster/run_benchmarks.py && cd LeanMaster && python run_benchmarks.py /Data && cd ../
- name: Build
run: dotnet build --verbosity q /p:Configuration=Release /p:WarningLevel=1 QuantConnect.Lean.sln
- name: Run Benchmarks
run: python run_benchmarks.py /Data
- name: Compare Benchmarks
run: python compare_benchmarks.py LeanMaster/benchmark_results.json benchmark_results.json
+61
View File
@@ -0,0 +1,61 @@
name: Build & Test Lean
on:
push:
branches: ['*']
tags: ['*']
pull_request:
branches: [master]
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
build:
runs-on: self-hosted
container:
image: quantconnect/lean:foundation
options: --cpus 12 --memory 12g
env:
PYPI_API_TOKEN: ${{ secrets.PYPI_API_TOKEN }}
QC_GIT_TOKEN: ${{ secrets.QC_GIT_TOKEN }}
steps:
- name: Checkout
uses: actions/checkout@v2
with:
fetch-depth: 0 # Ensures we fetch all history
- name: Run build and tests
run: |
# Add exception
git config --global --add safe.directory $GITHUB_WORKSPACE
# Get Last Commit of the Current Tag
TAG_COMMIT=$(git rev-parse HEAD) && echo "CURRENT BRANCH LAST COMMIT $TAG_COMMIT"
# Get Last Commit of the master
MASTER_COMMIT=$(git rev-parse origin/master) && echo "MASTER BRANCH LAST COMMIT $MASTER_COMMIT"
# Build
dotnet build /p:Configuration=Release /v:quiet /p:WarningLevel=1 QuantConnect.Lean.sln
# Run Tests
dotnet test ./Tests/bin/Release/QuantConnect.Tests.dll --blame-hang-timeout 300seconds --blame-crash --filter "TestCategory!=TravisExclude&TestCategory!=ResearchRegressionTests" -- TestRunParameters.Parameter\(name=\"log-handler\", value=\"ConsoleErrorLogHandler\"\)
# Generate & Publish python stubs
echo "GITHUB_REF ${{ github.ref }}"
case "${{ github.ref }}" in
refs/tags/*)
if [ "$TAG_COMMIT" = "$MASTER_COMMIT" ]; then
echo "Generating stubs"
chmod +x ci_build_stubs.sh
export ADDITIONAL_STUBS_REPOS=$(python find_datasource_repos.py) && ./ci_build_stubs.sh -t -g -p
else
echo "Skipping stub generation"
fi
;;
*)
echo "Skipping stub generation"
;;
esac
+24
View File
@@ -0,0 +1,24 @@
name: Rebase Organization Branches
on:
push:
branches:
- 'master'
jobs:
build:
runs-on: self-hosted
container:
image: quantconnect/lean:foundation
options: --cpus 12 --memory 12g
steps:
- uses: actions/checkout@v2
with:
fetch-depth: 0
- name: Rebase Organization Branches
run: |
chmod +x rebase_organization_branches.sh
./rebase_organization_branches.sh
env:
QC_GIT_TOKEN: ${{ secrets.QC_GIT_TOKEN }}
+32
View File
@@ -0,0 +1,32 @@
name: Regression Tests
on:
push:
branches: ['*']
tags: ['*']
pull_request:
branches: [master]
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
build:
runs-on: self-hosted
container:
image: quantconnect/lean:foundation
options: --cpus 12 --memory 12g
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Build
run: dotnet build /p:Configuration=Release /v:quiet /p:WarningLevel=1 QuantConnect.Lean.sln
- name: Run Tests
run: |
dotnet test ./Tests/bin/Release/QuantConnect.Tests.dll \
--filter TestCategory=RegressionTests \
-- TestRunParameters.Parameter\(name=\"log-handler\", value=\"ConsoleErrorLogHandler\"\) \
TestRunParameters.Parameter\(name=\"reduced-disk-size\", value=\"true\"\)
+33
View File
@@ -0,0 +1,33 @@
name: Report Generator Tests
on:
push:
branches: ['*']
tags: ['*']
pull_request:
branches: [master]
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
build:
runs-on: self-hosted
container:
image: quantconnect/lean:foundation
options: --cpus 12 --memory 12g
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Build and Run Report Generator Tests
run: |
# Build
dotnet build /p:Configuration=Release /v:quiet /p:WarningLevel=1 QuantConnect.Lean.sln
# Run Backtest
(cd ./Launcher/bin/Release && dotnet QuantConnect.Lean.Launcher.dll)
# Run Report
(cd ./Report/bin/Release && dotnet ./QuantConnect.Report.dll --backtest-data-source-file ../../../Launcher/bin/Release/BasicTemplateFrameworkAlgorithm.json --close-automatically true)
@@ -0,0 +1,48 @@
name: Research Regression Tests
on:
push:
branches: ['*']
tags: ['*']
pull_request:
branches: [master]
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
build:
runs-on: self-hosted
container:
image: quantconnect/lean:foundation
options: --cpus 12 --memory 12g
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Install Dependencies and Setup Kernel
run: |
# Install dependencies
pip3 install papermill==2.4.0 clr-loader==0.2.9
# Install kernel
dotnet tool install -g --no-cache --version 1.0.661703 \
--add-source 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools/nuget/v3/index.json' \
Microsoft.dotnet-interactive
# Add dotnet tools to Path and activate kernel
export PATH="$HOME/.dotnet/tools:$PATH"
dotnet interactive jupyter install
- name: Build and Run Research Tests
run: |
# Build
export PATH="$HOME/.dotnet/tools:$PATH"
dotnet build /p:Configuration=Release /v:quiet /p:WarningLevel=1 QuantConnect.Lean.sln
# Run Tests
dotnet test ./Tests/bin/Release/QuantConnect.Tests.dll \
--filter TestCategory=ResearchRegressionTests \
-- "TestRunParameters.Parameter(name=\"log-handler\", value=\"ConsoleErrorLogHandler\")" \
"TestRunParameters.Parameter(name=\"reduced-disk-size\", value=\"true\")"
+27
View File
@@ -0,0 +1,27 @@
name: Syntax Tests
on:
push:
branches: ['*']
tags: ['*']
pull_request:
branches: [master]
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
build:
runs-on: self-hosted
container:
image: quantconnect/lean:foundation
options: --cpus 12 --memory 12g
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Run Syntax Test
run: |
pip install --no-cache-dir quantconnect-stubs types-requests==2.32.* types-pytz==2025.2.0.* mypy==2.1.0
python run_syntax_check.py
@@ -0,0 +1,83 @@
name: Python Virtual Environments
on:
push:
branches: ['*']
tags: ['*']
pull_request:
branches: [master]
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
build:
runs-on: self-hosted
container:
image: quantconnect/lean:foundation
options: --cpus 12 --memory 12g
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Run Python Virtual Environments Tests
run: |
# Build
dotnet build /p:Configuration=Release /v:quiet /p:WarningLevel=1 QuantConnect.Lean.sln
# Python Virtual Environment System Packages
python -m venv /lean-testenv --system-site-packages && . /lean-testenv/bin/activate && pip install --no-cache-dir lean==1.0.221 && deactivate
# Run Virtual Environment Test System Packages
dotnet test ./Tests/bin/Release/QuantConnect.Tests.dll --filter "FullyQualifiedName=QuantConnect.Tests.Python.PythonVirtualEnvironmentTests.AssertVirtualEnvironment"
# Python Virtual Environment
rm -rf /lean-testenv && python -m venv /lean-testenv && . /lean-testenv/bin/activate && pip install --no-cache-dir lean==1.0.221 && deactivate
# Run Virtual Environment Test
dotnet test ./Tests/bin/Release/QuantConnect.Tests.dll --filter "FullyQualifiedName=QuantConnect.Tests.Python.PythonVirtualEnvironmentTests.AssertVirtualEnvironment"
# Run Python Package Tests
dotnet test ./Tests/bin/Release/QuantConnect.Tests.dll --filter "FullyQualifiedName=QuantConnect.Tests.Python.PythonPackagesTests" --blame-hang-timeout 120seconds --blame-crash
# Run StableBaselines Python Package Test
dotnet test ./Tests/bin/Release/QuantConnect.Tests.dll --filter "FullyQualifiedName=QuantConnect.Tests.Python.PythonPackagesTests.StableBaselinesTest" --blame-hang-timeout 120seconds --blame-crash
# Run AxPlatform Python Package Test
dotnet test ./Tests/bin/Release/QuantConnect.Tests.dll --filter "FullyQualifiedName=QuantConnect.Tests.Python.PythonPackagesTests.AxPlatformTest" --blame-hang-timeout 120seconds --blame-crash
# Run TensorlyTest Python Package Test
dotnet test ./Tests/bin/Release/QuantConnect.Tests.dll --filter "FullyQualifiedName=QuantConnect.Tests.Python.PythonPackagesTests.TensorlyTest" --blame-hang-timeout 120seconds --blame-crash
# Run NeuralTangents, Ignite Python Package Test
dotnet test ./Tests/bin/Release/QuantConnect.Tests.dll --filter "FullyQualifiedName=QuantConnect.Tests.Python.PythonPackagesTests.IgniteTest" --blame-hang-timeout 120seconds --blame-crash
# Run TensorflowTest
dotnet test ./Tests/bin/Release/QuantConnect.Tests.dll --filter "FullyQualifiedName=QuantConnect.Tests.Python.PythonPackagesTests.TensorflowTest" --blame-hang-timeout 120seconds --blame-crash
# Run TensorflowProbability
dotnet test ./Tests/bin/Release/QuantConnect.Tests.dll --filter "FullyQualifiedName=QuantConnect.Tests.Python.PythonPackagesTests.TensorflowProbabilityTest" --blame-hang-timeout 120seconds --blame-crash
# Run Hvplot Python Package Test
dotnet test ./Tests/bin/Release/QuantConnect.Tests.dll --filter "FullyQualifiedName=QuantConnect.Tests.Python.PythonPackagesTests.RiskparityportfolioTest" --blame-hang-timeout 120seconds --blame-crash
# Run Transformers
dotnet test ./Tests/bin/Release/QuantConnect.Tests.dll --filter "FullyQualifiedName=QuantConnect.Tests.Python.PythonPackagesTests.Transformers" --blame-hang-timeout 120seconds --blame-crash
dotnet test ./Tests/bin/Release/QuantConnect.Tests.dll --filter "FullyQualifiedName=QuantConnect.Tests.Python.PythonPackagesTests.XTransformers" --blame-hang-timeout 120seconds --blame-crash
# Run Shap
dotnet test ./Tests/bin/Release/QuantConnect.Tests.dll --filter "FullyQualifiedName=QuantConnect.Tests.Python.PythonPackagesTests.KerasTest|PyvinecopulibTest" --blame-hang-timeout 120seconds --blame-crash
dotnet test ./Tests/bin/Release/QuantConnect.Tests.dll --filter "FullyQualifiedName=QuantConnect.Tests.Python.PythonPackagesTests.StatsForecast|Mlforecast" --blame-hang-timeout 120seconds --blame-crash
dotnet test ./Tests/bin/Release/QuantConnect.Tests.dll --filter "FullyQualifiedName=QuantConnect.Tests.Python.PythonPackagesTests.MlxtendTest|Thinc" --blame-hang-timeout 120seconds --blame-crash
dotnet test ./Tests/bin/Release/QuantConnect.Tests.dll --filter "FullyQualifiedName=QuantConnect.Tests.Python.PythonPackagesTests.ModuleVersionTestExplicit" --blame-hang-timeout 120seconds --blame-crash
dotnet test ./Tests/bin/Release/QuantConnect.Tests.dll --filter "FullyQualifiedName=QuantConnect.Tests.Python.PythonPackagesTests.Neuralforecast" --blame-hang-timeout 120seconds --blame-crash
dotnet test ./Tests/bin/Release/QuantConnect.Tests.dll --filter "FullyQualifiedName=QuantConnect.Tests.Python.PythonPackagesTests.Tsfel" --blame-hang-timeout 120seconds --blame-crash
dotnet test ./Tests/bin/Release/QuantConnect.Tests.dll --filter "FullyQualifiedName=QuantConnect.Tests.Python.PythonPackagesTests.ScikitOptimizeTest" --blame-hang-timeout 120seconds --blame-crash
+283
View File
@@ -0,0 +1,283 @@
# OS Files
.DS_Store
# Object files
*.o
*.ko
*.obj
*.elf
*.pyc
# Visual Studio Project Items:
*.suo
# Precompiled Headers
*.gch
*.pch
# Libraries
*.lib
*.a
*.la
*.lo
# Shared objects (inc. Windows DLLs)
#*.dll
*.so
*.so.*
*.dylib
# Executables
*/bin/*.exe
*.out
*.app
*.i*86
*.x86_64
*.hex
# QC Cloud Setup Bash Files
*.sh
# Include docker launch scripts for Mac/Linux
!run_docker.sh
!research/run_docker_notebook.sh
# QC Config Files:
# config.json
# QC-C-Specific
*Engine/bin/Debug/cache/data/*.zip
*/obj/*
*/bin/*
*Data/*
*Docker/*
*/Docker/*
*Algorithm.Python/Lib/*
*/[Ee]xtensions/*
!**/Libraries/*
# C Debug Binaries
*.pdb
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
# User-specific files
*.suo
*.user
*.userosscache
*.sln.docstates
*.userprefs
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
.vs/
build/
bld/
[Bb]in/
[Oo]bj/
# Roslyn cache directories
*.ide/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
#NUNIT
*.VisualState.xml
TestResult.xml
# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c
*_i.c
*_p.c
*_i.h
*.ilk
*.meta
*.obj
*.pch
*.pdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*.log
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc
# Chutzpah Test files
_Chutzpah*
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opensdf
*.sdf
*.cachefile
# Visual Studio profiler
*.psess
*.vsp
*.vspx
# TFS 2012 Local Workspace
$tf/
# Guidance Automation Toolkit
*.gpState
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings
*.DotSettings.user
# JustCode is a .NET coding addin-in
.JustCode
# TeamCity is a build add-in
_TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
# NCrunch
_NCrunch_*
.*crunch*.local.xml
# MightyMoose
*.mm.*
AutoTest.Net/
# Web workbench (sass)
.sass-cache/
# Installshield output folder
[Ee]xpress/
# JetBrains Rider
.idea/
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Click-Once directory
publish/
# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
# TODO: Comment the next line if you want to checkin your web deploy settings
# but database connection strings (with potential passwords) will be unencrypted
*.pubxml
*.publishproj
# NuGet Packages
*.nupkg
!LocalPackages/*
# The packages folder can be ignored because of Package Restore
**/packages/*
# except build/, which is used as an MSBuild target.
!**/packages/build/
# If using the old MSBuild-Integrated Package Restore, uncomment this:
#!**/packages/repositories.config
# ignore sln level nuget
.nuget/
!.nuget/NuGet.config
# Windows Azure Build Output
csx/
*.build.csdef
# Windows Store app package directory
AppPackages/
# Others
*.Cache
ClientBin/
[Ss]tyle[Cc]op.*
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.pfx
*.publishsettings
node_modules/
bower_components/
# RIA/Silverlight projects
Generated_Code/
# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
# SQL Server files
*.mdf
*.ldf
# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
# Microsoft Fakes
FakesAssemblies/
# Test Runner
testrunner/
# Meld original diff files
*.orig
# Output chart data
Charts/
# NCrunch files
*.ncrunchsolution
*.ncrunchproject
# QuantConnect plugin files
QuantConnectProjects.xml
Launcher/Plugins/*
/ApiPython/dist
/ApiPython/quantconnect.egg-info
/ApiPython/quantconnect.egg-info/*
QuantConnect.Lean.sln.DotSettings*
#User notebook files
Research/Notebooks
#Docker result files
Results/
QuantConnect.Lean.sln.DotSettings
+23
View File
@@ -0,0 +1,23 @@
language: csharp
mono: none
dotnet: 5.0
os: linux
dist: focal
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
- sudo ln -s $HOME/miniconda3/lib/libpython3.6m.so /usr/lib/libpython3.6m.so
- conda update -y python conda pip
- conda install -y python=3.6.8
- conda install -y numpy=1.18.1
- conda install -y pandas=0.25.3
- conda install -y cython=0.29.15
- conda install -y scipy=1.4.1
- conda install -y wrapt=1.12.1
script:
- dotnet nuget add source $TRAVIS_BUILD_DIR/LocalPackages
- dotnet build /p:Configuration=Release /v:quiet /p:WarningLevel=1 QuantConnect.Lean.sln
- dotnet test ./Tests/bin/Release/QuantConnect.Tests.dll --filter TestCategory!=TravisExclude -- TestRunParameters.Parameter\(name=\"log-handler\", value=\"ConsoleErrorLogHandler\"\)
+11
View File
@@ -0,0 +1,11 @@
{
/*
Recommended VS Code extensions for the LEAN engine
*/
"recommendations": [
"ms-dotnettools.csharp",
"ms-dotnettools.csdevkit",
"ms-vscode-remote.remote-containers",
"ms-python.python"
]
}
+64
View File
@@ -0,0 +1,64 @@
{
/*
VS Code Launch configurations for the LEAN engine
Launch LEAN:
Builds the project and then launches the program using coreclr; supports debugging.
Requires the C# extension from the marketplace.
Run Tests:
Builds and runs tests with an optional filter prompt.
Attach to Python:
Will attempt to attach to LEAN running locally using DebugPy. Requires that the process is
actively running and config is set: "debugging": true, "debugging-method": "DebugPy",
Requires Python extension from the marketplace.
*/
"version": "0.2.0",
"configurations": [
{
"name": "Launch LEAN",
"type": "coreclr",
"request": "launch",
"preLaunchTask": "build",
"program": "${workspaceFolder}/Launcher/bin/Debug/QuantConnect.Lean.Launcher.dll",
"args": [
"--config",
"${workspaceFolder}/Launcher/bin/Debug/config.json"
],
"cwd": "${workspaceFolder}/Launcher/bin/Debug/",
"stopAtEntry": false,
"console": "integratedTerminal",
"internalConsoleOptions": "neverOpen"
},
{
"name": "Run Tests",
"type": "coreclr",
"request": "launch",
"preLaunchTask": "build",
"program": "dotnet",
"args": [
"test",
"${workspaceFolder}/Tests/QuantConnect.Tests.csproj",
"--no-build",
"--filter",
"TestCategory!=TravisExclude&TestCategory!=ResearchRegressionTests"
],
"cwd": "${workspaceFolder}",
"console": "integratedTerminal",
"internalConsoleOptions": "neverOpen"
},
{
"name": "Attach to Python",
"type": "python",
"request": "attach",
"port": 5678,
"pathMappings": [
{
"localRoot": "${workspaceFolder}",
"remoteRoot": "${workspaceFolder}"
}
]
}
]
}
+165
View File
@@ -0,0 +1,165 @@
<h1>Local Development & Docker Integration with Visual Studio Code</h1>
This document contains information regarding ways to use Visual Studio Code to work with the Lean engine, this includes a couple options that make lean easy to develop on any machine:
- Using Lean CLI -> A great tool for working with your algorithms locally, while still being able to deploy to the cloud and have access to Lean data. It is also able to run algorithms locally through our official docker images **Recommended for algorithm development.
- Using a Lean Dev container -> A docker environment with all dependencies pre-installed to allow seamless Lean development across platforms. Great for open source contributors.
- Locally installing all dependencies to run Lean with Visual Studio Code on your OS.
<br />
<h1>Setup</h1>
<h2>Option 1: Lean CLI</h2>
To use Lean CLI follow the instructions for installation and tutorial for usage in our [documentation](https://www.quantconnect.com/docs/v2/lean-cli/key-concepts/getting-started)
<br />
<h2>Option 2: Lean Development Container</h2>
Before anything we need to ensure a few things have been done for either option:
1. Get [Visual Studio Code](https://code.visualstudio.com/download)
- Get [Remote Containers](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers) Extension
2. Get [Docker](https://docs.docker.com/get-docker/):
- Follow the instructions for your Operating System
- New to Docker? Try [docker getting-started](https://docs.docker.com/get-started/)
3. Pull Leans latest research image from a terminal
- `docker pull quantconnect/research:latest`
4. Get Lean into VS Code
- Download the repo or clone it using: `git clone [https://github.com/QuantConnect/Lean](https://github.com/QuantConnect/Lean)`
- Open the folder using VS Code
5. Open Development Container
- In VS Code, either:
- Select "Reopen in Container" from pop up box.
OR
- Ctrl+Shift+P (Command Palette) and select "Remote-Containers: Rebuild and Reopen in Container"
You should now be in the development container, give VS Code a moment to prepare and you will be ready to go!
If you would like to mount any additional local files to your container, checkout [devcontainer.json "mounts" section](https://containers.dev/implementors/json_reference/) for an example! Upon any mount changes you must rebuild the container using Command Palette as in step 5.
<br />
<h2>Option 3: Install Dependencies Locally</h2>
1. Install [.NET 10](https://dotnet.microsoft.com/en-us/download/dotnet/10.0) for the project
2. (Optional) Get [Python 3.11.14](https://www.python.org/downloads/release/python-31114/) for running Python algorithms
- Follow Python instructions [here](https://github.com/QuantConnect/Lean/tree/master/Algorithm.Python#installing-python-311) for your platform
3. Get [Visual Studio Code](https://code.visualstudio.com/download)
- Get the Extension [C#](https://marketplace.visualstudio.com/items?itemName=ms-dotnettools.csharp) for C# Debugging
- Get the Extension [C# Dev Kit](https://marketplace.visualstudio.com/items?itemName=ms-dotnettools.csdevkit) for the .NET Test Explorer and enhanced C# development
- Get the Extension [IntelliCode for C# Dev Kit](https://marketplace.visualstudio.com/items?itemName=ms-dotnettools.vscodeintellicode-csharp) for AI-assisted IntelliSense
- Get the Extension [Python](https://marketplace.visualstudio.com/items?itemName=ms-python.python) for Python Debugging
4. Get Lean into VS Code
- Download the repo or clone it using: `git clone [https://github.com/QuantConnect/Lean](https://github.com/QuantConnect/Lean)`
- Open the folder using VS Code
Your environment is prepared and ready to run Lean.
<br />
<h1>How to use Lean</h1>
This section will cover configuring, building, launching and debugging lean. This is only applicable to option 2 from above. This does not apply to Lean CLI, please refer to [CLI documentation](https://www.quantconnect.com/docs/v2/lean-cli/key-concepts/getting-started)
<br />
<h2>Configuration</h2>
We need to be sure that our Lean configuration at **.\Launcher\config.json** is properly set.
Your configuration file should look something like this for the following languages:
<h3>Python:</h3>
"algorithm-type-name": "**AlgorithmName**",
"algorithm-language": "Python",
"algorithm-location": "../../../Algorithm.Python/**AlgorithmName**.py",
<h3>C#:</h3>
"algorithm-type-name": "**AlgorithmName**",
"algorithm-language": "CSharp",
"algorithm-location": "QuantConnect.Algorithm.CSharp.dll",
<br />
<h2>Building</h2>
Before running Lean, we must build the project. Currently the VS Code task will automatically build before launching. But find more information below about how to trigger building manually.
In VS Code run build task (Ctrl+Shift+B or "Terminal" dropdown); there are a few options:
- __Build__ - basic build task, just builds Lean once
- __Rebuild__ - rebuild task, completely rebuilds the project. Use if having issues with debugging symbols being loaded for your algorithms.
- __Clean__ - deletes out all project build files
- __Test__ - runs the unit tests (requires building first)
**Note:** VS Code will prompt you to install the recommended extensions (C#, C# Dev Kit, Python) when you first open the workspace. You can also install them manually or via the `extensions.json` file.
<br />
<h2>Launching Lean</h2>
Now that lean is configured and built we can launch Lean. Under "Run & Debug" use the launch option "Launch". This will start Lean with C# debugging. Any breakpoints in Lean C# will be triggered.
<br />
<h2>Debugging Python</h2>
Python algorithms require a little extra work in order to be able to debug them. Follow the steps below to get Python debugging working.
<br />
<h3>Modifying the Configuration</h3>
First in order to debug a Python algorithm in VS Code we must make the following change to our configuration (Launcher\config.json) under the comment debugging configuration:
"debugging": true,
"debugging-method": "DebugPy",
In setting this we are telling Lean to expect a debugger connection using Python Tools for Visual Studio Debugger. Once this is set Lean will stop upon initialization and await a connection to the debugger via port 5678.
<br />
<h3>Using VS Code Launch Options to Connect</h3>
Now that Lean is configured for the python debugger we can make use of the programmed launch options to connect to Lean during runtime.
Start Lean using the "Launch" option covered above. Once Lean starts you should see the messages in figure 2 If the message is displayed, use the launch option “Attach to Python”. Then press run, VS Code will now enter and debug any breakpoints you have set in your python algorithm.
<br />
_Figure 2: Python Debugger Messages_
```
20200715 17:12:06.546 Trace:: PythonInitializer.Initialize(): ended
20200715 17:12:06.547 Trace:: DebuggerHelper.Initialize(): python initialization done
20200715 17:12:06.547 Trace:: DebuggerHelper.Initialize(): starting...
20200715 17:12:06.548 Trace:: DebuggerHelper.Initialize(): waiting for debugger to attach at localhost:5678...
```
<br />
<h1>Common Issues</h1>
Here we will cover some common issues with setting this up. This section will expand as we get user feedback!
- The "project file cannot be loaded" and "nuget packages not found" errors occurs when the project files are open by another process in the host. Closing all applications and/or restarting the computer solve the issue.
- Autocomplete and reference finding with omnisharp can sometimes be buggy, if this occurs use the command palette to restart omnisharp. (Ctrl+Shift+P "OmniSharp: Restart OmniSharp")
- Any error messages about building in VSCode that point to comments in JSON. Either select **ignore** or follow steps described [here](https://stackoverflow.com/questions/47834825/in-vs-code-disable-error-comments-are-not-permitted-in-json) to remove the errors entirely.
+28
View File
@@ -0,0 +1,28 @@
{
"files.eol": "\n",
"files.exclude": {
"**/bin": true,
"**/obj": true,
"**/.git": true
},
"search.exclude": {
"**/bin": true,
"**/obj": true
},
"omnisharp.enableRoslynAnalyzers": true,
"omnisharp.enableEditorConfigSupport": true,
"dotnet.defaultSolution": "QuantConnect.Lean.sln",
"editor.formatOnSave": true,
"editor.rulers": [
150
],
"[csharp]": {
"editor.defaultFormatter": "ms-dotnettools.csharp",
"editor.tabSize": 4,
"editor.insertSpaces": true
},
"python.analysis.extraPaths": [
"./Algorithm.Python",
"/opt/miniconda3/lib/python3.11/site-packages",
]
}
+91
View File
@@ -0,0 +1,91 @@
{
/*
VS Code Tasks for the LEAN engine
In order to use the build tasks you need dotnet on your system path.
*/
"version": "2.0.0",
"tasks": [
{
"label": "build",
"type": "shell",
"command": "dotnet",
"args": [
"build",
"${workspaceFolder}/QuantConnect.Lean.sln",
"/p:Configuration=Debug",
"/p:DebugType=portable",
"/p:WarningLevel=1"
],
"group": {
"kind": "build",
"isDefault": true
},
"presentation": {
"reveal": "silent"
},
"problemMatcher": "$msCompile"
},
{
"label": "rebuild",
"type": "shell",
"command": "dotnet",
"args": [
"build",
"${workspaceFolder}/QuantConnect.Lean.sln",
"--no-incremental",
"/p:Configuration=Debug",
"/p:DebugType=portable",
"/p:WarningLevel=1"
],
"group": "build",
"presentation": {
"reveal": "silent"
},
"problemMatcher": "$msCompile"
},
{
"label": "clean",
"type": "shell",
"command": "dotnet",
"args": [
"clean",
"${workspaceFolder}/QuantConnect.Lean.sln"
],
"group": "build",
"presentation": {
"reveal": "silent"
},
"problemMatcher": "$msCompile"
},
{
"label": "test",
"type": "shell",
"command": "dotnet",
"args": [
"test",
"${workspaceFolder}/Tests/QuantConnect.Tests.csproj",
"--no-build"
],
"group": {
"kind": "test",
"isDefault": true
},
"presentation": {
"reveal": "always"
},
"problemMatcher": "$msCompile"
},
{
"label": "start research",
"type": "shell",
"dependsOn": ["build"],
"group": "build",
"isBackground": true,
"command": "${workspaceFolder}/.vscode/launch_research.sh",
"args": [
"${workspaceFolder}/Launcher/bin/Debug"
],
"problemMatcher": "$msCompile"
}
]
}
@@ -0,0 +1,87 @@
/*
* 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 Accord.MachineLearning.VectorMachines.Learning;
using QuantConnect.Indicators;
using System;
namespace QuantConnect.Algorithm.CSharp
{
/// <summary>
/// Machine Learning example using Accord VectorMachines Learning
/// In this example, the algorithm forecasts the direction based on the last 5 days of rate of return
/// </summary>
public class AccordVectorMachinesAlgorithm : QCAlgorithm
{
// Define the size of the data used to train the model
// It will use _lookback sets with _inputSize members
// Those members are rate of return
private const int _lookback = 30;
private const int _inputSize = 5;
private RollingWindow<double> _window = new RollingWindow<double>(_inputSize * _lookback + 2);
public override void Initialize()
{
SetStartDate(2013, 10, 07);
SetEndDate(2013, 10, 11);
SetCash(100000);
var symbol = AddEquity("SPY").Symbol;
ROC(symbol, 1, Resolution.Daily).Updated += (s, e) => _window.Add((double)e.Value);
Schedule.On(DateRules.Every(DayOfWeek.Monday),
TimeRules.AfterMarketOpen(symbol, 10),
TrainAndTrade);
SetWarmUp(_window.Size, Resolution.Daily);
}
private void TrainAndTrade()
{
if (!_window.IsReady) return;
// Convert the rolling window of rate of change into the Learn method
var returns = new double[_inputSize];
var targets = new double[_lookback];
var inputs = new double[_lookback][];
// Use the sign of the returns to predict the direction
for (var i = 0; i < _lookback; i++)
{
for (var j = 0; j < _inputSize; j++)
{
returns[j] = Math.Sign(_window[i + j + 1]);
}
targets[i] = Math.Sign(_window[i]);
inputs[i] = returns;
}
// Train SupportVectorMachine using SetHoldings("SPY", percentage);
var teacher = new LinearCoordinateDescent();
teacher.Learn(inputs, targets);
var svm = teacher.Model;
// Compute the value for the last rate of change
var last = (double) Math.Sign(_window[0]);
var value = svm.Compute(new[] {last});
if (value.IsNaNOrZero()) return;
SetHoldings("SPY", Math.Sign(value));
}
}
}
@@ -0,0 +1,122 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.Collections.Generic;
using QuantConnect.Algorithm.Framework.Alphas;
using QuantConnect.Algorithm.Framework.Execution;
using QuantConnect.Algorithm.Framework.Portfolio;
using QuantConnect.Algorithm.Framework.Selection;
using QuantConnect.Interfaces;
namespace QuantConnect.Algorithm.CSharp
{
/// <summary>
/// Test algorithm using <see cref="AccumulativeInsightPortfolioConstructionModel"/> and <see cref="ConstantAlphaModel"/>
/// generating a constant <see cref="Insight"/> with a 0.25 confidence
/// </summary>
public class AccumulativeInsightPortfolioRegressionAlgorithm : QCAlgorithm, IRegressionAlgorithmDefinition
{
/// <summary>
/// Initialise the data and resolution required, as well as the cash and start-end dates for your algorithm. All algorithms must initialized.
/// </summary>
public override void Initialize()
{
// Set requested data resolution
UniverseSettings.Resolution = Resolution.Minute;
SetStartDate(2013, 10, 07); //Set Start Date
SetEndDate(2013, 10, 11); //Set End Date
SetCash(100000); //Set Strategy Cash
// set algorithm framework models
SetUniverseSelection(new ManualUniverseSelectionModel(QuantConnect.Symbol.Create("SPY", SecurityType.Equity, Market.USA)));
SetAlpha(new ConstantAlphaModel(InsightType.Price, InsightDirection.Up, TimeSpan.FromMinutes(20), 0.025, 0.25));
SetPortfolioConstruction(new AccumulativeInsightPortfolioConstructionModel());
SetExecution(new ImmediateExecutionModel());
}
public override void OnEndOfAlgorithm()
{
if (// holdings value should be 0.03 - to avoid price fluctuation issue we compare with 0.06 and 0.01
Portfolio.TotalHoldingsValue > Portfolio.TotalPortfolioValue * 0.06m
||
Portfolio.TotalHoldingsValue < Portfolio.TotalPortfolioValue * 0.01m)
{
throw new RegressionTestException($"Unexpected Total Holdings Value: {Portfolio.TotalHoldingsValue}");
}
}
/// <summary>
/// This is used by the regression test system to indicate if the open source Lean repository has the required data to run this algorithm.
/// </summary>
public bool CanRunLocally { get; } = true;
/// <summary>
/// This is used by the regression test system to indicate which languages this algorithm is written in.
/// </summary>
public List<Language> Languages { get; } = new() { Language.CSharp, Language.Python };
/// <summary>
/// Data Points count of all timeslices of algorithm
/// </summary>
public long DataPoints => 3943;
/// <summary>
/// Data Points count of the algorithm history
/// </summary>
public int AlgorithmHistoryDataPoints => 0;
/// <summary>
/// Final status of the algorithm
/// </summary>
public AlgorithmStatus AlgorithmStatus => AlgorithmStatus.Completed;
/// <summary>
/// This is used by the regression test system to indicate what the expected statistics are from running the algorithm
/// </summary>
public Dictionary<string, string> ExpectedStatistics => new Dictionary<string, string>
{
{"Total Orders", "199"},
{"Average Win", "0.00%"},
{"Average Loss", "0.00%"},
{"Compounding Annual Return", "-12.611%"},
{"Drawdown", "0.200%"},
{"Expectancy", "-0.585"},
{"Start Equity", "100000"},
{"End Equity", "99827.80"},
{"Net Profit", "-0.172%"},
{"Sharpe Ratio", "-11.13"},
{"Sortino Ratio", "-16.704"},
{"Probabilistic Sharpe Ratio", "10.330%"},
{"Loss Rate", "78%"},
{"Win Rate", "22%"},
{"Profit-Loss Ratio", "0.87"},
{"Alpha", "-0.156"},
{"Beta", "0.035"},
{"Annual Standard Deviation", "0.008"},
{"Annual Variance", "0"},
{"Information Ratio", "-9.603"},
{"Tracking Error", "0.215"},
{"Treynor Ratio", "-2.478"},
{"Total Fees", "$199.00"},
{"Estimated Strategy Capacity", "$26000000.00"},
{"Lowest Capacity Asset", "SPY R735QTJ8XC9X"},
{"Portfolio Turnover", "119.89%"},
{"Drawdown Recovery", "0"},
{"OrderListHash", "d06c26f557b83d8d42ac808fe2815a1e"}
};
}
}
+158
View File
@@ -0,0 +1,158 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.Collections.Generic;
using System.Linq;
using QuantConnect.Algorithm.Framework.Alphas;
using QuantConnect.Algorithm.Framework.Execution;
using QuantConnect.Algorithm.Framework.Portfolio;
using QuantConnect.Algorithm.Framework.Selection;
using QuantConnect.Data;
using QuantConnect.Interfaces;
namespace QuantConnect.Algorithm.CSharp
{
/// <summary>
/// Test algorithm using <see cref="QCAlgorithm.AddAlphaModel(IAlphaModel)"/>
/// </summary>
public class AddAlphaModelAlgorithm : QCAlgorithm, IRegressionAlgorithmDefinition
{
private Symbol _spy;
private Symbol _fb;
private Symbol _ibm;
/// <summary>
/// Initialise the data and resolution required, as well as the cash and start-end dates for your algorithm. All algorithms must initialized.
/// </summary>
public override void Initialize()
{
SetStartDate(2013, 10, 07); //Set Start Date
SetEndDate(2013, 10, 11); //Set End Date
SetCash(100000); //Set Strategy Cash
UniverseSettings.Resolution = Resolution.Daily;
_spy = QuantConnect.Symbol.Create("SPY", SecurityType.Equity, Market.USA);
_fb = QuantConnect.Symbol.Create("FB", SecurityType.Equity, Market.USA);
_ibm = QuantConnect.Symbol.Create("IBM", SecurityType.Equity, Market.USA);
SetUniverseSelection(new ManualUniverseSelectionModel(_spy, _fb, _ibm));
SetPortfolioConstruction(new EqualWeightingPortfolioConstructionModel());
SetExecution(new ImmediateExecutionModel());
AddAlpha(new OneTimeAlphaModel(_spy));
AddAlpha(new OneTimeAlphaModel(_fb));
AddAlpha(new OneTimeAlphaModel(_ibm));
InsightsGenerated += OnInsightsGeneratedVerifier;
}
private void OnInsightsGeneratedVerifier(IAlgorithm algorithm,
GeneratedInsightsCollection insightsCollection)
{
if (insightsCollection.Insights.Count(insight => insight.Symbol == _fb) != 1
|| insightsCollection.Insights.Count(insight => insight.Symbol == _spy) != 1
|| insightsCollection.Insights.Count(insight => insight.Symbol == _ibm) != 1)
{
throw new RegressionTestException("Unexpected insights were emitted");
}
}
private class OneTimeAlphaModel : AlphaModel
{
private readonly Symbol _symbol;
private bool _triggered;
public OneTimeAlphaModel(Symbol symbol)
{
_symbol = symbol;
}
public override IEnumerable<Insight> Update(QCAlgorithm algorithm, Slice data)
{
if (!_triggered)
{
_triggered = true;
yield return Insight.Price(
_symbol,
Resolution.Daily,
1,
InsightDirection.Down
);
}
}
}
/// <summary>
/// This is used by the regression test system to indicate if the open source Lean repository has the required data to run this algorithm.
/// </summary>
public bool CanRunLocally { get; } = true;
/// <summary>
/// This is used by the regression test system to indicate which languages this algorithm is written in.
/// </summary>
public List<Language> Languages { get; } = new() { Language.CSharp, Language.Python };
/// <summary>
/// Data Points count of all timeslices of algorithm
/// </summary>
public long DataPoints => 58;
/// <summary>
/// Data Points count of the algorithm history
/// </summary>
public int AlgorithmHistoryDataPoints => 0;
/// <summary>
/// Final status of the algorithm
/// </summary>
public AlgorithmStatus AlgorithmStatus => AlgorithmStatus.Completed;
/// <summary>
/// This is used by the regression test system to indicate what the expected statistics are from running the algorithm
/// </summary>
public Dictionary<string, string> ExpectedStatistics => new Dictionary<string, string>
{
{"Total Orders", "9"},
{"Average Win", "0.86%"},
{"Average Loss", "-0.27%"},
{"Compounding Annual Return", "206.404%"},
{"Drawdown", "1.700%"},
{"Expectancy", "1.781"},
{"Start Equity", "100000"},
{"End Equity", "101441.92"},
{"Net Profit", "1.442%"},
{"Sharpe Ratio", "4.836"},
{"Sortino Ratio", "10.481"},
{"Probabilistic Sharpe Ratio", "59.374%"},
{"Loss Rate", "33%"},
{"Win Rate", "67%"},
{"Profit-Loss Ratio", "3.17"},
{"Alpha", "4.164"},
{"Beta", "-1.322"},
{"Annual Standard Deviation", "0.321"},
{"Annual Variance", "0.103"},
{"Information Ratio", "-0.795"},
{"Tracking Error", "0.532"},
{"Treynor Ratio", "-1.174"},
{"Total Fees", "$14.78"},
{"Estimated Strategy Capacity", "$120000000.00"},
{"Lowest Capacity Asset", "IBM R735QTJ8XC9X"},
{"Portfolio Turnover", "41.18%"},
{"Drawdown Recovery", "0"},
{"OrderListHash", "713c956deb193bed2290e9f379c0f9f9"}
};
}
}
@@ -0,0 +1,137 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.Linq;
using QuantConnect.Data;
using QuantConnect.Interfaces;
using System.Collections.Generic;
namespace QuantConnect.Algorithm.CSharp
{
/// <summary>
/// Regression algorithm reproducing GH issue #5748 where in some cases an option underlying symbol was not being
/// removed from all universes it was hold
/// </summary>
public class AddAndRemoveOptionContractRegressionAlgorithm : QCAlgorithm, IRegressionAlgorithmDefinition
{
private Symbol _contract;
private bool _hasRemoved;
public override void Initialize()
{
SetStartDate(2014, 06, 06);
SetEndDate(2014, 06, 09);
UniverseSettings.DataNormalizationMode = DataNormalizationMode.Raw;
UniverseSettings.MinimumTimeInUniverse = TimeSpan.Zero;
var aapl = QuantConnect.Symbol.Create("AAPL", SecurityType.Equity, Market.USA);
_contract = OptionChain(aapl)
.OrderBy(symbol => symbol.ID.OptionRight)
.ThenBy(symbol => symbol.ID.StrikePrice)
.ThenBy(symbol => symbol.ID.Date)
.ThenBy(symbol => symbol.ID)
.FirstOrDefault(optionContract => optionContract.ID.OptionRight == OptionRight.Call);
AddOptionContract(_contract);
}
public override void OnData(Slice slice)
{
if (slice.HasData)
{
if (!_hasRemoved)
{
RemoveOptionContract(_contract);
RemoveSecurity(_contract.Underlying);
_hasRemoved = true;
}
else
{
throw new RegressionTestException("Expect a single call to OnData where we removed the option and underlying");
}
}
}
public override void OnEndOfAlgorithm()
{
if (!_hasRemoved)
{
throw new RegressionTestException("Expect a single call to OnData where we removed the option and underlying");
}
}
/// <summary>
/// This is used by the regression test system to indicate if the open source Lean repository has the required data to run this algorithm.
/// </summary>
public bool CanRunLocally { get; } = true;
/// <summary>
/// This is used by the regression test system to indicate which languages this algorithm is written in.
/// </summary>
public List<Language> Languages { get; } = new() { Language.CSharp };
/// <summary>
/// Data Points count of all timeslices of algorithm
/// </summary>
public long DataPoints => 26;
/// <summary>
/// Data Points count of the algorithm history
/// </summary>
public int AlgorithmHistoryDataPoints => 1;
/// <summary>
/// Final status of the algorithm
/// </summary>
public AlgorithmStatus AlgorithmStatus => AlgorithmStatus.Completed;
/// <summary>
/// This is used by the regression test system to indicate what the expected statistics are from running the algorithm
/// </summary>
public Dictionary<string, string> ExpectedStatistics => new Dictionary<string, string>
{
{"Total Orders", "0"},
{"Average Win", "0%"},
{"Average Loss", "0%"},
{"Compounding Annual Return", "0%"},
{"Drawdown", "0%"},
{"Expectancy", "0"},
{"Start Equity", "100000"},
{"End Equity", "100000"},
{"Net Profit", "0%"},
{"Sharpe Ratio", "0"},
{"Sortino Ratio", "0"},
{"Probabilistic Sharpe Ratio", "0%"},
{"Loss Rate", "0%"},
{"Win Rate", "0%"},
{"Profit-Loss Ratio", "0"},
{"Alpha", "0"},
{"Beta", "0"},
{"Annual Standard Deviation", "0"},
{"Annual Variance", "0"},
{"Information Ratio", "-9.486"},
{"Tracking Error", "0.008"},
{"Treynor Ratio", "0"},
{"Total Fees", "$0.00"},
{"Estimated Strategy Capacity", "$0"},
{"Lowest Capacity Asset", ""},
{"Portfolio Turnover", "0%"},
{"Drawdown Recovery", "0"},
{"OrderListHash", "d41d8cd98f00b204e9800998ecf8427e"}
};
}
}
@@ -0,0 +1,132 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.Linq;
using QuantConnect.Data;
using QuantConnect.Interfaces;
using System.Collections.Generic;
namespace QuantConnect.Algorithm.CSharp
{
/// <summary>
/// Regression algorithm reproducing GH issue #5971 where we add and remove an option in the same loop
/// </summary>
public class AddAndRemoveSecuritySameLoopRegressionAlgorithm : QCAlgorithm, IRegressionAlgorithmDefinition
{
private Symbol _contract;
private bool _hasRemoved;
public override void Initialize()
{
SetStartDate(2014, 06, 06);
SetEndDate(2014, 06, 09);
UniverseSettings.DataNormalizationMode = DataNormalizationMode.Raw;
UniverseSettings.MinimumTimeInUniverse = TimeSpan.Zero;
var aapl = AddEquity("AAPL").Symbol;
_contract = OptionChain(aapl)
.OrderBy(x => x.ID.Symbol)
.FirstOrDefault(optionContract => optionContract.ID.OptionRight == OptionRight.Call
&& optionContract.ID.OptionStyle == OptionStyle.American);
}
public override void OnData(Slice slice)
{
if (_hasRemoved)
{
throw new RegressionTestException("Expect a single call to OnData where we removed the option and underlying");
}
_hasRemoved = true;
AddOptionContract(_contract);
// changed my mind!
RemoveOptionContract(_contract);
RemoveSecurity(_contract.Underlying);
RemoveSecurity(AddEquity("SPY", Resolution.Daily).Symbol);
}
public override void OnEndOfAlgorithm()
{
if (!_hasRemoved)
{
throw new RegressionTestException("We did not remove the option contract!");
}
}
/// <summary>
/// This is used by the regression test system to indicate if the open source Lean repository has the required data to run this algorithm.
/// </summary>
public bool CanRunLocally { get; } = true;
/// <summary>
/// This is used by the regression test system to indicate which languages this algorithm is written in.
/// </summary>
public List<Language> Languages { get; } = new() { Language.CSharp };
/// <summary>
/// Data Points count of all timeslices of algorithm
/// </summary>
public long DataPoints => 25;
/// <summary>
/// Data Points count of the algorithm history
/// </summary>
public int AlgorithmHistoryDataPoints => 1;
/// <summary>
/// Final status of the algorithm
/// </summary>
public AlgorithmStatus AlgorithmStatus => AlgorithmStatus.Completed;
/// <summary>
/// This is used by the regression test system to indicate what the expected statistics are from running the algorithm
/// </summary>
public Dictionary<string, string> ExpectedStatistics => new Dictionary<string, string>
{
{"Total Orders", "0"},
{"Average Win", "0%"},
{"Average Loss", "0%"},
{"Compounding Annual Return", "0%"},
{"Drawdown", "0%"},
{"Expectancy", "0"},
{"Start Equity", "100000"},
{"End Equity", "100000"},
{"Net Profit", "0%"},
{"Sharpe Ratio", "0"},
{"Sortino Ratio", "0"},
{"Probabilistic Sharpe Ratio", "0%"},
{"Loss Rate", "0%"},
{"Win Rate", "0%"},
{"Profit-Loss Ratio", "0"},
{"Alpha", "0"},
{"Beta", "0"},
{"Annual Standard Deviation", "0"},
{"Annual Variance", "0"},
{"Information Ratio", "-9.486"},
{"Tracking Error", "0.008"},
{"Treynor Ratio", "0"},
{"Total Fees", "$0.00"},
{"Estimated Strategy Capacity", "$0"},
{"Lowest Capacity Asset", ""},
{"Portfolio Turnover", "0%"},
{"Drawdown Recovery", "0"},
{"OrderListHash", "d41d8cd98f00b204e9800998ecf8427e"}
};
}
}
@@ -0,0 +1,152 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.Collections.Generic;
using QuantConnect.Data;
using QuantConnect.Indicators;
using QuantConnect.Interfaces;
using QuantConnect.Orders;
using QuantConnect.Brokerages;
namespace QuantConnect.Algorithm.CSharp
{
/// <summary>
/// Regression test to explain how Beta indicator works
/// </summary>
public class AddBetaIndicatorNewAssetsRegressionAlgorithm : QCAlgorithm, IRegressionAlgorithmDefinition
{
private Beta _beta;
private SimpleMovingAverage _sma;
private decimal _lastSMAValue;
public override void Initialize()
{
SetStartDate(2015, 05, 08);
SetEndDate(2017, 06, 15);
SetCash(10000);
AddCrypto("BTCUSD", Resolution.Daily);
AddEquity("SPY", Resolution.Daily);
EnableAutomaticIndicatorWarmUp = true;
_beta = B("BTCUSD", "SPY", 3, Resolution.Daily);
_sma = SMA("SPY", 3, Resolution.Daily);
_lastSMAValue = 0;
if (!_beta.IsReady)
{
throw new RegressionTestException("Beta indicator was expected to be ready");
}
}
public override void OnData(Slice slice)
{
var price = Securities["BTCUSD"].Price;
if (!Portfolio.Invested)
{
var quantityToBuy = (int)(Portfolio.Cash * 0.05m / price);
Buy("BTCUSD", quantityToBuy);
}
if (Math.Abs(_beta.Current.Value) > 2)
{
Liquidate("BTCUSD");
Log("Liquidated BTCUSD due to high Beta");
}
Log($"Beta between BTCUSD and SPY is: {_beta.Current.Value}");
}
public override void OnOrderEvent(OrderEvent orderEvent)
{
var order = Transactions.GetOrderById(orderEvent.OrderId);
var goUpwards = _lastSMAValue < _sma.Current.Value;
_lastSMAValue = _sma.Current.Value;
if (order.Status == OrderStatus.Filled)
{
if (order.Type == OrderType.Limit && Math.Abs(_beta.Current.Value - 1) < 0.2m && goUpwards)
{
Transactions.CancelOpenOrders(order.Symbol);
}
}
if (order.Status == OrderStatus.Canceled)
{
Log(orderEvent.ToString());
}
}
public bool CanRunLocally { get; } = true;
/// <summary>
/// This is used by the regression test system to indicate which languages this algorithm is written in.
/// </summary>
public virtual List<Language> Languages { get; } = new() { Language.CSharp };
/// <summary>
/// Data Points count of all timeslices of algorithm
/// </summary>
public long DataPoints => 5798;
/// <summary>
/// Data Points count of the algorithm history
/// </summary>
public int AlgorithmHistoryDataPoints => 26;
/// <summary>
/// Final status of the algorithm
/// </summary>
public AlgorithmStatus AlgorithmStatus => AlgorithmStatus.Completed;
/// <summary>
/// This is used by the regression test system to indicate what the expected statistics are from running the algorithm
/// </summary>
public Dictionary<string, string> ExpectedStatistics => new Dictionary<string, string>
{
{"Total Orders", "327"},
{"Average Win", "0.32%"},
{"Average Loss", "-0.02%"},
{"Compounding Annual Return", "1.274%"},
{"Drawdown", "1.100%"},
{"Expectancy", "0.904"},
{"Start Equity", "10000.00"},
{"End Equity", "10270.95"},
{"Net Profit", "2.710%"},
{"Sharpe Ratio", "-0.126"},
{"Sortino Ratio", "-0.112"},
{"Probabilistic Sharpe Ratio", "2.398%"},
{"Loss Rate", "90%"},
{"Win Rate", "10%"},
{"Profit-Loss Ratio", "17.14"},
{"Alpha", "-0.002"},
{"Beta", "0.004"},
{"Annual Standard Deviation", "0.01"},
{"Annual Variance", "0"},
{"Information Ratio", "-0.536"},
{"Tracking Error", "0.111"},
{"Treynor Ratio", "-0.335"},
{"Total Fees", "$0.00"},
{"Estimated Strategy Capacity", "$100000.00"},
{"Lowest Capacity Asset", "BTCUSD 2XR"},
{"Portfolio Turnover", "1.69%"},
{"Drawdown Recovery", "104"},
{"OrderListHash", "52a71939d45d41e0c585301b2ae71f21"}
};
}
}
@@ -0,0 +1,152 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.Collections.Generic;
using QuantConnect.Data;
using QuantConnect.Indicators;
using QuantConnect.Interfaces;
using QuantConnect.Orders;
namespace QuantConnect.Algorithm.CSharp
{
/// <summary>
/// Regression test to explain how Beta indicator works
/// </summary>
public class AddBetaIndicatorRegressionAlgorithm : QCAlgorithm, IRegressionAlgorithmDefinition
{
private Beta _beta;
private SimpleMovingAverage _sma;
private decimal _lastSMAValue;
public override void Initialize()
{
SetStartDate(2013, 10, 07);
SetEndDate(2013, 10, 15);
SetCash(10000);
AddEquity("IBM");
AddEquity("SPY");
EnableAutomaticIndicatorWarmUp = true;
_beta = B("IBM", "SPY", 3, Resolution.Daily);
_sma = SMA("SPY", 3, Resolution.Daily);
_lastSMAValue = 0;
if (!_beta.IsReady)
{
throw new RegressionTestException("Beta indicator was expected to be ready");
}
}
public override void OnData(Slice slice)
{
if (!Portfolio.Invested)
{
var price = slice["IBM"].Close;
Buy("IBM", 10);
LimitOrder("IBM", 10, price * 0.1m);
StopMarketOrder("IBM", 10, price / 0.1m);
}
if (_beta.Current.Value < 0m || _beta.Current.Value > 2.80m)
{
throw new RegressionTestException($"_beta value was expected to be between 0 and 2.80 but was {_beta.Current.Value}");
}
Log($"Beta between IBM and SPY is: {_beta.Current.Value}");
}
public override void OnOrderEvent(OrderEvent orderEvent)
{
var order = Transactions.GetOrderById(orderEvent.OrderId);
var goUpwards = _lastSMAValue < _sma.Current.Value;
_lastSMAValue = _sma.Current.Value;
if (order.Status == OrderStatus.Filled)
{
if (order.Type == OrderType.Limit && Math.Abs(_beta.Current.Value - 1) < 0.2m && goUpwards)
{
Transactions.CancelOpenOrders(order.Symbol);
}
}
if (order.Status == OrderStatus.Canceled)
{
Log(orderEvent.ToString());
}
}
/// <summary>
/// This is used by the regression test system to indicate if the open source Lean repository has the required data to run this algorithm.
/// </summary>
public bool CanRunLocally { get; } = true;
/// <summary>
/// This is used by the regression test system to indicate which languages this algorithm is written in.
/// </summary>
public virtual List<Language> Languages { get; } = new() { Language.CSharp };
/// <summary>
/// Data Points count of all timeslices of algorithm
/// </summary>
public long DataPoints => 10977;
/// <summary>
/// Data Points count of the algorithm history
/// </summary>
public int AlgorithmHistoryDataPoints => 11;
/// <summary>
/// Final status of the algorithm
/// </summary>
public AlgorithmStatus AlgorithmStatus => AlgorithmStatus.Completed;
/// <summary>
/// This is used by the regression test system to indicate what the expected statistics are from running the algorithm
/// </summary>
public Dictionary<string, string> ExpectedStatistics => new Dictionary<string, string>
{
{"Total Orders", "3"},
{"Average Win", "0%"},
{"Average Loss", "0%"},
{"Compounding Annual Return", "12.939%"},
{"Drawdown", "0.300%"},
{"Expectancy", "0"},
{"Start Equity", "10000"},
{"End Equity", "10028.93"},
{"Net Profit", "0.289%"},
{"Sharpe Ratio", "3.924"},
{"Sortino Ratio", "0"},
{"Probabilistic Sharpe Ratio", "66.659%"},
{"Loss Rate", "0%"},
{"Win Rate", "0%"},
{"Profit-Loss Ratio", "0"},
{"Alpha", "0.028"},
{"Beta", "0.122"},
{"Annual Standard Deviation", "0.024"},
{"Annual Variance", "0.001"},
{"Information Ratio", "-3.181"},
{"Tracking Error", "0.142"},
{"Treynor Ratio", "0.78"},
{"Total Fees", "$1.00"},
{"Estimated Strategy Capacity", "$35000000.00"},
{"Lowest Capacity Asset", "IBM R735QTJ8XC9X"},
{"Portfolio Turnover", "1.51%"},
{"Drawdown Recovery", "2"},
{"OrderListHash", "1db1ce949db995bba20ed96ea5e2438a"}
};
}
}
@@ -0,0 +1,165 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.Linq;
using QuantConnect.Data;
using QuantConnect.Orders;
using QuantConnect.Interfaces;
using QuantConnect.Securities;
using System.Collections.Generic;
using QuantConnect.Securities.Future;
using QuantConnect.Data.UniverseSelection;
namespace QuantConnect.Algorithm.CSharp
{
/// <summary>
/// Continuous Futures Regression algorithm. Asserting and showcasing the behavior of adding a continuous future
/// and a future contract at the same time
/// </summary>
public class AddFutureContractWithContinuousRegressionAlgorithm : QCAlgorithm, IRegressionAlgorithmDefinition
{
private Future _continuousContract;
private Future _futureContract;
private bool _ended;
/// <summary>
/// Initialise the data and resolution required, as well as the cash and start-end dates for your algorithm. All algorithms must initialized.
/// </summary>
public override void Initialize()
{
SetStartDate(2013, 10, 6);
SetEndDate(2013, 10, 10);
_continuousContract = AddFuture(Futures.Indices.SP500EMini,
dataNormalizationMode: DataNormalizationMode.BackwardsRatio,
dataMappingMode: DataMappingMode.LastTradingDay,
contractDepthOffset: 0
);
_futureContract = AddFutureContract(FuturesChain(_continuousContract.Symbol).First());
}
/// <summary>
/// OnData event is the primary entry point for your algorithm. Each new data point will be pumped in here.
/// </summary>
/// <param name="slice">Slice object keyed by symbol containing the stock data</param>
public override void OnData(Slice slice)
{
if (_ended)
{
throw new RegressionTestException($"Algorithm should of ended!");
}
if (slice.Keys.Count > 2)
{
throw new RegressionTestException($"Getting data for more than 2 symbols! {string.Join(",", slice.Keys.Select(symbol => symbol))}");
}
if (UniverseManager.Count != 3)
{
throw new RegressionTestException($"Expecting 3 universes (chain, continuous and user defined) but have {UniverseManager.Count}");
}
if (!Portfolio.Invested)
{
Buy(_futureContract.Symbol, 1);
Buy(_continuousContract.Mapped, 1);
RemoveSecurity(_futureContract.Symbol);
RemoveSecurity(_continuousContract.Symbol);
_ended = true;
}
}
public override void OnOrderEvent(OrderEvent orderEvent)
{
if (orderEvent.Status == OrderStatus.Filled)
{
Log($"{orderEvent}");
}
}
public override void OnSecuritiesChanged(SecurityChanges changes)
{
Debug($"{Time}-{changes}");
if (changes.AddedSecurities.Any(security => security.Symbol != _continuousContract.Symbol && security.Symbol != _futureContract.Symbol)
|| changes.RemovedSecurities.Any(security => security.Symbol != _continuousContract.Symbol && security.Symbol != _futureContract.Symbol))
{
throw new RegressionTestException($"We got an unexpected security changes {changes}");
}
}
/// <summary>
/// This is used by the regression test system to indicate if the open source Lean repository has the required data to run this algorithm.
/// </summary>
public bool CanRunLocally { get; } = true;
/// <summary>
/// This is used by the regression test system to indicate which languages this algorithm is written in.
/// </summary>
public List<Language> Languages { get; } = new() { Language.CSharp };
/// <summary>
/// Data Points count of all timeslices of algorithm
/// </summary>
public long DataPoints => 61;
/// <summary>
/// Data Points count of the algorithm history
/// </summary>
public int AlgorithmHistoryDataPoints => 1;
/// <summary>
/// Final status of the algorithm
/// </summary>
public AlgorithmStatus AlgorithmStatus => AlgorithmStatus.Completed;
/// <summary>
/// This is used by the regression test system to indicate what the expected statistics are from running the algorithm
/// </summary>
public Dictionary<string, string> ExpectedStatistics => new Dictionary<string, string>
{
{"Total Orders", "4"},
{"Average Win", "0%"},
{"Average Loss", "-0.10%"},
{"Compounding Annual Return", "-14.232%"},
{"Drawdown", "0.200%"},
{"Expectancy", "-1"},
{"Start Equity", "100000"},
{"End Equity", "99803.9"},
{"Net Profit", "-0.196%"},
{"Sharpe Ratio", "-7.95"},
{"Sortino Ratio", "0"},
{"Probabilistic Sharpe Ratio", "0.401%"},
{"Loss Rate", "100%"},
{"Win Rate", "0%"},
{"Profit-Loss Ratio", "0"},
{"Alpha", "-0.128"},
{"Beta", "0.026"},
{"Annual Standard Deviation", "0.016"},
{"Annual Variance", "0"},
{"Information Ratio", "-1.186"},
{"Tracking Error", "0.237"},
{"Treynor Ratio", "-4.747"},
{"Total Fees", "$8.60"},
{"Estimated Strategy Capacity", "$2000.00"},
{"Lowest Capacity Asset", "ES VU1EHIDJYLMP"},
{"Portfolio Turnover", "66.50%"},
{"Drawdown Recovery", "0"},
{"OrderListHash", "4720516462fcabb4db1aead46051cb4a"}
};
}
}
@@ -0,0 +1,214 @@
/*
* 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.Data.Market;
using QuantConnect.Interfaces;
using QuantConnect.Securities;
namespace QuantConnect.Algorithm.CSharp
{
/// <summary>
/// This regression algorithm tests that we receive the expected data when
/// we add future option contracts individually using <see cref="AddFutureOptionContract"/>
/// </summary>
public class AddFutureOptionContractDataStreamingRegressionAlgorithm : QCAlgorithm, IRegressionAlgorithmDefinition
{
private bool _onDataReached;
private bool _invested;
private Symbol _es20h20;
private Symbol _es19m20;
private readonly HashSet<Symbol> _symbolsReceived = new HashSet<Symbol>();
private readonly HashSet<Symbol> _expectedSymbolsReceived = new HashSet<Symbol>();
private readonly Dictionary<Symbol, List<QuoteBar>> _dataReceived = new Dictionary<Symbol, List<QuoteBar>>();
public override void Initialize()
{
SetStartDate(2020, 1, 4);
SetEndDate(2020, 1, 8);
_es20h20 = AddFutureContract(
QuantConnect.Symbol.CreateFuture(Futures.Indices.SP500EMini, Market.CME, new DateTime(2020, 3, 20)),
Resolution.Minute).Symbol;
_es19m20 = AddFutureContract(
QuantConnect.Symbol.CreateFuture(Futures.Indices.SP500EMini, Market.CME, new DateTime(2020, 6, 19)),
Resolution.Minute).Symbol;
// Get option contract lists for 2020/01/05 (Time.AddDays(1)) because Lean has local data for that date
var optionChains = OptionChainProvider.GetOptionContractList(_es20h20, Time.AddDays(1))
.Concat(OptionChainProvider.GetOptionContractList(_es19m20, Time.AddDays(1)));
foreach (var optionContract in optionChains)
{
_expectedSymbolsReceived.Add(AddFutureOptionContract(optionContract, Resolution.Minute).Symbol);
}
if (_expectedSymbolsReceived.Count == 0)
{
throw new InvalidOperationException("Expected Symbols receive count is 0, expected >0");
}
}
public override void OnData(Slice slice)
{
if (!slice.HasData)
{
return;
}
_onDataReached = true;
var hasOptionQuoteBars = false;
foreach (var qb in slice.QuoteBars.Values)
{
if (qb.Symbol.SecurityType != SecurityType.FutureOption)
{
continue;
}
hasOptionQuoteBars = true;
_symbolsReceived.Add(qb.Symbol);
if (!_dataReceived.ContainsKey(qb.Symbol))
{
_dataReceived[qb.Symbol] = new List<QuoteBar>();
}
_dataReceived[qb.Symbol].Add(qb);
}
if (_invested || !hasOptionQuoteBars)
{
return;
}
if (slice.ContainsKey(_es20h20) && slice.ContainsKey(_es19m20))
{
SetHoldings(_es20h20, 0.2);
SetHoldings(_es19m20, 0.2);
_invested = true;
}
}
public override void OnEndOfAlgorithm()
{
base.OnEndOfAlgorithm();
if (!_onDataReached)
{
throw new RegressionTestException("OnData() was never called.");
}
if (_symbolsReceived.Count != _expectedSymbolsReceived.Count)
{
throw new AggregateException($"Expected {_expectedSymbolsReceived.Count} option contracts Symbols, found {_symbolsReceived.Count}");
}
var missingSymbols = new List<Symbol>();
foreach (var expectedSymbol in _expectedSymbolsReceived)
{
if (!_symbolsReceived.Contains(expectedSymbol))
{
missingSymbols.Add(expectedSymbol);
}
}
if (missingSymbols.Count > 0)
{
throw new RegressionTestException($"Symbols: \"{string.Join(", ", missingSymbols)}\" were not found in OnData");
}
foreach (var expectedSymbol in _expectedSymbolsReceived)
{
var data = _dataReceived[expectedSymbol];
var nonDupeDataCount = data.Select(x =>
{
x.EndTime = default(DateTime);
return x;
}).Distinct().Count();
if (nonDupeDataCount < 1000)
{
throw new RegressionTestException($"Received too few data points. Expected >=1000, found {nonDupeDataCount} for {expectedSymbol}");
}
}
}
/// <summary>
/// This is used by the regression test system to indicate if the open source Lean repository has the required data to run this algorithm.
/// </summary>
public bool CanRunLocally { get; } = true;
/// <summary>
/// This is used by the regression test system to indicate which languages this algorithm is written in.
/// </summary>
public List<Language> Languages { get; } = new() { Language.CSharp, Language.Python };
/// <summary>
/// Data Points count of all timeslices of algorithm
/// </summary>
public long DataPoints => 311881;
/// <summary>
/// Data Points count of the algorithm history
/// </summary>
public int AlgorithmHistoryDataPoints => 2;
/// <summary>
/// Final status of the algorithm
/// </summary>
public AlgorithmStatus AlgorithmStatus => AlgorithmStatus.Completed;
/// <summary>
/// This is used by the regression test system to indicate what the expected statistics are from running the algorithm
/// </summary>
public Dictionary<string, string> ExpectedStatistics => new Dictionary<string, string>
{
{"Total Orders", "2"},
{"Average Win", "0%"},
{"Average Loss", "0%"},
{"Compounding Annual Return", "5512.811%"},
{"Drawdown", "1.000%"},
{"Expectancy", "0"},
{"Start Equity", "100000"},
{"End Equity", "105332.8"},
{"Net Profit", "5.333%"},
{"Sharpe Ratio", "64.084"},
{"Sortino Ratio", "0"},
{"Probabilistic Sharpe Ratio", "95.688%"},
{"Loss Rate", "0%"},
{"Win Rate", "0%"},
{"Profit-Loss Ratio", "0"},
{"Alpha", "25.763"},
{"Beta", "2.914"},
{"Annual Standard Deviation", "0.423"},
{"Annual Variance", "0.179"},
{"Information Ratio", "66.11"},
{"Tracking Error", "0.403"},
{"Treynor Ratio", "9.308"},
{"Total Fees", "$8.60"},
{"Estimated Strategy Capacity", "$22000000.00"},
{"Lowest Capacity Asset", "ES XFH59UK0MYO1"},
{"Portfolio Turnover", "122.11%"},
{"Drawdown Recovery", "0"},
{"OrderListHash", "d744fa8beaa60546c84924ed68d945d9"}
};
}
}
@@ -0,0 +1,143 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using QuantConnect.Data;
using QuantConnect.Interfaces;
using QuantConnect.Securities;
using System.Collections.Generic;
using System.Linq;
namespace QuantConnect.Algorithm.CSharp
{
/// <summary>
/// This regression algorithm tests we can add future option contracts from contracts in the future chain
/// </summary>
public class AddFutureOptionContractFromFutureChainRegressionAlgorithm : QCAlgorithm, IRegressionAlgorithmDefinition
{
private bool _addedOptions;
public override void Initialize()
{
SetStartDate(2020, 1, 4);
SetEndDate(2020, 1, 6);
var es = AddFuture(Futures.Indices.SP500EMini, Resolution.Minute, Market.CME);
es.SetFilter((futureFilter) =>
{
return futureFilter.Expiration(0, 365).ExpirationCycle(new[] { 3, 6 });
});
}
public override void OnData(Slice slice)
{
if (!_addedOptions)
{
_addedOptions = true;
foreach (var futuresContracts in slice.FutureChains.Values)
{
foreach (var contract in futuresContracts)
{
var option_contract_symbols = OptionChain(contract.Symbol).ToList();
if(option_contract_symbols.Count == 0)
{
continue;
}
foreach (var option_contract_symbol in option_contract_symbols.OrderBy(x => x.ID.Date)
.ThenBy(x => x.ID.StrikePrice)
.ThenBy(x => x.ID.OptionRight).Take(5))
{
AddOptionContract(option_contract_symbol);
}
}
}
}
if (Portfolio.Invested)
{
return;
}
foreach (var chain in slice.OptionChains.Values)
{
foreach (var option in chain.Contracts.Keys)
{
MarketOrder(option, 1);
MarketOrder(option.Underlying, 1);
}
}
}
/// <summary>
/// This is used by the regression test system to indicate if the open source Lean repository has the required data to run this algorithm.
/// </summary>
public bool CanRunLocally { get; } = true;
/// <summary>
/// This is used by the regression test system to indicate which languages this algorithm is written in.
/// </summary>
public List<Language> Languages { get; } = new() { Language.CSharp };
/// <summary>
/// Data Points count of all timeslices of algorithm
/// </summary>
public long DataPoints => 9922;
/// <summary>
/// Data Points count of the algorithm history
/// </summary>
public int AlgorithmHistoryDataPoints => 2;
/// <summary>
/// Final status of the algorithm
/// </summary>
public AlgorithmStatus AlgorithmStatus => AlgorithmStatus.Completed;
/// <summary>
/// This is used by the regression test system to indicate what the expected statistics are from running the algorithm
/// </summary>
public Dictionary<string, string> ExpectedStatistics => new Dictionary<string, string>
{
{"Total Orders", "20"},
{"Average Win", "0%"},
{"Average Loss", "0%"},
{"Compounding Annual Return", "88398927.578%"},
{"Drawdown", "5.200%"},
{"Expectancy", "0"},
{"Start Equity", "100000"},
{"End Equity", "111911.55"},
{"Net Profit", "11.912%"},
{"Sharpe Ratio", "1604181.904"},
{"Sortino Ratio", "0"},
{"Probabilistic Sharpe Ratio", "0%"},
{"Loss Rate", "0%"},
{"Win Rate", "0%"},
{"Profit-Loss Ratio", "0"},
{"Alpha", "2144882.02"},
{"Beta", "31.223"},
{"Annual Standard Deviation", "1.337"},
{"Annual Variance", "1.788"},
{"Information Ratio", "1657259.526"},
{"Tracking Error", "1.294"},
{"Treynor Ratio", "68696.045"},
{"Total Fees", "$35.70"},
{"Estimated Strategy Capacity", "$2600000.00"},
{"Lowest Capacity Asset", "ES 31C3JQS9DCF1G|ES XCZJLC9NOB29"},
{"Portfolio Turnover", "495.15%"},
{"Drawdown Recovery", "0"},
{"OrderListHash", "af830085995d0b8fa0d33a6e80dd1241"}
};
}
}
@@ -0,0 +1,145 @@
/*
* 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.UniverseSelection;
using QuantConnect.Interfaces;
using QuantConnect.Securities;
using QuantConnect.Securities.Future;
using QuantConnect.Securities.Option;
namespace QuantConnect.Algorithm.CSharp
{
/// <summary>
/// Algorithm asserting AddFutureOptionContract does not throw even when the underlying security configurations are internal
/// </summary>
public class AddFutureOptionContractWithInternalMappedUnderlyingRegressionAlgorithm : QCAlgorithm, IRegressionAlgorithmDefinition
{
private Future _continuousContract;
private Option _fopContract;
public override void Initialize()
{
SetStartDate(2020, 01, 04);
SetEndDate(2020, 01 , 06);
_continuousContract = AddFuture(Futures.Indices.SP500EMini,
dataNormalizationMode: DataNormalizationMode.BackwardsRatio,
dataMappingMode: DataMappingMode.LastTradingDay,
contractDepthOffset: 0);
}
public override void OnSecuritiesChanged(SecurityChanges changes)
{
if (changes.AddedSecurities.Any(security => security.Symbol == _continuousContract.Symbol))
{
if (SubscriptionManager.SubscriptionDataConfigService.GetSubscriptionDataConfigs(_continuousContract.Mapped).Count != 0 ||
SubscriptionManager.SubscriptionDataConfigService.GetSubscriptionDataConfigs(_continuousContract.Mapped, includeInternalConfigs: true).Count == 0)
{
throw new RegressionTestException("Continuous future underlying should only have internal subscription configs");
}
var contract = OptionChain(_continuousContract.Mapped).FirstOrDefault()?.Symbol;
try
{
_fopContract = AddFutureOptionContract(contract);
}
catch (Exception e)
{
throw new RegressionTestException($"Failed to add future option contract {contract}", e);
}
}
else if (_fopContract != null && changes.AddedSecurities.Any(security => security.Symbol == _fopContract.Symbol))
{
var underlyingSubscriptions = SubscriptionManager.SubscriptionDataConfigService.GetSubscriptionDataConfigs(_fopContract.Symbol.Underlying);
if (underlyingSubscriptions.Any(x => x.DataNormalizationMode == DataNormalizationMode.Raw))
{
throw new RegressionTestException("Future option underlying should not have raw data normalization mode");
}
}
}
public override void OnEndOfAlgorithm()
{
if (_fopContract == null)
{
throw new RegressionTestException("Failed to add future option contract");
}
}
/// <summary>
/// This is used by the regression test system to indicate if the open source Lean repository has the required data to run this algorithm.
/// </summary>
public bool CanRunLocally { get; } = true;
/// <summary>
/// This is used by the regression test system to indicate which languages this algorithm is written in.
/// </summary>
public List<Language> Languages { get; } = new() { Language.CSharp };
/// <summary>
/// Data Points count of all timeslices of algorithm
/// </summary>
public long DataPoints => 3181;
/// <summary>
/// Data Points count of the algorithm history
/// </summary>
public int AlgorithmHistoryDataPoints => 1;
/// <summary>
/// Final status of the algorithm
/// </summary>
public AlgorithmStatus AlgorithmStatus => AlgorithmStatus.Completed;
/// <summary>
/// This is used by the regression test system to indicate what the expected statistics are from running the algorithm
/// </summary>
public Dictionary<string, string> ExpectedStatistics => new Dictionary<string, string>
{
{"Total Orders", "0"},
{"Average Win", "0%"},
{"Average Loss", "0%"},
{"Compounding Annual Return", "0%"},
{"Drawdown", "0%"},
{"Expectancy", "0"},
{"Start Equity", "100000"},
{"End Equity", "100000"},
{"Net Profit", "0%"},
{"Sharpe Ratio", "0"},
{"Sortino Ratio", "0"},
{"Probabilistic Sharpe Ratio", "0%"},
{"Loss Rate", "0%"},
{"Win Rate", "0%"},
{"Profit-Loss Ratio", "0"},
{"Alpha", "0"},
{"Beta", "0"},
{"Annual Standard Deviation", "0"},
{"Annual Variance", "0"},
{"Information Ratio", "-14.395"},
{"Tracking Error", "0.043"},
{"Treynor Ratio", "0"},
{"Total Fees", "$0.00"},
{"Estimated Strategy Capacity", "$0"},
{"Lowest Capacity Asset", ""},
{"Portfolio Turnover", "0%"},
{"Drawdown Recovery", "0"},
{"OrderListHash", "d41d8cd98f00b204e9800998ecf8427e"}
};
}
}
@@ -0,0 +1,270 @@
/*
* 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.Data.Market;
using QuantConnect.Interfaces;
using QuantConnect.Securities;
using QuantConnect.Securities.Future;
using QuantConnect.Securities.Option;
namespace QuantConnect.Algorithm.CSharp
{
/// <summary>
/// This regression algorithm tests that we only receive the option chain for a single future contract
/// in the option universe filter.
/// </summary>
public class AddFutureOptionSingleOptionChainSelectedInUniverseFilterRegressionAlgorithm : QCAlgorithm, IRegressionAlgorithmDefinition
{
private bool _invested;
private bool _onDataReached;
private bool _optionFilterRan;
private readonly HashSet<Symbol> _symbolsReceived = new HashSet<Symbol>();
private readonly HashSet<Symbol> _expectedSymbolsReceived = new HashSet<Symbol>();
private readonly Dictionary<Symbol, List<QuoteBar>> _dataReceived = new Dictionary<Symbol, List<QuoteBar>>();
private Future _es;
public override void Initialize()
{
SetStartDate(2020, 1, 4);
SetEndDate(2020, 1, 8);
_es = AddFuture(Futures.Indices.SP500EMini, Resolution.Minute, Market.CME);
_es.SetFilter((futureFilter) =>
{
return futureFilter.Expiration(0, 365).ExpirationCycle(new[] { 3, 6 });
});
AddFutureOption(_es.Symbol, optionContracts =>
{
_optionFilterRan = true;
var expiry = new HashSet<DateTime>(optionContracts.Select(x => x.Symbol.Underlying.ID.Date)).SingleOrDefault();
// Cast to List<Symbol> because OptionFilterContract overrides some LINQ operators like `Select` and `Where`
// and cause it to mutate the underlying Symbol collection when using those operators.
var symbol = new HashSet<Symbol>(((List<Symbol>)optionContracts).Select(x => x.Underlying)).SingleOrDefault();
if (expiry == null || symbol == null)
{
throw new InvalidOperationException("Expected a single Option contract in the chain, found 0 contracts");
}
var enumerator = optionContracts.GetEnumerator();
while (enumerator.MoveNext())
{
_expectedSymbolsReceived.Add(enumerator.Current);
}
return optionContracts;
});
}
public override void OnData(Slice slice)
{
if (!slice.HasData)
{
return;
}
_onDataReached = true;
var hasOptionQuoteBars = false;
foreach (var qb in slice.QuoteBars.Values)
{
if (qb.Symbol.SecurityType != SecurityType.FutureOption)
{
continue;
}
hasOptionQuoteBars = true;
_symbolsReceived.Add(qb.Symbol);
if (!_dataReceived.ContainsKey(qb.Symbol))
{
_dataReceived[qb.Symbol] = new List<QuoteBar>();
}
_dataReceived[qb.Symbol].Add(qb);
}
if (_invested || !hasOptionQuoteBars)
{
return;
}
foreach (var chain in slice.OptionChains.Values.OrderBy(x => x.Symbol.Underlying.ID.Date))
{
var futureInvested = false;
var optionInvested = false;
foreach (var option in chain.Contracts.Keys)
{
if (futureInvested && optionInvested)
{
return;
}
var future = option.Underlying;
if (!optionInvested && slice.ContainsKey(option))
{
var optionContract = Securities[option];
var marginModel = optionContract.BuyingPowerModel as FuturesOptionsMarginModel;
if (marginModel.InitialIntradayMarginRequirement == 0
|| marginModel.InitialOvernightMarginRequirement == 0
|| marginModel.MaintenanceIntradayMarginRequirement == 0
|| marginModel.MaintenanceOvernightMarginRequirement == 0)
{
throw new RegressionTestException("Unexpected margin requirements");
}
if (marginModel.GetInitialMarginRequirement(optionContract, 1) == 0)
{
throw new RegressionTestException("Unexpected Initial Margin requirement");
}
if (marginModel.GetMaintenanceMargin(optionContract) != 0)
{
throw new RegressionTestException("Unexpected Maintenance Margin requirement");
}
MarketOrder(option, 1);
_invested = true;
optionInvested = true;
if (marginModel.GetMaintenanceMargin(optionContract) == 0)
{
throw new RegressionTestException("Unexpected Maintenance Margin requirement");
}
}
if (!futureInvested && slice.ContainsKey(future))
{
MarketOrder(future, 1);
_invested = true;
futureInvested = true;
}
}
}
}
public override void OnEndOfAlgorithm()
{
if (!_optionFilterRan)
{
throw new InvalidOperationException("Option chain filter was never ran");
}
if (!_onDataReached)
{
throw new RegressionTestException("OnData() was never called.");
}
if (_symbolsReceived.Count != _expectedSymbolsReceived.Count)
{
throw new AggregateException($"Expected {_expectedSymbolsReceived.Count} option contracts Symbols, found {_symbolsReceived.Count}");
}
var missingSymbols = new List<Symbol>();
foreach (var expectedSymbol in _expectedSymbolsReceived)
{
if (!_symbolsReceived.Contains(expectedSymbol))
{
missingSymbols.Add(expectedSymbol);
}
}
if (missingSymbols.Count > 0)
{
throw new RegressionTestException($"Symbols: \"{string.Join(", ", missingSymbols)}\" were not found in OnData");
}
foreach (var expectedSymbol in _expectedSymbolsReceived)
{
var data = _dataReceived[expectedSymbol];
var nonDupeDataCount = data.Select(x =>
{
x.EndTime = default(DateTime);
return x;
}).Distinct().Count();
if (nonDupeDataCount < 1000)
{
throw new RegressionTestException($"Received too few data points. Expected >=1000, found {nonDupeDataCount} for {expectedSymbol}");
}
}
}
/// <summary>
/// This is used by the regression test system to indicate if the open source Lean repository has the required data to run this algorithm.
/// </summary>
public bool CanRunLocally { get; } = true;
/// <summary>
/// This is used by the regression test system to indicate which languages this algorithm is written in.
/// </summary>
public List<Language> Languages { get; } = new() { Language.CSharp, Language.Python };
/// <summary>
/// Data Points count of all timeslices of algorithm
/// </summary>
public long DataPoints => 319494;
/// <summary>
/// Data Points count of the algorithm history
/// </summary>
public int AlgorithmHistoryDataPoints => 0;
/// <summary>
/// Final status of the algorithm
/// </summary>
public AlgorithmStatus AlgorithmStatus => AlgorithmStatus.Completed;
/// <summary>
/// This is used by the regression test system to indicate what the expected statistics are from running the algorithm
/// </summary>
public Dictionary<string, string> ExpectedStatistics => new Dictionary<string, string>
{
{"Total Orders", "2"},
{"Average Win", "0%"},
{"Average Loss", "0%"},
{"Compounding Annual Return", "430.834%"},
{"Drawdown", "4.200%"},
{"Expectancy", "0"},
{"Start Equity", "100000"},
{"End Equity", "102313.03"},
{"Net Profit", "2.313%"},
{"Sharpe Ratio", "17.721"},
{"Sortino Ratio", "0"},
{"Probabilistic Sharpe Ratio", "95.297%"},
{"Loss Rate", "0%"},
{"Win Rate", "0%"},
{"Profit-Loss Ratio", "0"},
{"Alpha", "2.663"},
{"Beta", "1.264"},
{"Annual Standard Deviation", "0.184"},
{"Annual Variance", "0.034"},
{"Information Ratio", "16.514"},
{"Tracking Error", "0.169"},
{"Treynor Ratio", "2.574"},
{"Total Fees", "$3.57"},
{"Estimated Strategy Capacity", "$28000000.00"},
{"Lowest Capacity Asset", "ES XCZJLCA62LNO|ES XCZJLC9NOB29"},
{"Portfolio Turnover", "33.84%"},
{"Drawdown Recovery", "0"},
{"OrderListHash", "7c82013ecabca41591e0253a477025dd"}
};
}
}
@@ -0,0 +1,131 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System.Collections.Generic;
using QuantConnect.Algorithm.Framework.Selection;
using QuantConnect.Interfaces;
using System;
using QuantConnect.Securities;
using QuantConnect.Data.UniverseSelection;
namespace QuantConnect.Algorithm.CSharp
{
/// <summary>
/// This example demonstrates how to use the FutureUniverseSelectionModel to select futures contracts for a given underlying asset.
/// The model is set to update daily, and the algorithm ensures that the selected contracts meet specific criteria.
/// This also includes a check to ensure that only future contracts are added to the algorithm's universe.
/// </summary>
public class AddFutureUniverseSelectionModelRegressionAlgorithm : QCAlgorithm, IRegressionAlgorithmDefinition
{
public override void Initialize()
{
SetStartDate(2013, 10, 08);
SetEndDate(2013, 10, 10);
SetUniverseSelection(new FutureUniverseSelectionModel(
TimeSpan.FromDays(1),
time => new List<Symbol> {
QuantConnect.Symbol.Create(Futures.Indices.SP500EMini, SecurityType.Future, Market.CME)
}
));
}
public override void OnSecuritiesChanged(SecurityChanges changes)
{
if (changes.AddedSecurities.Count > 0)
{
foreach (var security in changes.AddedSecurities)
{
if (security.Symbol.SecurityType != SecurityType.Future)
{
throw new RegressionTestException($"Expected future security, but found '{security.Symbol.SecurityType}'");
}
if (security.Symbol.ID.Symbol != "ES")
{
throw new RegressionTestException($"Expected future symbol 'ES', but found '{security.Symbol.ID.Symbol}");
}
}
}
}
public override void OnEndOfAlgorithm()
{
if (ActiveSecurities.Count == 0)
{
throw new RegressionTestException("No active securities found. Expected at least one active security");
}
}
/// <summary>
/// This is used by the regression test system to indicate if the open source Lean repository has the required data to run this algorithm.
/// </summary>
public bool CanRunLocally { get; } = true;
/// <summary>
/// This is used by the regression test system to indicate which languages this algorithm is written in.
/// </summary>
public List<Language> Languages { get; } = new() { Language.CSharp, Language.Python };
/// <summary>
/// Data Points count of all timeslices of algorithm
/// </summary>
public long DataPoints => 26094;
/// <summary>
/// Data Points count of the algorithm history
/// </summary>
public int AlgorithmHistoryDataPoints => 0;
/// <summary>
/// Final status of the algorithm
/// </summary>
public AlgorithmStatus AlgorithmStatus => AlgorithmStatus.Completed;
/// <summary>
/// This is used by the regression test system to indicate what the expected statistics are from running the algorithm
/// </summary>
public Dictionary<string, string> ExpectedStatistics => new Dictionary<string, string>
{
{"Total Orders", "0"},
{"Average Win", "0%"},
{"Average Loss", "0%"},
{"Compounding Annual Return", "0%"},
{"Drawdown", "0%"},
{"Expectancy", "0"},
{"Start Equity", "100000"},
{"End Equity", "100000"},
{"Net Profit", "0%"},
{"Sharpe Ratio", "0"},
{"Sortino Ratio", "0"},
{"Probabilistic Sharpe Ratio", "0%"},
{"Loss Rate", "0%"},
{"Win Rate", "0%"},
{"Profit-Loss Ratio", "0"},
{"Alpha", "0"},
{"Beta", "0"},
{"Annual Standard Deviation", "0"},
{"Annual Variance", "0"},
{"Information Ratio", "-66.775"},
{"Tracking Error", "0.243"},
{"Treynor Ratio", "0"},
{"Total Fees", "$0.00"},
{"Estimated Strategy Capacity", "$0"},
{"Lowest Capacity Asset", ""},
{"Portfolio Turnover", "0%"},
{"Drawdown Recovery", "0"},
{"OrderListHash", "d41d8cd98f00b204e9800998ecf8427e"}
};
}
}
@@ -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.Linq;
using QuantConnect.Data;
using QuantConnect.Interfaces;
using System.Collections.Generic;
namespace QuantConnect.Algorithm.CSharp
{
/// <summary>
/// We add an option contract using <see cref="QCAlgorithm.AddOptionContract"/> and place a trade and wait till it expires
/// later will liquidate the resulting equity position and assert both option and underlying get removed
/// </summary>
public class AddOptionContractExpiresRegressionAlgorithm : QCAlgorithm, IRegressionAlgorithmDefinition
{
private DateTime _expiration = new DateTime(2014, 06, 21);
private Symbol _option;
private Symbol _twx;
private bool _traded;
public override void Initialize()
{
SetStartDate(2014, 06, 05);
SetEndDate(2014, 06, 30);
_twx = QuantConnect.Symbol.Create("TWX", SecurityType.Equity, Market.USA);
AddUniverse("my-daily-universe-name", time => new List<string> { "AAPL" });
}
public override void OnData(Slice slice)
{
if (_option == null)
{
var option = OptionChain(_twx)
.OrderBy(x => x.ID.Symbol)
.FirstOrDefault(optionContract => optionContract.ID.Date == _expiration
&& optionContract.ID.OptionRight == OptionRight.Call
&& optionContract.ID.OptionStyle == OptionStyle.American);
if (option != null)
{
_option = AddOptionContract(option).Symbol;
}
}
if (_option != null && Securities[_option].Price != 0 && !_traded)
{
_traded = true;
Buy(_option, 1);
foreach (var symbol in new [] { _option, _option.Underlying })
{
var config = SubscriptionManager.SubscriptionDataConfigService.GetSubscriptionDataConfigs(symbol).ToList();
if (!config.Any())
{
throw new RegressionTestException($"Was expecting configurations for {symbol}");
}
if (config.Any(dataConfig => dataConfig.DataNormalizationMode != DataNormalizationMode.Raw))
{
throw new RegressionTestException($"Was expecting DataNormalizationMode.Raw configurations for {symbol}");
}
}
}
if (Time.Date > _expiration)
{
if (SubscriptionManager.SubscriptionDataConfigService.GetSubscriptionDataConfigs(_option).Any())
{
throw new RegressionTestException($"Unexpected configurations for {_option} after it has been delisted");
}
if (Securities[_twx].Invested)
{
if (!SubscriptionManager.SubscriptionDataConfigService.GetSubscriptionDataConfigs(_twx).Any())
{
throw new RegressionTestException($"Was expecting configurations for {_twx}");
}
// first we liquidate the option exercised position
Liquidate(_twx);
}
}
else if (Time.Date > _expiration && !Securities[_twx].Invested)
{
if (SubscriptionManager.SubscriptionDataConfigService.GetSubscriptionDataConfigs(_twx).Any())
{
throw new RegressionTestException($"Unexpected configurations for {_twx} after it has been liquidated");
}
}
}
/// <summary>
/// This is used by the regression test system to indicate if the open source Lean repository has the required data to run this algorithm.
/// </summary>
public bool CanRunLocally { get; } = true;
/// <summary>
/// This is used by the regression test system to indicate which languages this algorithm is written in.
/// </summary>
public List<Language> Languages { get; } = new() { Language.CSharp, Language.Python };
/// <summary>
/// Data Points count of all timeslices of algorithm
/// </summary>
public long DataPoints => 37598;
/// <summary>
/// Data Points count of the algorithm history
/// </summary>
public int AlgorithmHistoryDataPoints => 1;
/// <summary>
/// Final status of the algorithm
/// </summary>
public AlgorithmStatus AlgorithmStatus => AlgorithmStatus.Completed;
/// <summary>
/// This is used by the regression test system to indicate what the expected statistics are from running the algorithm
/// </summary>
public Dictionary<string, string> ExpectedStatistics => new Dictionary<string, string>
{
{"Total Orders", "3"},
{"Average Win", "2.67%"},
{"Average Loss", "-2.98%"},
{"Compounding Annual Return", "-5.432%"},
{"Drawdown", "0.400%"},
{"Expectancy", "-0.052"},
{"Start Equity", "100000"},
{"End Equity", "99608"},
{"Net Profit", "-0.392%"},
{"Sharpe Ratio", "-5.487"},
{"Sortino Ratio", "-2.607"},
{"Probabilistic Sharpe Ratio", "0.000%"},
{"Loss Rate", "50%"},
{"Win Rate", "50%"},
{"Profit-Loss Ratio", "0.90"},
{"Alpha", "-0.028"},
{"Beta", "-0.01"},
{"Annual Standard Deviation", "0.005"},
{"Annual Variance", "0"},
{"Information Ratio", "-2.949"},
{"Tracking Error", "0.049"},
{"Treynor Ratio", "3.063"},
{"Total Fees", "$2.00"},
{"Estimated Strategy Capacity", "$5700000.00"},
{"Lowest Capacity Asset", "AOL VRKS95ENPM9Y|AOL R735QTJ8XC9X"},
{"Portfolio Turnover", "0.54%"},
{"Drawdown Recovery", "0"},
{"OrderListHash", "65d9c6a5991648c8c54a23423a51340d"}
};
}
}
@@ -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 QuantConnect.Data;
using QuantConnect.Data.UniverseSelection;
using QuantConnect.Interfaces;
using System;
using System.Collections.Generic;
using System.Linq;
namespace QuantConnect.Algorithm.CSharp
{
/// <summary>
/// We add an option contract using <see cref="QCAlgorithm.AddOptionContract"/> and place a trade, the underlying
/// gets deselected from the universe selection but should still be present since we manually added the option contract.
/// Later we call <see cref="QCAlgorithm.RemoveOptionContract"/> and expect both option and underlying to be removed.
/// </summary>
public class AddOptionContractFromUniverseRegressionAlgorithm : QCAlgorithm, IRegressionAlgorithmDefinition
{
private DateTime _expiration = new DateTime(2014, 06, 21);
private SecurityChanges _securityChanges = SecurityChanges.None;
private Symbol _option;
private Symbol _aapl;
private Symbol _twx;
private bool _traded;
public override void Initialize()
{
_twx = QuantConnect.Symbol.Create("TWX", SecurityType.Equity, Market.USA);
_aapl = QuantConnect.Symbol.Create("AAPL", SecurityType.Equity, Market.USA);
UniverseSettings.Resolution = Resolution.Minute;
UniverseSettings.DataNormalizationMode = DataNormalizationMode.Raw;
SetStartDate(2014, 06, 05);
SetEndDate(2014, 06, 09);
AddUniverse(enumerable => new[] { Time.Date <= new DateTime(2014, 6, 5) ? _twx : _aapl },
enumerable => new[] { Time.Date <= new DateTime(2014, 6, 5) ? _twx : _aapl });
}
public override void OnData(Slice slice)
{
if (_option != null && Securities[_option].Price != 0 && !_traded)
{
_traded = true;
Buy(_option, 1);
}
if (Time.Date > new DateTime(2014, 6, 5))
{
if (Time < new DateTime(2014, 6, 6, 14, 0, 0))
{
var configs = SubscriptionManager.SubscriptionDataConfigService.GetSubscriptionDataConfigs(_twx);
// assert underlying still there after the universe selection removed it, still used by the manually added option contract
if (!configs.Any())
{
throw new RegressionTestException($"Was expecting configurations for {_twx}" +
$" even after it has been deselected from coarse universe because we still have the option contract.");
}
}
else if (Time == new DateTime(2014, 6, 6, 14, 0, 0))
{
// liquidate & remove the option
RemoveOptionContract(_option);
}
// assert underlying was finally removed
else if(Time > new DateTime(2014, 6, 6, 14, 0, 0))
{
foreach (var symbol in new[] { _option, _option.Underlying })
{
var configs = SubscriptionManager.SubscriptionDataConfigService.GetSubscriptionDataConfigs(symbol);
if (configs.Any())
{
throw new RegressionTestException($"Unexpected configuration for {symbol} after it has been deselected from coarse universe and option contract is removed.");
}
}
}
}
}
public override void OnSecuritiesChanged(SecurityChanges changes)
{
if (_securityChanges.RemovedSecurities.Intersect(changes.RemovedSecurities).Any())
{
throw new RegressionTestException($"SecurityChanges.RemovedSecurities intersect {changes.RemovedSecurities}. We expect no duplicate!");
}
if (_securityChanges.AddedSecurities.Intersect(changes.AddedSecurities).Any())
{
throw new RegressionTestException($"SecurityChanges.AddedSecurities intersect {changes.RemovedSecurities}. We expect no duplicate!");
}
// keep track of all removed and added securities
_securityChanges += changes;
if (changes.AddedSecurities.Any(security => security.Symbol.SecurityType == SecurityType.Option))
{
return;
}
foreach (var addedSecurity in changes.AddedSecurities)
{
var option = OptionChain(addedSecurity.Symbol)
.OrderBy(contractData => contractData.ID.Symbol)
.First(optionContract => optionContract.ID.Date == _expiration
&& optionContract.ID.OptionRight == OptionRight.Call
&& optionContract.ID.OptionStyle == OptionStyle.American);
AddOptionContract(option);
foreach (var symbol in new[] { option.Symbol, option.UnderlyingSymbol })
{
var config = SubscriptionManager.SubscriptionDataConfigService.GetSubscriptionDataConfigs(symbol).ToList();
if (!config.Any())
{
throw new RegressionTestException($"Was expecting configurations for {symbol}");
}
if (config.Any(dataConfig => dataConfig.DataNormalizationMode != DataNormalizationMode.Raw))
{
throw new RegressionTestException($"Was expecting DataNormalizationMode.Raw configurations for {symbol}");
}
}
// just keep the first we got
if (_option == null)
{
_option = option;
}
}
}
public override void OnEndOfAlgorithm()
{
if (SubscriptionManager.Subscriptions.Any(dataConfig => dataConfig.Symbol == _twx || dataConfig.Symbol.Underlying == _twx))
{
throw new RegressionTestException($"Was NOT expecting any configurations for {_twx} or it's options, since we removed the contract");
}
if (SubscriptionManager.Subscriptions.All(dataConfig => dataConfig.Symbol != _aapl))
{
throw new RegressionTestException($"Was expecting configurations for {_aapl}");
}
if (SubscriptionManager.Subscriptions.All(dataConfig => dataConfig.Symbol.Underlying != _aapl))
{
throw new RegressionTestException($"Was expecting options configurations for {_aapl}");
}
}
/// <summary>
/// This is used by the regression test system to indicate if the open source Lean repository has the required data to run this algorithm.
/// </summary>
public bool CanRunLocally { get; } = true;
/// <summary>
/// This is used by the regression test system to indicate which languages this algorithm is written in.
/// </summary>
public List<Language> Languages { get; } = new() { Language.CSharp, Language.Python };
/// <summary>
/// Data Points count of all timeslices of algorithm
/// </summary>
public long DataPoints => 5800;
/// <summary>
/// Data Points count of the algorithm history
/// </summary>
public int AlgorithmHistoryDataPoints => 2;
/// <summary>
/// Final status of the algorithm
/// </summary>
public AlgorithmStatus AlgorithmStatus => AlgorithmStatus.Completed;
/// <summary>
/// This is used by the regression test system to indicate what the expected statistics are from running the algorithm
/// </summary>
public Dictionary<string, string> ExpectedStatistics => new Dictionary<string, string>
{
{"Total Orders", "2"},
{"Average Win", "0%"},
{"Average Loss", "-0.23%"},
{"Compounding Annual Return", "-15.596%"},
{"Drawdown", "0.200%"},
{"Expectancy", "-1"},
{"Start Equity", "100000"},
{"End Equity", "99768"},
{"Net Profit", "-0.232%"},
{"Sharpe Ratio", "-8.903"},
{"Sortino Ratio", "0"},
{"Probabilistic Sharpe Ratio", "0.024%"},
{"Loss Rate", "100%"},
{"Win Rate", "0%"},
{"Profit-Loss Ratio", "0"},
{"Alpha", "0.015"},
{"Beta", "-0.171"},
{"Annual Standard Deviation", "0.006"},
{"Annual Variance", "0"},
{"Information Ratio", "-11.082"},
{"Tracking Error", "0.043"},
{"Treynor Ratio", "0.335"},
{"Total Fees", "$2.00"},
{"Estimated Strategy Capacity", "$2800000.00"},
{"Lowest Capacity Asset", "AOL VRKS95ENPM9Y|AOL R735QTJ8XC9X"},
{"Portfolio Turnover", "1.14%"},
{"Drawdown Recovery", "0"},
{"OrderListHash", "e33b98d8e94ed92d0441fc6fe0d461fb"}
};
}
}
@@ -0,0 +1,166 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.Linq;
using QuantConnect.Data;
using QuantConnect.Interfaces;
using System.Collections.Generic;
namespace QuantConnect.Algorithm.CSharp
{
/// <summary>
/// Regression algorithm reproducing GH issue #6073 where we remove and re add an option and expect it to work
/// </summary>
public class AddOptionContractTwiceRegressionAlgorithm : QCAlgorithm, IRegressionAlgorithmDefinition
{
private Symbol _contract;
private bool _hasRemoved;
private bool _reAdded;
public override void Initialize()
{
SetStartDate(2014, 06, 06);
SetEndDate(2014, 06, 09);
UniverseSettings.DataNormalizationMode = DataNormalizationMode.Raw;
UniverseSettings.MinimumTimeInUniverse = TimeSpan.Zero;
UniverseSettings.FillForward = false;
AddEquity("SPY", Resolution.Hour);
var aapl = QuantConnect.Symbol.Create("AAPL", SecurityType.Equity, Market.USA);
_contract = OptionChain(aapl)
.OrderBy(x => x.ID.StrikePrice)
.FirstOrDefault(optionContract => optionContract.ID.OptionRight == OptionRight.Call
&& optionContract.ID.OptionStyle == OptionStyle.American);
AddOptionContract(_contract);
}
public override void OnData(Slice slice)
{
if (_hasRemoved)
{
if (!_reAdded && slice.ContainsKey(_contract) && slice.ContainsKey(_contract.Underlying))
{
throw new RegressionTestException("Getting data for removed option and underlying!");
}
if (!Portfolio.Invested && _reAdded)
{
var option = Securities[_contract];
var optionUnderlying = Securities[_contract.Underlying];
if (option.IsTradable && optionUnderlying.IsTradable
&& slice.ContainsKey(_contract) && slice.ContainsKey(_contract.Underlying))
{
Buy(_contract, 1);
}
}
if (!Securities[_contract].IsTradable
&& !Securities[_contract.Underlying].IsTradable
&& !_reAdded)
{
// ha changed my mind!
AddOptionContract(_contract);
_reAdded = true;
}
}
if (slice.ContainsKey(_contract) && slice.ContainsKey(_contract.Underlying))
{
if (!_hasRemoved)
{
RemoveOptionContract(_contract);
RemoveSecurity(_contract.Underlying);
_hasRemoved = true;
}
}
}
public override void OnEndOfAlgorithm()
{
if (!_hasRemoved)
{
throw new RegressionTestException("We did not remove the option contract!");
}
if (!_reAdded)
{
throw new RegressionTestException("We did not re add the option contract!");
}
}
/// <summary>
/// This is used by the regression test system to indicate if the open source Lean repository has the required data to run this algorithm.
/// </summary>
public bool CanRunLocally { get; } = true;
/// <summary>
/// This is used by the regression test system to indicate which languages this algorithm is written in.
/// </summary>
public List<Language> Languages { get; } = new() { Language.CSharp };
/// <summary>
/// Data Points count of all timeslices of algorithm
/// </summary>
public long DataPoints => 3818;
/// <summary>
/// Data Points count of the algorithm history
/// </summary>
public int AlgorithmHistoryDataPoints => 1;
/// <summary>
/// Final status of the algorithm
/// </summary>
public AlgorithmStatus AlgorithmStatus => AlgorithmStatus.Completed;
/// <summary>
/// This is used by the regression test system to indicate what the expected statistics are from running the algorithm
/// </summary>
public Dictionary<string, string> ExpectedStatistics => new Dictionary<string, string>
{
{"Total Orders", "2"},
{"Average Win", "0%"},
{"Average Loss", "-0.50%"},
{"Compounding Annual Return", "-39.406%"},
{"Drawdown", "0.700%"},
{"Expectancy", "-1"},
{"Start Equity", "100000"},
{"End Equity", "99498"},
{"Net Profit", "-0.502%"},
{"Sharpe Ratio", "0"},
{"Sortino Ratio", "0"},
{"Probabilistic Sharpe Ratio", "0%"},
{"Loss Rate", "100%"},
{"Win Rate", "0%"},
{"Profit-Loss Ratio", "0"},
{"Alpha", "0"},
{"Beta", "0"},
{"Annual Standard Deviation", "0"},
{"Annual Variance", "0"},
{"Information Ratio", "-9.486"},
{"Tracking Error", "0.008"},
{"Treynor Ratio", "0"},
{"Total Fees", "$2.00"},
{"Estimated Strategy Capacity", "$5000000.00"},
{"Lowest Capacity Asset", "AAPL VXBK4R62H7S6|AAPL R735QTJ8XC9X"},
{"Portfolio Turnover", "22.70%"},
{"Drawdown Recovery", "0"},
{"OrderListHash", "71511e4929377cd55fbf5e7e9555c248"}
};
}
}
@@ -0,0 +1,146 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System.Collections.Generic;
using QuantConnect.Algorithm.Framework.Selection;
using QuantConnect.Interfaces;
using System;
using QuantConnect.Data.UniverseSelection;
namespace QuantConnect.Algorithm.CSharp
{
/// <summary>
/// This example demonstrates how to use the OptionUniverseSelectionModel to select options contracts based on specified conditions.
/// The model is updated daily and selects different options based on the current date.
/// The algorithm ensures that only valid option contracts are selected for the universe.
/// </summary>
public class AddOptionUniverseSelectionModelRegressionAlgorithm : QCAlgorithm, IRegressionAlgorithmDefinition
{
private int _optionCount;
public override void Initialize()
{
SetStartDate(2014, 06, 05);
SetEndDate(2014, 06, 06);
UniverseSettings.Resolution = Resolution.Minute;
SetUniverseSelection(new OptionUniverseSelectionModel(
TimeSpan.FromDays(1),
SelectOptionChainSymbols
));
}
private static IEnumerable<Symbol> SelectOptionChainSymbols(DateTime utcTime)
{
var newYorkTime = utcTime.ConvertFromUtc(TimeZones.NewYork);
if (newYorkTime.Date < new DateTime(2014, 06, 06))
{
yield return QuantConnect.Symbol.Create("TWX", SecurityType.Option, Market.USA);
}
if (newYorkTime.Date >= new DateTime(2014, 06, 06))
{
yield return QuantConnect.Symbol.Create("AAPL", SecurityType.Option, Market.USA);
}
}
public override void OnSecuritiesChanged(SecurityChanges changes)
{
if (changes.AddedSecurities.Count > 0)
{
foreach (var security in changes.AddedSecurities)
{
var symbol = security.Symbol.Underlying == null ? security.Symbol : security.Symbol.Underlying;
if (symbol != "AAPL" && symbol != "TWX")
{
throw new RegressionTestException($"Unexpected security {security.Symbol}");
}
_optionCount += (security.Symbol.SecurityType == SecurityType.Option) ? 1 : 0;
}
}
}
public override void OnEndOfAlgorithm()
{
if (ActiveSecurities.Count == 0)
{
throw new RegressionTestException("No active securities found. Expected at least one active security");
}
if (_optionCount == 0)
{
throw new RegressionTestException("The option count should be greater than 0");
}
}
/// <summary>
/// This is used by the regression test system to indicate if the open source Lean repository has the required data to run this algorithm.
/// </summary>
public bool CanRunLocally { get; } = true;
/// <summary>
/// This is used by the regression test system to indicate which languages this algorithm is written in.
/// </summary>
public List<Language> Languages { get; } = new() { Language.CSharp, Language.Python };
/// <summary>
/// Data Points count of all timeslices of algorithm
/// </summary>
public long DataPoints => 2349547;
/// <summary>
/// Data Points count of the algorithm history
/// </summary>
public int AlgorithmHistoryDataPoints => 0;
/// <summary>
/// Final status of the algorithm
/// </summary>
public AlgorithmStatus AlgorithmStatus => AlgorithmStatus.Completed;
/// <summary>
/// This is used by the regression test system to indicate what the expected statistics are from running the algorithm
/// </summary>
public Dictionary<string, string> ExpectedStatistics => new Dictionary<string, string>
{
{"Total Orders", "0"},
{"Average Win", "0%"},
{"Average Loss", "0%"},
{"Compounding Annual Return", "0%"},
{"Drawdown", "0%"},
{"Expectancy", "0"},
{"Start Equity", "100000"},
{"End Equity", "100000"},
{"Net Profit", "0%"},
{"Sharpe Ratio", "0"},
{"Sortino Ratio", "0"},
{"Probabilistic Sharpe Ratio", "0%"},
{"Loss Rate", "0%"},
{"Win Rate", "0%"},
{"Profit-Loss Ratio", "0"},
{"Alpha", "0"},
{"Beta", "0"},
{"Annual Standard Deviation", "0"},
{"Annual Variance", "0"},
{"Information Ratio", "0"},
{"Tracking Error", "0"},
{"Treynor Ratio", "0"},
{"Total Fees", "$0.00"},
{"Estimated Strategy Capacity", "$0"},
{"Lowest Capacity Asset", ""},
{"Portfolio Turnover", "0%"},
{"Drawdown Recovery", "0"},
{"OrderListHash", "d41d8cd98f00b204e9800998ecf8427e"}
};
}
}
@@ -0,0 +1,127 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System.Collections.Generic;
using System.Linq;
using QuantConnect.Data.UniverseSelection;
using QuantConnect.Interfaces;
using QuantConnect.Securities;
namespace QuantConnect.Algorithm.CSharp
{
/// <summary>
/// Algorithm asserting that using OnlyApplyFilterAtMarketOpen along with other dynamic filters will make the filters be applied only on market
/// open, regardless of the order of configuration of the filters
/// </summary>
public class AddOptionWithOnMarketOpenOnlyFilterRegressionAlgorithm : QCAlgorithm, IRegressionAlgorithmDefinition
{
public override void Initialize()
{
SetStartDate(2014, 6, 5);
SetEndDate(2014, 6, 10);
// OnlyApplyFilterAtMarketOpen as first filter
AddOption("AAPL", Resolution.Minute).SetFilter(u =>
u.OnlyApplyFilterAtMarketOpen()
.Strikes(-5, 5)
.Expiration(0, 100)
.IncludeWeeklys());
// OnlyApplyFilterAtMarketOpen as last filter
AddOption("TWX", Resolution.Minute).SetFilter(u =>
u.Strikes(-5, 5)
.Expiration(0, 100)
.IncludeWeeklys()
.OnlyApplyFilterAtMarketOpen());
}
public override void OnSecuritiesChanged(SecurityChanges changes)
{
// This will be the first call, the underlying securities are added.
if (changes.AddedSecurities.All(s => s.Type != SecurityType.Option))
{
return;
}
var changeOptions = changes.AddedSecurities.Concat(changes.RemovedSecurities)
.Where(s => s.Type == SecurityType.Option);
if (Time != Time.Date)
{
throw new RegressionTestException($"Expected options filter to be run only at midnight. Actual was {Time}");
}
}
/// <summary>
/// This is used by the regression test system to indicate if the open source Lean repository has the required data to run this algorithm.
/// </summary>
public bool CanRunLocally { get; } = true;
/// <summary>
/// This is used by the regression test system to indicate which languages this algorithm is written in.
/// </summary>
public List<Language> Languages { get; } = new() { Language.CSharp };
/// <summary>
/// Data Points count of all time slices of algorithm
/// </summary>
public long DataPoints => 470217;
/// <summary>
/// Data Points count of the algorithm history
/// </summary>
public int AlgorithmHistoryDataPoints => 0;
/// <summary>
/// Final status of the algorithm
/// </summary>
public AlgorithmStatus AlgorithmStatus => AlgorithmStatus.Completed;
/// <summary>
/// This is used by the regression test system to indicate what the expected statistics are from running the algorithm
/// </summary>
public Dictionary<string, string> ExpectedStatistics => new Dictionary<string, string>
{
{"Total Orders", "0"},
{"Average Win", "0%"},
{"Average Loss", "0%"},
{"Compounding Annual Return", "0%"},
{"Drawdown", "0%"},
{"Expectancy", "0"},
{"Start Equity", "100000"},
{"End Equity", "100000"},
{"Net Profit", "0%"},
{"Sharpe Ratio", "0"},
{"Sortino Ratio", "0"},
{"Probabilistic Sharpe Ratio", "0%"},
{"Loss Rate", "0%"},
{"Win Rate", "0%"},
{"Profit-Loss Ratio", "0"},
{"Alpha", "0"},
{"Beta", "0"},
{"Annual Standard Deviation", "0"},
{"Annual Variance", "0"},
{"Information Ratio", "-10.144"},
{"Tracking Error", "0.033"},
{"Treynor Ratio", "0"},
{"Total Fees", "$0.00"},
{"Estimated Strategy Capacity", "$0"},
{"Lowest Capacity Asset", ""},
{"Portfolio Turnover", "0%"},
{"Drawdown Recovery", "0"},
{"OrderListHash", "d41d8cd98f00b204e9800998ecf8427e"}
};
}
}
@@ -0,0 +1,255 @@
/*
* 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.Data.UniverseSelection;
using QuantConnect.Util;
using QuantConnect.Interfaces;
// ReSharper disable InvokeAsExtensionMethod -- .net 4.7.2 added ToHashSet and it looks like our version of mono has it as well causing ambiguity in the cloud
namespace QuantConnect.Algorithm.CSharp
{
public class AddRemoveOptionUniverseRegressionAlgorithm : QCAlgorithm, IRegressionAlgorithmDefinition
{
private const string UnderlyingTicker = "GOOG";
private readonly Symbol Underlying = QuantConnect.Symbol.Create(UnderlyingTicker, SecurityType.Equity, Market.USA);
private readonly Symbol OptionChainSymbol = QuantConnect.Symbol.Create(UnderlyingTicker, SecurityType.Option, Market.USA);
private readonly HashSet<Symbol> _expectedSecurities = new HashSet<Symbol>();
private readonly HashSet<Symbol> _expectedData = new HashSet<Symbol>();
private readonly HashSet<Symbol> _expectedUniverses = new HashSet<Symbol>();
private bool _expectUniverseSubscription;
private DateTime _universeSubscriptionTime;
// order of expected contract additions as price moves
private int _expectedContractIndex;
private readonly List<Symbol> _expectedContracts = new List<Symbol>
{
SymbolRepresentation.ParseOptionTickerOSI("GOOG 151224P00750000"),
SymbolRepresentation.ParseOptionTickerOSI("GOOG 151224P00752500"),
SymbolRepresentation.ParseOptionTickerOSI("GOOG 151224P00755000")
};
public override void Initialize()
{
SetStartDate(2015, 12, 24);
SetEndDate(2015, 12, 24);
var goog = AddEquity(UnderlyingTicker);
// expect GOOG equity
_expectedData.Add(goog.Symbol);
_expectedSecurities.Add(goog.Symbol);
// expect user defined universe holding GOOG equity
_expectedUniverses.Add(UserDefinedUniverse.CreateSymbol(SecurityType.Equity, Market.USA));
}
public override void OnData(Slice slice)
{
// verify expectations
if (SubscriptionManager.Subscriptions.Count(x => x.Symbol == OptionChainSymbol)
!= (_expectUniverseSubscription ? 1 : 0))
{
Log($"SubscriptionManager.Subscriptions: {string.Join(" -- ", SubscriptionManager.Subscriptions)}");
throw new RegressionTestException($"Unexpected {OptionChainSymbol} subscription presence");
}
if (Time != _universeSubscriptionTime && !slice.ContainsKey(Underlying))
{
// TODO : In fact, we're unable to properly detect whether or not we auto-added or it was manually added
// this is because when we auto-add the underlying we don't mark it as an internal security like we do with other auto adds
// so there's currently no good way to remove the underlying equity without invoking RemoveSecurity(underlying) manually
// from the algorithm, otherwise we may remove it incorrectly. Now, we could track MORE state, but it would likely be a duplication
// of the internal flag's purpose, so kicking this issue for now with a big fat note here about it :) to be considerd for any future
// refactorings of how we manage subscription/security data and track various aspects about the security (thinking a flags enum with
// things like manually added, auto added, internal, and any other boolean state we need to track against a single security)
throw new RegressionTestException("The underlying equity data should NEVER be removed in this algorithm because it was manually added");
}
if (_expectedSecurities.AreDifferent(Securities.Total.Select(x => x.Symbol).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 RegressionTestException($"{Time}:: Detected differences in expected and actual securities{Environment.NewLine}Expected:{Environment.NewLine}{expected}{Environment.NewLine}Actual:{Environment.NewLine}{actual}");
}
if (_expectedUniverses.AreDifferent(UniverseManager.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 RegressionTestException($"{Time}:: Detected differences in expected and actual universes{Environment.NewLine}Expected:{Environment.NewLine}{expected}{Environment.NewLine}Actual:{Environment.NewLine}{actual}");
}
if (Time != _universeSubscriptionTime && _expectedData.AreDifferent(slice.Keys.ToHashSet()))
{
var expected = string.Join(Environment.NewLine, _expectedData.OrderBy(s => s.ToString()));
var actual = string.Join(Environment.NewLine, slice.Keys.OrderBy(s => s.ToString()));
throw new RegressionTestException($"{Time}:: Detected differences in expected and actual slice data keys{Environment.NewLine}Expected:{Environment.NewLine}{expected}{Environment.NewLine}Actual:{Environment.NewLine}{actual}");
}
// 10AM add GOOG option chain
if (Time.TimeOfDay.Hours == 10 && Time.TimeOfDay.Minutes == 0 && !_expectUniverseSubscription)
{
if (Securities.ContainsKey(OptionChainSymbol))
{
throw new RegressionTestException("The option chain security should not have been added yet");
}
var googOptionChain = AddOption(UnderlyingTicker);
googOptionChain.SetFilter(u =>
{
// we added the universe at 10, the universe selection data should not be from before
if (u.LocalTime.Hour < 10)
{
throw new RegressionTestException($"Unexpected selection time {u.LocalTime}");
}
// find first put above market price
return u.IncludeWeeklys()
.Strikes(+1, +3)
.Expiration(TimeSpan.Zero, TimeSpan.FromDays(1))
.Contracts(c => c.Where(s => s.ID.OptionRight == OptionRight.Put));
});
_expectedSecurities.Add(OptionChainSymbol);
_expectedUniverses.Add(OptionChainSymbol);
_expectUniverseSubscription = true;
_universeSubscriptionTime = Time;
}
// 11:30AM remove GOOG option chain
if (Time.TimeOfDay.Hours == 11 && Time.TimeOfDay.Minutes == 30)
{
RemoveSecurity(OptionChainSymbol);
// remove contracts from expected data
_expectedData.RemoveWhere(s => _expectedContracts.Contains(s));
// remove option chain universe from expected universes
_expectedUniverses.Remove(OptionChainSymbol);
// OptionChainSymbol universe subscription should not be present
_expectUniverseSubscription = false;
}
}
public override void OnSecuritiesChanged(SecurityChanges changes)
{
if (changes.AddedSecurities.Any())
{
foreach (var added in changes.AddedSecurities)
{
// any option security additions for this algorithm should match the expected contracts
if (added.Symbol.SecurityType == SecurityType.Option)
{
var expectedContract = _expectedContracts[_expectedContractIndex];
if (added.Symbol != expectedContract)
{
throw new RegressionTestException($"Expected option contract {expectedContract.Value} to be added but received {added.Symbol}");
}
_expectedContractIndex++;
// purchase for regression statistics
MarketOrder(added.Symbol, 1);
}
_expectedData.Add(added.Symbol);
_expectedSecurities.Add(added.Symbol);
}
}
// security removal happens exactly once in this algorithm when the option chain is removed
// and all child subscriptions (option contracts) should be removed at the same time
if (changes.RemovedSecurities.Any(x => x.Symbol.SecurityType == SecurityType.Option))
{
// receive removed event next timestep at 11:31AM
if (Time.TimeOfDay.Hours != 11 || Time.TimeOfDay.Minutes != 31)
{
throw new RegressionTestException($"Expected option contracts to be removed at 11:31AM, instead removed at: {Time}");
}
if (changes.RemovedSecurities
.Where(x => x.Symbol.SecurityType == SecurityType.Option)
.ToHashSet(s => s.Symbol)
.AreDifferent(_expectedContracts.ToHashSet()))
{
throw new RegressionTestException("Expected removed securities to equal expected contracts added");
}
}
if (Securities.ContainsKey(Underlying))
{
Log($"{Time:o}:: PRICE:: {Securities[Underlying].Price} CHANGES:: {changes}");
}
}
/// <summary>
/// This is used by the regression test system to indicate if the open source Lean repository has the required data to run this algorithm.
/// </summary>
public bool CanRunLocally { get; } = true;
/// <summary>
/// This is used by the regression test system to indicate which languages this algorithm is written in.
/// </summary>
public List<Language> Languages { get; } = new() { Language.CSharp };
/// <summary>
/// Data Points count of all timeslices of algorithm
/// </summary>
public long DataPoints => 3502;
/// <summary>
/// Data Points count of the algorithm history
/// </summary>
public int AlgorithmHistoryDataPoints => 0;
/// <summary>
/// Final status of the algorithm
/// </summary>
public AlgorithmStatus AlgorithmStatus => AlgorithmStatus.Completed;
/// <summary>
/// This is used by the regression test system to indicate what the expected statistics are from running the algorithm
/// </summary>
public Dictionary<string, string> ExpectedStatistics => new Dictionary<string, string>
{
{"Total Orders", "6"},
{"Average Win", "0%"},
{"Average Loss", "0%"},
{"Compounding Annual Return", "0%"},
{"Drawdown", "0%"},
{"Expectancy", "0"},
{"Start Equity", "100000"},
{"End Equity", "98784"},
{"Net Profit", "0%"},
{"Sharpe Ratio", "0"},
{"Sortino Ratio", "0"},
{"Probabilistic Sharpe Ratio", "0%"},
{"Loss Rate", "0%"},
{"Win Rate", "0%"},
{"Profit-Loss Ratio", "0"},
{"Alpha", "0"},
{"Beta", "0"},
{"Annual Standard Deviation", "0"},
{"Annual Variance", "0"},
{"Information Ratio", "0"},
{"Tracking Error", "0"},
{"Treynor Ratio", "0"},
{"Total Fees", "$6.00"},
{"Estimated Strategy Capacity", "$4000.00"},
{"Lowest Capacity Asset", "GOOCV 305RBQ2BZGA4M|GOOCV VP83T1ZUHROL"},
{"Portfolio Turnover", "2.58%"},
{"Drawdown Recovery", "0"},
{"OrderListHash", "f418de0673fc166487daf80991dfe3a0"}
};
}
}
@@ -0,0 +1,133 @@
/*
* 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 QuantConnect.Interfaces;
using System.Collections.Generic;
using QuantConnect.Orders;
namespace QuantConnect.Algorithm.CSharp
{
/// <summary>
/// Regression algorithm making sure the securities cache is reset correctly once it's removed from the algorithm
/// </summary>
public class AddRemoveSecurityCacheRegressionAlgorithm : QCAlgorithm, IRegressionAlgorithmDefinition
{
/// <summary>
/// Initialise the data and resolution required, as well as the cash and start-end dates for your algorithm. All algorithms must initialized.
/// </summary>
public override void Initialize()
{
SetStartDate(2013, 10, 07); //Set Start Date
SetEndDate(2013, 10, 11); //Set End Date
SetCash(100000); //Set Strategy Cash
AddEquity("SPY", Resolution.Minute, extendedMarketHours: true);
}
/// <summary>
/// OnData event is the primary entry point for your algorithm. Each new data point will be pumped in here.
/// </summary>
/// <param name="slice">Slice object keyed by symbol containing the stock data</param>
public override void OnData(Slice slice)
{
if (!Portfolio.Invested)
{
SetHoldings("SPY", 1);
}
if (Time.Day == 11)
{
return;
}
if (!ActiveSecurities.ContainsKey("AIG"))
{
var aig = AddEquity("AIG", Resolution.Minute);
var ticket = MarketOrder("AIG", 1);
if (ticket.Status != OrderStatus.Invalid || aig.HasData || aig.Price != 0)
{
throw new RegressionTestException("Expected order to always be invalid because there is no data yet!");
}
}
else
{
RemoveSecurity("AIG");
}
}
/// <summary>
/// This is used by the regression test system to indicate if the open source Lean repository has the required data to run this algorithm.
/// </summary>
public bool CanRunLocally { get; } = true;
/// <summary>
/// This is used by the regression test system to indicate which languages this algorithm is written in.
/// </summary>
public List<Language> Languages { get; } = new() { Language.CSharp };
/// <summary>
/// Data Points count of all timeslices of algorithm
/// </summary>
public long DataPoints => 15042;
/// <summary>
/// Data Points count of the algorithm history
/// </summary>
public int AlgorithmHistoryDataPoints => 0;
/// <summary>
/// Final status of the algorithm
/// </summary>
public AlgorithmStatus AlgorithmStatus => AlgorithmStatus.Completed;
/// <summary>
/// This is used by the regression test system to indicate what the expected statistics are from running the algorithm
/// </summary>
public Dictionary<string, string> ExpectedStatistics => new Dictionary<string, string>
{
{"Total Orders", "19"},
{"Average Win", "0%"},
{"Average Loss", "0.00%"},
{"Compounding Annual Return", "271.720%"},
{"Drawdown", "2.500%"},
{"Expectancy", "-1"},
{"Start Equity", "100000"},
{"End Equity", "101753.84"},
{"Net Profit", "1.754%"},
{"Sharpe Ratio", "11.954"},
{"Sortino Ratio", "29.606"},
{"Probabilistic Sharpe Ratio", "73.973%"},
{"Loss Rate", "100%"},
{"Win Rate", "0%"},
{"Profit-Loss Ratio", "0"},
{"Alpha", "0.616"},
{"Beta", "0.81"},
{"Annual Standard Deviation", "0.185"},
{"Annual Variance", "0.034"},
{"Information Ratio", "3.961"},
{"Tracking Error", "0.061"},
{"Treynor Ratio", "2.737"},
{"Total Fees", "$21.45"},
{"Estimated Strategy Capacity", "$830000.00"},
{"Lowest Capacity Asset", "SPY R735QTJ8XC9X"},
{"Portfolio Turnover", "20.49%"},
{"Drawdown Recovery", "2"},
{"OrderListHash", "6ebe462373e2ecc22de8eb2fe114d704"}
};
}
}
@@ -0,0 +1,160 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.Collections.Generic;
using QuantConnect.Data.Market;
using QuantConnect.Orders;
using QuantConnect.Interfaces;
using QuantConnect.Data;
namespace QuantConnect.Algorithm.CSharp
{
/// <summary>
/// This algorithm demonstrates the runtime addition and removal of securities from your algorithm.
/// With LEAN it is possible to add and remove securities after the initialization.
/// </summary>
/// <meta name="tag" content="using data" />
/// <meta name="tag" content="assets" />
/// <meta name="tag" content="regression test" />
public class AddRemoveSecurityRegressionAlgorithm : QCAlgorithm, IRegressionAlgorithmDefinition
{
private DateTime lastAction;
private Symbol _spy = QuantConnect.Symbol.Create("SPY", SecurityType.Equity, Market.USA);
private Symbol _aig = QuantConnect.Symbol.Create("AIG", SecurityType.Equity, Market.USA);
private Symbol _bac = QuantConnect.Symbol.Create("BAC", SecurityType.Equity, Market.USA);
/// <summary>
/// Initialise the data and resolution required, as well as the cash and start-end dates for your algorithm. All algorithms must initialized.
/// </summary>
public override void Initialize()
{
SetStartDate(2013, 10, 07); //Set Start Date
SetEndDate(2013, 10, 11); //Set End Date
SetCash(100000); //Set Strategy Cash
AddSecurity(SecurityType.Equity, "SPY");
}
/// <summary>
/// OnData event is the primary entry point for your algorithm. Each new data point will be pumped in here.
/// </summary>
/// <param name="data">Slice object keyed by symbol containing the stock data</param>
public override void OnData(Slice slice)
{
if (lastAction.Date == Time.Date) return;
if (!Portfolio.Invested)
{
SetHoldings(_spy, 0.5);
lastAction = Time;
}
if (Time.DayOfWeek == DayOfWeek.Tuesday)
{
AddSecurity(SecurityType.Equity, "AIG");
AddSecurity(SecurityType.Equity, "BAC");
lastAction = Time;
}
else if (Time.DayOfWeek == DayOfWeek.Wednesday)
{
SetHoldings(_aig, .25);
SetHoldings(_bac, .25);
lastAction = Time;
}
else if (Time.DayOfWeek == DayOfWeek.Thursday)
{
RemoveSecurity(_aig);
RemoveSecurity(_bac);
lastAction = Time;
}
}
/// <summary>
/// Order events are triggered on order status changes. There are many order events including non-fill messages.
/// </summary>
/// <param name="orderEvent">OrderEvent object with details about the order status</param>
public override void OnOrderEvent(OrderEvent orderEvent)
{
if (orderEvent.Status == OrderStatus.Submitted)
{
Debug(Time + ": Submitted: " + Transactions.GetOrderById(orderEvent.OrderId));
}
if (orderEvent.Status.IsFill())
{
Debug(Time + ": Filled: " + Transactions.GetOrderById(orderEvent.OrderId));
}
}
/// <summary>
/// This is used by the regression test system to indicate if the open source Lean repository has the required data to run this algorithm.
/// </summary>
public bool CanRunLocally { get; } = true;
/// <summary>
/// This is used by the regression test system to indicate which languages this algorithm is written in.
/// </summary>
public List<Language> Languages { get; } = new() { Language.CSharp, Language.Python };
/// <summary>
/// Data Points count of all timeslices of algorithm
/// </summary>
public long DataPoints => 7065;
/// <summary>
/// Data Points count of the algorithm history
/// </summary>
public int AlgorithmHistoryDataPoints => 0;
/// <summary>
/// Final status of the algorithm
/// </summary>
public AlgorithmStatus AlgorithmStatus => AlgorithmStatus.Completed;
/// <summary>
/// This is used by the regression test system to indicate what the expected statistics are from running the algorithm
/// </summary>
public Dictionary<string, string> ExpectedStatistics => new Dictionary<string, string>
{
{"Total Orders", "5"},
{"Average Win", "0.46%"},
{"Average Loss", "0%"},
{"Compounding Annual Return", "296.356%"},
{"Drawdown", "1.400%"},
{"Expectancy", "0"},
{"Start Equity", "100000"},
{"End Equity", "101776.32"},
{"Net Profit", "1.776%"},
{"Sharpe Ratio", "12.966"},
{"Sortino Ratio", "0"},
{"Probabilistic Sharpe Ratio", "80.179%"},
{"Loss Rate", "0%"},
{"Win Rate", "100%"},
{"Profit-Loss Ratio", "0"},
{"Alpha", "0.678"},
{"Beta", "0.707"},
{"Annual Standard Deviation", "0.16"},
{"Annual Variance", "0.026"},
{"Information Ratio", "1.378"},
{"Tracking Error", "0.072"},
{"Treynor Ratio", "2.935"},
{"Total Fees", "$28.30"},
{"Estimated Strategy Capacity", "$4700000.00"},
{"Lowest Capacity Asset", "AIG R735QTJ8XC9X"},
{"Portfolio Turnover", "29.88%"},
{"Drawdown Recovery", "2"},
{"OrderListHash", "f04b3521256c7d6740966bc3df34e7b1"}
};
}
}
@@ -0,0 +1,112 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.Collections.Generic;
using QuantConnect.Algorithm.Framework.Alphas;
using QuantConnect.Algorithm.Framework.Execution;
using QuantConnect.Algorithm.Framework.Portfolio;
using QuantConnect.Algorithm.Framework.Risk;
using QuantConnect.Algorithm.Framework.Selection;
using QuantConnect.Interfaces;
namespace QuantConnect.Algorithm.CSharp
{
/// <summary>
/// Test algorithm using <see cref="QCAlgorithm.AddRiskManagement(IRiskManagementModel)"/>
/// </summary>
public class AddRiskManagementAlgorithm : QCAlgorithm, IRegressionAlgorithmDefinition
{
/// <summary>
/// Initialise the data and resolution required, as well as the cash and start-end dates for your algorithm. All algorithms must initialized.
/// </summary>
public override void Initialize()
{
UniverseSettings.Resolution = Resolution.Minute;
SetStartDate(2013, 10, 07); //Set Start Date
SetEndDate(2013, 10, 11); //Set End Date
SetCash(100000); //Set Strategy Cash
SetUniverseSelection(new ManualUniverseSelectionModel(QuantConnect.Symbol.Create("SPY", SecurityType.Equity, Market.USA)));
SetAlpha(new ConstantAlphaModel(InsightType.Price, InsightDirection.Up, TimeSpan.FromMinutes(20), 0.025, null));
SetPortfolioConstruction(new EqualWeightingPortfolioConstructionModel());
SetExecution(new ImmediateExecutionModel());
AddRiskManagement(new MaximumDrawdownPercentPortfolio(0.02m));
AddRiskManagement(new MaximumUnrealizedProfitPercentPerSecurity(0.01m));
}
/// <summary>
/// This is used by the regression test system to indicate if the open source Lean repository has the required data to run this algorithm.
/// </summary>
public bool CanRunLocally { get; } = true;
/// <summary>
/// This is used by the regression test system to indicate which languages this algorithm is written in.
/// </summary>
public List<Language> Languages { get; } = new() { Language.CSharp, Language.Python };
/// <summary>
/// Data Points count of all timeslices of algorithm
/// </summary>
public long DataPoints => 3943;
/// <summary>
/// Data Points count of the algorithm history
/// </summary>
public int AlgorithmHistoryDataPoints => 0;
/// <summary>
/// Final status of the algorithm
/// </summary>
public AlgorithmStatus AlgorithmStatus => AlgorithmStatus.Completed;
/// <summary>
/// This is used by the regression test system to indicate what the expected statistics are from running the algorithm
/// </summary>
public Dictionary<string, string> ExpectedStatistics => new Dictionary<string, string>
{
{"Total Orders", "3"},
{"Average Win", "1.02%"},
{"Average Loss", "0%"},
{"Compounding Annual Return", "296.066%"},
{"Drawdown", "2.200%"},
{"Expectancy", "0"},
{"Start Equity", "100000"},
{"End Equity", "101775.37"},
{"Net Profit", "1.775%"},
{"Sharpe Ratio", "9.34"},
{"Sortino Ratio", "0"},
{"Probabilistic Sharpe Ratio", "68.153%"},
{"Loss Rate", "0%"},
{"Win Rate", "100%"},
{"Profit-Loss Ratio", "0"},
{"Alpha", "0.106"},
{"Beta", "1.021"},
{"Annual Standard Deviation", "0.227"},
{"Annual Variance", "0.052"},
{"Information Ratio", "25.083"},
{"Tracking Error", "0.006"},
{"Treynor Ratio", "2.079"},
{"Total Fees", "$10.33"},
{"Estimated Strategy Capacity", "$38000000.00"},
{"Lowest Capacity Asset", "SPY R735QTJ8XC9X"},
{"Portfolio Turnover", "59.74%"},
{"Drawdown Recovery", "3"},
{"OrderListHash", "5d7657ec9954875eca633bed711085d3"}
};
}
}
@@ -0,0 +1,154 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.Linq;
using QuantConnect.Data;
using QuantConnect.Interfaces;
using System.Collections.Generic;
namespace QuantConnect.Algorithm.CSharp
{
/// <summary>
/// Regression algorithm reproducing issue where underlying option contract would be removed with the first call
/// too RemoveOptionContract
/// </summary>
public class AddTwoAndRemoveOneOptionContractRegressionAlgorithm : QCAlgorithm, IRegressionAlgorithmDefinition
{
private Symbol _contract1;
private Symbol _contract2;
private bool _hasRemoved;
public override void Initialize()
{
SetStartDate(2014, 06, 06);
SetEndDate(2014, 06, 06);
UniverseSettings.DataNormalizationMode = DataNormalizationMode.Raw;
UniverseSettings.MinimumTimeInUniverse = TimeSpan.Zero;
var aapl = QuantConnect.Symbol.Create("AAPL", SecurityType.Equity, Market.USA);
var contracts = OptionChain(aapl)
.OrderBy(x => x.ID.StrikePrice)
.Where(optionContract => optionContract.ID.OptionRight == OptionRight.Call
&& optionContract.ID.OptionStyle == OptionStyle.American)
.Take(2)
.ToList();
_contract1 = contracts[0];
_contract2 = contracts[1];
AddOptionContract(_contract1);
AddOptionContract(_contract2);
}
public override void OnData(Slice slice)
{
if (slice.HasData)
{
if (!_hasRemoved)
{
RemoveOptionContract(_contract1);
_hasRemoved = true;
}
else
{
var subscriptions =
SubscriptionManager.SubscriptionDataConfigService.GetSubscriptionDataConfigs("AAPL");
if (subscriptions.Count == 0)
{
throw new RegressionTestException("No configuration for underlying was found!");
}
if (!Portfolio.Invested &&
// This security will be liquidated due to impending split, let's not trade it again after the contract is removed.
// Trying to trade it will make the security to be re-added
Securities[_contract2].IsTradable)
{
Buy(_contract2, 1);
}
}
}
}
public override void OnEndOfAlgorithm()
{
if (!_hasRemoved)
{
throw new RegressionTestException("Expect a single call to OnData where we removed the option and underlying");
}
}
/// <summary>
/// This is used by the regression test system to indicate if the open source Lean repository has the required data to run this algorithm.
/// </summary>
public bool CanRunLocally { get; } = true;
/// <summary>
/// This is used by the regression test system to indicate which languages this algorithm is written in.
/// </summary>
public List<Language> Languages { get; } = new() { Language.CSharp };
/// <summary>
/// Data Points count of all timeslices of algorithm
/// </summary>
public long DataPoints => 1579;
/// <summary>
/// Data Points count of the algorithm history
/// </summary>
public int AlgorithmHistoryDataPoints => 1;
/// <summary>
/// Final status of the algorithm
/// </summary>
public AlgorithmStatus AlgorithmStatus => AlgorithmStatus.Completed;
/// <summary>
/// This is used by the regression test system to indicate what the expected statistics are from running the algorithm
/// </summary>
public Dictionary<string, string> ExpectedStatistics => new Dictionary<string, string>
{
{"Total Orders", "2"},
{"Average Win", "0%"},
{"Average Loss", "0%"},
{"Compounding Annual Return", "0%"},
{"Drawdown", "0%"},
{"Expectancy", "0"},
{"Start Equity", "100000"},
{"End Equity", "99238"},
{"Net Profit", "0%"},
{"Sharpe Ratio", "0"},
{"Sortino Ratio", "0"},
{"Probabilistic Sharpe Ratio", "0%"},
{"Loss Rate", "0%"},
{"Win Rate", "0%"},
{"Profit-Loss Ratio", "0"},
{"Alpha", "0"},
{"Beta", "0"},
{"Annual Standard Deviation", "0"},
{"Annual Variance", "0"},
{"Information Ratio", "0"},
{"Tracking Error", "0"},
{"Treynor Ratio", "0"},
{"Total Fees", "$2.00"},
{"Estimated Strategy Capacity", "$6200000.00"},
{"Lowest Capacity Asset", "AAPL VXBK4QA5IWKM|AAPL R735QTJ8XC9X"},
{"Portfolio Turnover", "90.27%"},
{"Drawdown Recovery", "0"},
{"OrderListHash", "a332b93ff5e2dfe89258c450a64c7125"}
};
}
}
@@ -0,0 +1,131 @@
/*
* 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.Algorithm.Framework.Alphas;
using QuantConnect.Algorithm.Framework.Execution;
using QuantConnect.Algorithm.Framework.Portfolio;
using QuantConnect.Algorithm.Framework.Selection;
using QuantConnect.Interfaces;
namespace QuantConnect.Algorithm.CSharp
{
/// <summary>
/// Test algorithm using <see cref="QCAlgorithm.AddUniverseSelection(IUniverseSelectionModel)"/>
/// </summary>
public class AddUniverseSelectionModelAlgorithm : QCAlgorithm, IRegressionAlgorithmDefinition
{
/// <summary>
/// Initialise the data and resolution required, as well as the cash and start-end dates for your algorithm. All algorithms must initialized.
/// </summary>
public override void Initialize()
{
// Set requested data resolution
UniverseSettings.Resolution = Resolution.Daily;
SetStartDate(2013, 10, 08); //Set Start Date
SetEndDate(2013, 10, 11); //Set End Date
SetCash(100000); //Set Strategy Cash
// set algorithm framework models
SetAlpha(new ConstantAlphaModel(InsightType.Price, InsightDirection.Up, TimeSpan.FromMinutes(20), 0.025, null));
SetPortfolioConstruction(new EqualWeightingPortfolioConstructionModel());
SetExecution(new ImmediateExecutionModel());
SetUniverseSelection(new ManualUniverseSelectionModel(QuantConnect.Symbol.Create("SPY", SecurityType.Equity, Market.USA)));
AddUniverseSelection(new ManualUniverseSelectionModel(QuantConnect.Symbol.Create("AAPL", SecurityType.Equity, Market.USA)));
AddUniverseSelection(new ManualUniverseSelectionModel(
QuantConnect.Symbol.Create("SPY", SecurityType.Equity, Market.USA), // duplicate will be ignored
QuantConnect.Symbol.Create("FB", SecurityType.Equity, Market.USA)));
}
public override void OnEndOfAlgorithm()
{
if (UniverseManager.Count != 3)
{
throw new RegressionTestException("Unexpected universe count");
}
if (UniverseManager.ActiveSecurities.Count != 3
|| UniverseManager.ActiveSecurities.Keys.All(symbol => symbol.Value != "SPY")
|| UniverseManager.ActiveSecurities.Keys.All(symbol => symbol.Value != "AAPL")
|| UniverseManager.ActiveSecurities.Keys.All(symbol => symbol.Value != "FB"))
{
throw new RegressionTestException("Unexpected active securities");
}
}
/// <summary>
/// This is used by the regression test system to indicate if the open source Lean repository has the required data to run this algorithm.
/// </summary>
public bool CanRunLocally { get; } = true;
/// <summary>
/// This is used by the regression test system to indicate which languages this algorithm is written in.
/// </summary>
public List<Language> Languages { get; } = new() { Language.CSharp, Language.Python };
/// <summary>
/// Data Points count of all timeslices of algorithm
/// </summary>
public long DataPoints => 50;
/// <summary>
/// Data Points count of the algorithm history
/// </summary>
public int AlgorithmHistoryDataPoints => 0;
/// <summary>
/// Final status of the algorithm
/// </summary>
public AlgorithmStatus AlgorithmStatus => AlgorithmStatus.Completed;
/// <summary>
/// This is used by the regression test system to indicate what the expected statistics are from running the algorithm
/// </summary>
public Dictionary<string, string> ExpectedStatistics => new Dictionary<string, string>
{
{"Total Orders", "6"},
{"Average Win", "0.01%"},
{"Average Loss", "0%"},
{"Compounding Annual Return", "1296.838%"},
{"Drawdown", "0.400%"},
{"Expectancy", "0"},
{"Start Equity", "100000"},
{"End Equity", "102684.23"},
{"Net Profit", "2.684%"},
{"Sharpe Ratio", "34.319"},
{"Sortino Ratio", "0"},
{"Probabilistic Sharpe Ratio", "0%"},
{"Loss Rate", "0%"},
{"Win Rate", "100%"},
{"Profit-Loss Ratio", "0"},
{"Alpha", "-5.738"},
{"Beta", "1.381"},
{"Annual Standard Deviation", "0.246"},
{"Annual Variance", "0.06"},
{"Information Ratio", "-26.937"},
{"Tracking Error", "0.068"},
{"Treynor Ratio", "6.106"},
{"Total Fees", "$18.61"},
{"Estimated Strategy Capacity", "$980000000.00"},
{"Lowest Capacity Asset", "FB V6OIPNZEM8V9"},
{"Portfolio Turnover", "25.56%"},
{"Drawdown Recovery", "1"},
{"OrderListHash", "5ee20c8556d706ab0a63ae41b6579c62"}
};
}
}
@@ -0,0 +1,142 @@
/*
* 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.Algorithm.Framework.Alphas;
using QuantConnect.Algorithm.Framework.Execution;
using QuantConnect.Algorithm.Framework.Portfolio;
using QuantConnect.Algorithm.Framework.Selection;
using QuantConnect.Interfaces;
namespace QuantConnect.Algorithm.CSharp
{
/// <summary>
/// Test algorithm using <see cref="QCAlgorithm.AddUniverseSelection(IUniverseSelectionModel)"/>
/// </summary>
public class AddUniverseSelectionModelCoarseAlgorithm : QCAlgorithm, IRegressionAlgorithmDefinition
{
/// <summary>
/// Initialise the data and resolution required, as well as the cash and start-end dates for your algorithm. All algorithms must initialized.
/// </summary>
public override void Initialize()
{
// Set requested data resolution
UniverseSettings.Resolution = Resolution.Daily;
// Order margin value has to have a minimum of 0.5% of Portfolio value, allows filtering out small trades and reduce fees.
// Commented so regression algorithm is more sensitive
//Settings.MinimumOrderMarginPortfolioPercentage = 0.005m;
SetStartDate(2014, 03, 24);
SetEndDate(2014, 04, 07);
SetCash(100000);
// set algorithm framework models
SetAlpha(new ConstantAlphaModel(InsightType.Price, InsightDirection.Up, TimeSpan.FromMinutes(20), 0.025, null));
SetPortfolioConstruction(new EqualWeightingPortfolioConstructionModel());
SetExecution(new ImmediateExecutionModel());
SetUniverseSelection(new CoarseFundamentalUniverseSelectionModel(
enumerable => enumerable
.Select(fundamental => fundamental.Symbol)
.Where(symbol => symbol.Value == "AAPL")));
AddUniverseSelection(new CoarseFundamentalUniverseSelectionModel(
enumerable => enumerable
.Select(fundamental => fundamental.Symbol)
.Where(symbol => symbol.Value == "SPY")));
AddUniverseSelection(new CoarseFundamentalUniverseSelectionModel(
enumerable => enumerable
.Select(fundamental => fundamental.Symbol)
.Where(symbol => symbol.Value == "FB")));
}
public override void OnEndOfAlgorithm()
{
if (UniverseManager.Count != 3)
{
throw new RegressionTestException("Unexpected universe count");
}
if (UniverseManager.ActiveSecurities.Count != 3
|| UniverseManager.ActiveSecurities.Keys.All(symbol => symbol.Value != "SPY")
|| UniverseManager.ActiveSecurities.Keys.All(symbol => symbol.Value != "AAPL")
|| UniverseManager.ActiveSecurities.Keys.All(symbol => symbol.Value != "FB"))
{
throw new RegressionTestException("Unexpected active securities");
}
}
/// <summary>
/// This is used by the regression test system to indicate if the open source Lean repository has the required data to run this algorithm.
/// </summary>
public bool CanRunLocally { get; } = true;
/// <summary>
/// This is used by the regression test system to indicate which languages this algorithm is written in.
/// </summary>
public List<Language> Languages { get; } = new() { Language.CSharp };
/// <summary>
/// Data Points count of all timeslices of algorithm
/// </summary>
public long DataPoints => 234015;
/// <summary>
/// Data Points count of the algorithm history
/// </summary>
public int AlgorithmHistoryDataPoints => 0;
/// <summary>
/// Final status of the algorithm
/// </summary>
public AlgorithmStatus AlgorithmStatus => AlgorithmStatus.Completed;
/// <summary>
/// This is used by the regression test system to indicate what the expected statistics are from running the algorithm
/// </summary>
public Dictionary<string, string> ExpectedStatistics => new Dictionary<string, string>
{
{"Total Orders", "21"},
{"Average Win", "0.01%"},
{"Average Loss", "-0.01%"},
{"Compounding Annual Return", "-77.566%"},
{"Drawdown", "6.000%"},
{"Expectancy", "-0.811"},
{"Start Equity", "100000"},
{"End Equity", "94042.73"},
{"Net Profit", "-5.957%"},
{"Sharpe Ratio", "-3.345"},
{"Sortino Ratio", "-3.766"},
{"Probabilistic Sharpe Ratio", "4.444%"},
{"Loss Rate", "89%"},
{"Win Rate", "11%"},
{"Profit-Loss Ratio", "0.70"},
{"Alpha", "-0.519"},
{"Beta", "1.491"},
{"Annual Standard Deviation", "0.2"},
{"Annual Variance", "0.04"},
{"Information Ratio", "-3.878"},
{"Tracking Error", "0.147"},
{"Treynor Ratio", "-0.449"},
{"Total Fees", "$29.11"},
{"Estimated Strategy Capacity", "$680000000.00"},
{"Lowest Capacity Asset", "AAPL R735QTJ8XC9X"},
{"Portfolio Turnover", "7.48%"},
{"Drawdown Recovery", "0"},
{"OrderListHash", "2c814c55e7d7c56482411c065b861b33"}
};
}
}
@@ -0,0 +1,206 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.Collections.Generic;
using QuantConnect.Configuration;
using QuantConnect.Data;
using QuantConnect.Data.Auxiliary;
using QuantConnect.Interfaces;
using QuantConnect.Util;
namespace QuantConnect.Algorithm.CSharp
{
/// <summary>
/// Regression algorithm to test volume adjusted behavior
/// </summary>
public class AdjustedVolumeRegressionAlgorithm : QCAlgorithm, IRegressionAlgorithmDefinition
{
private Symbol _aapl;
private const string Ticker = "AAPL";
private CorporateFactorProvider _factorFile;
private readonly IEnumerator<decimal> _expectedAdjustedVolume = new List<decimal> { 6164842, 3044047, 3680347, 3468303, 2169943, 2652523,
1499707, 1518215, 1655219, 1510487 }.GetEnumerator();
private readonly IEnumerator<decimal> _expectedAdjustedAskSize = new List<decimal> { 215600, 5600, 25200, 8400, 5600, 5600, 2800,
8400, 14000, 2800 }.GetEnumerator();
private readonly IEnumerator<decimal> _expectedAdjustedBidSize = new List<decimal> { 2800, 11200, 2800, 2800, 2800, 5600, 11200,
8400, 30800, 2800 }.GetEnumerator();
public override void Initialize()
{
SetStartDate(2014, 6, 5); //Set Start Date
SetEndDate(2014, 6, 5); //Set End Date
UniverseSettings.DataNormalizationMode = DataNormalizationMode.SplitAdjusted;
_aapl = AddEquity(Ticker, Resolution.Minute).Symbol;
var dataProvider =
Composer.Instance.GetExportedValueByTypeName<IDataProvider>(Config.Get("data-provider",
"DefaultDataProvider"));
var mapFileProvider = new LocalDiskMapFileProvider();
mapFileProvider.Initialize(dataProvider);
var factorFileProvider = new LocalDiskFactorFileProvider();
factorFileProvider.Initialize(mapFileProvider, dataProvider);
_factorFile = factorFileProvider.Get(_aapl) as CorporateFactorProvider;
}
/// <summary>
/// OnData event is the primary entry point for your algorithm. Each new data point will be pumped in here.
/// </summary>
/// <param name="data">Slice object keyed by symbol containing the stock data</param>
public override void OnData(Slice slice)
{
if (!Portfolio.Invested)
{
SetHoldings(_aapl, 1);
}
if (slice.Splits.ContainsKey(_aapl))
{
Log(slice.Splits[_aapl].ToString());
}
if (slice.Bars.ContainsKey(_aapl))
{
var aaplData = slice.Bars[_aapl];
// Assert our volume matches what we expect
if (_expectedAdjustedVolume.MoveNext() && _expectedAdjustedVolume.Current != aaplData.Volume)
{
// Our values don't match lets try and give a reason why
var dayFactor = _factorFile.GetPriceScale(aaplData.Time, DataNormalizationMode.SplitAdjusted);
var probableAdjustedVolume = aaplData.Volume / dayFactor;
if (_expectedAdjustedVolume.Current == probableAdjustedVolume)
{
throw new ArgumentException($"Volume was incorrect; but manually adjusted value is correct." +
$" Adjustment by multiplying volume by {1 / dayFactor} is not occurring.");
}
else
{
throw new ArgumentException($"Volume was incorrect; even when adjusted manually by" +
$" multiplying volume by {1 / dayFactor}. Data may have changed.");
}
}
}
if (slice.QuoteBars.ContainsKey(_aapl))
{
var aaplQuoteData = slice.QuoteBars[_aapl];
// Assert our askSize matches what we expect
if (_expectedAdjustedAskSize.MoveNext() && _expectedAdjustedAskSize.Current != aaplQuoteData.LastAskSize)
{
// Our values don't match lets try and give a reason why
var dayFactor = _factorFile.GetPriceScale(aaplQuoteData.Time, DataNormalizationMode.SplitAdjusted);
var probableAdjustedAskSize = aaplQuoteData.LastAskSize / dayFactor;
if (_expectedAdjustedAskSize.Current == probableAdjustedAskSize)
{
throw new ArgumentException($"Ask size was incorrect; but manually adjusted value is correct." +
$" Adjustment by multiplying size by {1 / dayFactor} is not occurring.");
}
else
{
throw new ArgumentException($"Ask size was incorrect; even when adjusted manually by" +
$" multiplying size by {1 / dayFactor}. Data may have changed.");
}
}
// Assert our bidSize matches what we expect
if (_expectedAdjustedBidSize.MoveNext() && _expectedAdjustedBidSize.Current != aaplQuoteData.LastBidSize)
{
// Our values don't match lets try and give a reason why
var dayFactor = _factorFile.GetPriceScale(aaplQuoteData.Time, DataNormalizationMode.SplitAdjusted);
var probableAdjustedBidSize = aaplQuoteData.LastBidSize / dayFactor;
if (_expectedAdjustedBidSize.Current == probableAdjustedBidSize)
{
throw new ArgumentException($"Bid size was incorrect; but manually adjusted value is correct." +
$" Adjustment by multiplying size by {1 / dayFactor} is not occurring.");
}
else
{
throw new ArgumentException($"Bid size was incorrect; even when adjusted manually by" +
$" multiplying size by {1 / dayFactor}. Data may have changed.");
}
}
}
}
/// <summary>
/// This is used by the regression test system to indicate if the open source Lean repository has the required data to run this algorithm.
/// </summary>
public bool CanRunLocally { get; } = true;
/// <summary>
/// This is used by the regression test system to indicate which languages this algorithm is written in.
/// </summary>
public List<Language> Languages { get; } = new() { Language.CSharp };
/// <summary>
/// Data Points count of all timeslices of algorithm
/// </summary>
public long DataPoints => 795;
/// <summary>
/// Data Points count of the algorithm history
/// </summary>
public int AlgorithmHistoryDataPoints => 0;
/// <summary>
/// Final status of the algorithm
/// </summary>
public AlgorithmStatus AlgorithmStatus => AlgorithmStatus.Completed;
/// <summary>
/// This is used by the regression test system to indicate what the expected statistics are from running the algorithm
/// </summary>
public Dictionary<string, string> ExpectedStatistics => new Dictionary<string, string>
{
{"Total Orders", "1"},
{"Average Win", "0%"},
{"Average Loss", "0%"},
{"Compounding Annual Return", "0%"},
{"Drawdown", "0%"},
{"Expectancy", "0"},
{"Start Equity", "100000"},
{"End Equity", "100146.57"},
{"Net Profit", "0%"},
{"Sharpe Ratio", "0"},
{"Sortino Ratio", "0"},
{"Probabilistic Sharpe Ratio", "0%"},
{"Loss Rate", "0%"},
{"Win Rate", "0%"},
{"Profit-Loss Ratio", "0"},
{"Alpha", "0"},
{"Beta", "0"},
{"Annual Standard Deviation", "0"},
{"Annual Variance", "0"},
{"Information Ratio", "0"},
{"Tracking Error", "0"},
{"Treynor Ratio", "0"},
{"Total Fees", "$21.60"},
{"Estimated Strategy Capacity", "$42000000.00"},
{"Lowest Capacity Asset", "AAPL R735QTJ8XC9X"},
{"Portfolio Turnover", "99.56%"},
{"Drawdown Recovery", "0"},
{"OrderListHash", "60f03c8c589a4f814dc4e8945df23207"}
};
}
}
@@ -0,0 +1,120 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.Collections.Generic;
using QuantConnect.Interfaces;
namespace QuantConnect.Algorithm.CSharp
{
/// <summary>
/// Algorithm asserting the correct values for the deployment target and algorithm mode.
/// </summary>
public class AlgorithmModeAndDeploymentTargetAlgorithm : QCAlgorithm, IRegressionAlgorithmDefinition
{
public override void Initialize()
{
SetStartDate(2013, 10, 07);
SetEndDate(2013, 10, 07);
SetCash(100000);
Debug($"Algorithm Mode: {AlgorithmMode}. Is Live Mode: {LiveMode}. Deployment Target: {DeploymentTarget}.");
if (AlgorithmMode != AlgorithmMode.Backtesting)
{
throw new RegressionTestException($"Algorithm mode is not backtesting. Actual: {AlgorithmMode}");
}
if (LiveMode)
{
throw new RegressionTestException("Algorithm should not be live");
}
if (DeploymentTarget != DeploymentTarget.LocalPlatform)
{
throw new RegressionTestException($"Algorithm deployment target is not local. Actual{DeploymentTarget}");
}
// For a live deployment these checks should pass:
//if (AlgorithmMode != AlgorithmMode.Live) throw new RegressionTestException("Algorithm mode is not live");
//if (!LiveMode) throw new RegressionTestException("Algorithm should be live");
// For a cloud deployment these checks should pass:
//if (DeploymentTarget != DeploymentTarget.CloudPlatform) throw new RegressionTestException("Algorithm deployment target is not cloud");
Quit();
}
/// <summary>
/// This is used by the regression test system to indicate if the open source Lean repository has the required data to run this algorithm.
/// </summary>
public bool CanRunLocally { get; } = true;
/// <summary>
/// This is used by the regression test system to indicate which languages this algorithm is written in.
/// </summary>
public List<Language> Languages { get; } = new() { Language.CSharp, Language.Python };
/// <summary>
/// Data Points count of all timeslices of algorithm
/// </summary>
public long DataPoints => 0;
/// <summary>
/// Data Points count of the algorithm history
/// </summary>
public int AlgorithmHistoryDataPoints => 0;
/// <summary>
/// Final status of the algorithm
/// </summary>
public AlgorithmStatus AlgorithmStatus => AlgorithmStatus.Completed;
/// <summary>
/// This is used by the regression test system to indicate what the expected statistics are from running the algorithm
/// </summary>
public Dictionary<string, string> ExpectedStatistics => new Dictionary<string, string>
{
{"Total Orders", "0"},
{"Average Win", "0%"},
{"Average Loss", "0%"},
{"Compounding Annual Return", "0%"},
{"Drawdown", "0%"},
{"Expectancy", "0"},
{"Start Equity", "100000"},
{"End Equity", "100000"},
{"Net Profit", "0%"},
{"Sharpe Ratio", "0"},
{"Sortino Ratio", "0"},
{"Probabilistic Sharpe Ratio", "0%"},
{"Loss Rate", "0%"},
{"Win Rate", "0%"},
{"Profit-Loss Ratio", "0"},
{"Alpha", "0"},
{"Beta", "0"},
{"Annual Standard Deviation", "0"},
{"Annual Variance", "0"},
{"Information Ratio", "0"},
{"Tracking Error", "0"},
{"Treynor Ratio", "0"},
{"Total Fees", "$0.00"},
{"Estimated Strategy Capacity", "$0"},
{"Lowest Capacity Asset", ""},
{"Portfolio Turnover", "0%"},
{"Drawdown Recovery", "0"},
{"OrderListHash", "d41d8cd98f00b204e9800998ecf8427e"}
};
}
}
@@ -0,0 +1,288 @@
/*
* 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.Brokerages;
using QuantConnect.Securities;
using QuantConnect.Data;
using QuantConnect.Data.Shortable;
using QuantConnect.Data.UniverseSelection;
using QuantConnect.Interfaces;
using System.IO;
namespace QuantConnect.Algorithm.CSharp
{
/// <summary>
/// Tests filtering in coarse selection by shortable quantity
/// </summary>
public class AllShortableSymbolsCoarseSelectionRegressionAlgorithm : QCAlgorithm, IRegressionAlgorithmDefinition
{
private static readonly DateTime _20140325 = new DateTime(2014, 3, 25);
private static readonly DateTime _20140326 = new DateTime(2014, 3, 26);
private static readonly DateTime _20140327 = new DateTime(2014, 3, 27);
private static readonly DateTime _20140328 = new DateTime(2014, 3, 28);
private static readonly DateTime _20140329 = new DateTime(2014, 3, 29);
private static readonly Symbol _aapl = QuantConnect.Symbol.Create("AAPL", SecurityType.Equity, Market.USA);
private static readonly Symbol _bac = QuantConnect.Symbol.Create("BAC", SecurityType.Equity, Market.USA);
private static readonly Symbol _gme = QuantConnect.Symbol.Create("GME", SecurityType.Equity, Market.USA);
private static readonly Symbol _goog = QuantConnect.Symbol.Create("GOOG", SecurityType.Equity, Market.USA);
private static readonly Symbol _qqq = QuantConnect.Symbol.Create("QQQ", SecurityType.Equity, Market.USA);
private static readonly Symbol _spy = QuantConnect.Symbol.Create("SPY", SecurityType.Equity, Market.USA);
private DateTime _lastTradeDate;
private static readonly Dictionary<DateTime, bool> _coarseSelected = new Dictionary<DateTime, bool>
{
{ _20140325, false },
{ _20140326, false },
{ _20140327, false },
{ _20140328, false },
};
private static readonly Dictionary<DateTime, Symbol[]> _expectedSymbols = new Dictionary<DateTime, Symbol[]>
{
{ _20140325, new[]
{
_bac,
_qqq,
_spy
}
},
{ _20140326, new[]
{
_spy
}
},
{ _20140327, new[]
{
_aapl,
_bac,
_gme,
_qqq,
_spy,
}
},
{ _20140328, new[]
{
_goog
}
},
{ _20140329, new Symbol[0] }
};
private Security _security;
public override void Initialize()
{
SetStartDate(2014, 3, 25);
SetEndDate(2014, 3, 29);
SetCash(10000000);
_security = AddEquity(_spy);
_security.SetShortableProvider(new RegressionTestShortableProvider());
AddUniverse(CoarseSelection);
UniverseSettings.Resolution = Resolution.Daily;
SetBrokerageModel(new AllShortableSymbolsRegressionAlgorithmBrokerageModel());
}
public override void OnData(Slice slice)
{
if (Time.Date == _lastTradeDate)
{
return;
}
foreach (var (symbol, security) in ActiveSecurities.Where(kvp => !kvp.Value.Invested).OrderBy(kvp => kvp.Key))
{
var shortableQuantity = security.ShortableProvider.ShortableQuantity(symbol, Time);
if (shortableQuantity == null)
{
throw new RegressionTestException($"Expected {symbol} to be shortable on {Time:yyyy-MM-dd}");
}
// Buy at least once into all Symbols. Since daily data will always use
// MOO orders, it makes the testing of liquidating buying into Symbols difficult.
MarketOrder(symbol, -(decimal)shortableQuantity);
_lastTradeDate = Time.Date;
}
}
private IEnumerable<Symbol> CoarseSelection(IEnumerable<CoarseFundamental> coarse)
{
var shortableSymbols = (_security.ShortableProvider as dynamic).AllShortableSymbols(Time);
var selectedSymbols = coarse
.Select(x => x.Symbol)
.Where(s => shortableSymbols.ContainsKey(s) && shortableSymbols[s] >= 500)
.OrderBy(s => s)
.ToList();
var expectedMissing = 0;
if (Time.Date == _20140327)
{
var gme = QuantConnect.Symbol.Create("GME", SecurityType.Equity, Market.USA);
if (!shortableSymbols.ContainsKey(gme))
{
throw new RegressionTestException("Expected unmapped GME in shortable symbols list on 2014-03-27");
}
if (!coarse.Select(x => x.Symbol.Value).Contains("GME"))
{
throw new RegressionTestException("Expected mapped GME in coarse symbols on 2014-03-27");
}
expectedMissing = 1;
}
var missing = _expectedSymbols[Time.Date].Except(selectedSymbols).ToList();
if (missing.Count != expectedMissing)
{
throw new RegressionTestException($"Expected Symbols selected on {Time.Date:yyyy-MM-dd} to match expected Symbols, but the following Symbols were missing: {string.Join(", ", missing.Select(s => s.ToString()))}");
}
_coarseSelected[Time.Date] = true;
return selectedSymbols;
}
public override void OnEndOfAlgorithm()
{
if (!_coarseSelected.Values.All(x => x))
{
throw new AggregateException($"Expected coarse selection on all dates, but didn't run on: {string.Join(", ", _coarseSelected.Where(kvp => !kvp.Value).Select(kvp => kvp.Key.ToStringInvariant("yyyy-MM-dd")))}");
}
}
private class AllShortableSymbolsRegressionAlgorithmBrokerageModel : DefaultBrokerageModel
{
public AllShortableSymbolsRegressionAlgorithmBrokerageModel() : base()
{
}
public override IShortableProvider GetShortableProvider(Security security)
{
return new RegressionTestShortableProvider();
}
}
private class RegressionTestShortableProvider : LocalDiskShortableProvider
{
public RegressionTestShortableProvider() : base("testbrokerage")
{
}
/// <summary>
/// Gets a list of all shortable Symbols, including the quantity shortable as a Dictionary.
/// </summary>
/// <param name="localTime">The algorithm's local time</param>
/// <returns>Symbol/quantity shortable as a Dictionary. Returns null if no entry data exists for this date or brokerage</returns>
public Dictionary<Symbol, long> AllShortableSymbols(DateTime localTime)
{
var shortableDataDirectory = Path.Combine(Globals.DataFolder, SecurityType.Equity.SecurityTypeToLower(), Market.USA, "shortable", Brokerage);
var allSymbols = new Dictionary<Symbol, long>();
// Check backwards up to one week to see if we can source a previous file.
// If not, then we return a list of all Symbols with quantity set to zero.
var i = 0;
while (i <= 7)
{
var shortableListFile = Path.Combine(shortableDataDirectory, "dates", $"{localTime.AddDays(-i):yyyyMMdd}.csv");
foreach (var line in DataProvider.ReadLines(shortableListFile))
{
var csv = line.Split(',');
var ticker = csv[0];
var symbol = new Symbol(
SecurityIdentifier.GenerateEquity(ticker, QuantConnect.Market.USA,
mappingResolveDate: localTime), ticker);
var quantity = Parse.Long(csv[1]);
allSymbols[symbol] = quantity;
}
if (allSymbols.Count > 0)
{
return allSymbols;
}
i++;
}
// Return our empty dictionary if we did not find a file to extract
return allSymbols;
}
}
/// <summary>
/// This is used by the regression test system to indicate if the open source Lean repository has the required data to run this algorithm.
/// </summary>
public bool CanRunLocally { get; } = true;
/// <summary>
/// This is used by the regression test system to indicate which languages this algorithm is written in.
/// </summary>
public List<Language> Languages { get; } = new() { Language.CSharp, Language.Python };
/// <summary>
/// Data Points count of all timeslices of algorithm
/// </summary>
public long DataPoints => 36573;
/// <summary>
/// Data Points count of the algorithm history
/// </summary>
public int AlgorithmHistoryDataPoints => 0;
/// <summary>
/// Final status of the algorithm
/// </summary>
public AlgorithmStatus AlgorithmStatus => AlgorithmStatus.Completed;
/// <summary>
/// This is used by the regression test system to indicate what the expected statistics are from running the algorithm
/// </summary>
public Dictionary<string, string> ExpectedStatistics => new Dictionary<string, string>
{
{"Total Orders", "8"},
{"Average Win", "0%"},
{"Average Loss", "0%"},
{"Compounding Annual Return", "11.027%"},
{"Drawdown", "0.000%"},
{"Expectancy", "0"},
{"Start Equity", "10000000"},
{"End Equity", "10011469.88"},
{"Net Profit", "0.115%"},
{"Sharpe Ratio", "11.963"},
{"Sortino Ratio", "0"},
{"Probabilistic Sharpe Ratio", "0%"},
{"Loss Rate", "0%"},
{"Win Rate", "0%"},
{"Profit-Loss Ratio", "0"},
{"Alpha", "0.07"},
{"Beta", "-0.077"},
{"Annual Standard Deviation", "0.008"},
{"Annual Variance", "0"},
{"Information Ratio", "3.876"},
{"Tracking Error", "0.105"},
{"Treynor Ratio", "-1.215"},
{"Total Fees", "$282.50"},
{"Estimated Strategy Capacity", "$61000000000.00"},
{"Lowest Capacity Asset", "NB R735QTJ8XC9X"},
{"Portfolio Turnover", "3.62%"},
{"Drawdown Recovery", "0"},
{"OrderListHash", "ce85d312f2e4e97c605d13dda0aab8fd"}
};
}
}
@@ -0,0 +1,314 @@
/*
* 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 Accord.Math;
using Accord.Statistics;
using QuantConnect.Algorithm.Framework.Alphas;
using QuantConnect.Algorithm.Framework.Execution;
using QuantConnect.Algorithm.Framework.Portfolio;
using QuantConnect.Algorithm.Framework.Risk;
using QuantConnect.Algorithm.Framework.Selection;
using QuantConnect.Data;
using QuantConnect.Data.Consolidators;
using QuantConnect.Data.UniverseSelection;
using QuantConnect.Indicators;
using QuantConnect.Orders.Fees;
using System;
using System.Collections.Generic;
using System.Linq;
namespace QuantConnect.Algorithm.CSharp.Alphas
{
/// <summary>
/// Energy prices, especially Oil and Natural Gas, are in general fairly correlated,
/// meaning they typically move in the same direction as an overall trend.This Alpha
/// uses this idea and implements an Alpha Model that takes Natural Gas ETF price
/// movements as a leading indicator for Crude Oil ETF price movements.We take the
/// Natural Gas/Crude Oil ETF pair with the highest historical price correlation and
/// then create insights for Crude Oil depending on whether or not the Natural Gas ETF price change
/// is above/below a certain threshold that we set (arbitrarily).
///
/// This alpha is part of the Benchmark Alpha Series created by QuantConnect which are open
/// sourced so the community and client funds can see an example of an alpha.
///</summary>
public class GasAndCrudeOilEnergyCorrelationAlpha : QCAlgorithm
{
public override void Initialize()
{
SetStartDate(2018, 1, 1);
SetCash(100000);
// Set zero transaction fees
SetSecurityInitializer(security => security.FeeModel = new ConstantFeeModel(0));
Func<string, Symbol> ToSymbol = x => QuantConnect.Symbol.Create(x, SecurityType.Equity, Market.USA);
var naturalGas = new[] { "UNG", "BOIL", "FCG" }.Select(ToSymbol).ToArray();
var crudeOil = new[] { "USO", "UCO", "DBO" }.Select(ToSymbol).ToArray();
// Manually curated universe
UniverseSettings.Resolution = Resolution.Minute;
SetUniverseSelection(new ManualUniverseSelectionModel(naturalGas.Concat(crudeOil)));
// Use PairsAlphaModel to establish insights
SetAlpha(new PairsAlphaModel(naturalGas, crudeOil, 90, Resolution.Minute));
// Equally weigh securities in portfolio, based on insights
SetPortfolioConstruction(new EqualWeightingPortfolioConstructionModel());
// Set Custom Execution Model
SetExecution(new CustomExecutionModel());
// Set Null Risk Management Model
SetRiskManagement(new NullRiskManagementModel());
}
/// <summary>
/// This Alpha model assumes that the ETF for natural gas is a good leading-indicator
/// of the price of the crude oil ETF.The model will take in arguments for a threshold
/// at which the model triggers an insight, the length of the look-back period for evaluating
/// rate-of-change of UNG prices, and the duration of the insight
/// </summary>
private class PairsAlphaModel : AlphaModel
{
private readonly Symbol[] _leading;
private readonly Symbol[] _following;
private readonly int _historyDays;
private readonly int _lookback;
private readonly decimal _differenceTrigger = 0.75m;
private readonly Resolution _resolution;
private readonly TimeSpan _predictionInterval;
private readonly Dictionary<Symbol, SymbolData> _symbolDataBySymbol;
private Tuple<SymbolData, SymbolData> _pair;
private DateTime _nextUpdate;
public PairsAlphaModel(
Symbol[] naturalGas,
Symbol[] crudeOil,
int historyDays = 90,
Resolution resolution = Resolution.Hour,
int lookback = 5,
decimal differenceTrigger = 0.75m)
{
_leading = naturalGas;
_following = crudeOil;
_historyDays = historyDays;
_resolution = resolution;
_lookback = lookback;
_differenceTrigger = differenceTrigger;
_symbolDataBySymbol = new Dictionary<Symbol, SymbolData>();
_predictionInterval = resolution.ToTimeSpan().Multiply(lookback);
}
public override IEnumerable<Insight> Update(QCAlgorithm algorithm, Slice data)
{
if (_nextUpdate == DateTime.MinValue || algorithm.Time > _nextUpdate)
{
CorrelationPairsSelection();
_nextUpdate = algorithm.Time.AddDays(30);
}
var magnitude = (double)Math.Round(_pair.Item1.Return / 100, 6);
if (_pair.Item1.Return > _differenceTrigger)
{
yield return Insight.Price(_pair.Item2.Symbol, _predictionInterval, InsightDirection.Up, magnitude);
}
if (_pair.Item1.Return < -_differenceTrigger)
{
yield return Insight.Price(_pair.Item2.Symbol, _predictionInterval, InsightDirection.Down, magnitude);
}
}
public void CorrelationPairsSelection()
{
var maxCorrelation = -1.0;
var matrix = new double[_historyDays, _following.Length + 1];
// Get returns for each oil ETF
for (var j = 0; j < _following.Length; j++)
{
SymbolData symbolData2;
if (_symbolDataBySymbol.TryGetValue(_following[j], out symbolData2))
{
var dailyReturn2 = symbolData2.DailyReturnArray;
for (var i = 0; i < _historyDays; i++)
{
matrix[i, j + 1] = symbolData2.DailyReturnArray[i];
}
}
}
// Get returns for each natural gas ETF
for (var j = 0; j < _leading.Length; j++)
{
SymbolData symbolData1;
if (_symbolDataBySymbol.TryGetValue(_leading[j], out symbolData1))
{
for (var i = 0; i < _historyDays; i++)
{
matrix[i, 0] = symbolData1.DailyReturnArray[i];
}
var column = matrix.Correlation().GetColumn(0);
var correlation = column.RemoveAt(0).Max();
// Calculate the pair with highest historical correlation
if (correlation > maxCorrelation)
{
var maxIndex = column.IndexOf(correlation) - 1;
if (maxIndex < 0) continue;
var symbolData2 = _symbolDataBySymbol[_following[maxIndex]];
_pair = Tuple.Create(symbolData1, symbolData2);
maxCorrelation = correlation;
}
}
}
}
public override void OnSecuritiesChanged(QCAlgorithm algorithm, SecurityChanges changes)
{
foreach (var removed in changes.RemovedSecurities)
{
if (_symbolDataBySymbol.ContainsKey(removed.Symbol))
{
_symbolDataBySymbol[removed.Symbol].RemoveConsolidators(algorithm);
_symbolDataBySymbol.Remove(removed.Symbol);
}
}
// Initialize data for added securities
var symbols = changes.AddedSecurities.Select(x => x.Symbol);
var dailyHistory = algorithm.History(symbols, _historyDays + 1, Resolution.Daily);
if (symbols.Count() > 0 && dailyHistory.Count() == 0)
{
algorithm.Debug($"{algorithm.Time} :: No daily data");
}
dailyHistory.PushThrough(bar =>
{
SymbolData symbolData;
if (!_symbolDataBySymbol.TryGetValue(bar.Symbol, out symbolData))
{
symbolData = new SymbolData(algorithm, bar.Symbol, _historyDays, _lookback, _resolution);
_symbolDataBySymbol.Add(bar.Symbol, symbolData);
}
// Update daily rate of change indicator
symbolData.UpdateDailyRateOfChange(bar);
});
algorithm.History(symbols, _lookback, _resolution).PushThrough(bar =>
{
// Update rate of change indicator with given resolution
if (_symbolDataBySymbol.ContainsKey(bar.Symbol))
{
_symbolDataBySymbol[bar.Symbol].UpdateRateOfChange(bar);
}
});
}
/// <summary>
/// Contains data specific to a symbol required by this model
/// </summary>
private class SymbolData
{
private readonly RateOfChangePercent _dailyReturn;
private readonly IDataConsolidator _dailyConsolidator;
private readonly RollingWindow<IndicatorDataPoint> _dailyReturnHistory;
private readonly IDataConsolidator _consolidator;
public Symbol Symbol { get; }
public RateOfChangePercent Return { get; }
public double[] DailyReturnArray => _dailyReturnHistory
.OrderBy(x => x.EndTime)
.Select(x => (double)x.Value).ToArray();
public SymbolData(QCAlgorithm algorithm, Symbol symbol, int dailyLookback, int lookback, Resolution resolution)
{
Symbol = symbol;
_dailyReturn = new RateOfChangePercent($"{symbol}.DailyROCP(1)", 1);
_dailyConsolidator = algorithm.ResolveConsolidator(symbol, Resolution.Daily);
_dailyReturnHistory = new RollingWindow<IndicatorDataPoint>(dailyLookback);
_dailyReturn.Updated += (s, e) => _dailyReturnHistory.Add(e);
algorithm.RegisterIndicator(symbol, _dailyReturn, _dailyConsolidator);
Return = new RateOfChangePercent($"{symbol}.ROCP({lookback})", lookback);
_consolidator = algorithm.ResolveConsolidator(symbol, resolution);
algorithm.RegisterIndicator(symbol, Return, _consolidator);
}
public void RemoveConsolidators(QCAlgorithm algorithm)
{
algorithm.SubscriptionManager.RemoveConsolidator(Symbol, _consolidator);
algorithm.SubscriptionManager.RemoveConsolidator(Symbol, _dailyConsolidator);
}
public void UpdateRateOfChange(BaseData data)
{
Return.Update(data.EndTime, data.Value);
}
internal void UpdateDailyRateOfChange(BaseData data)
{
_dailyReturn.Update(data.EndTime, data.Value);
}
public override string ToString() => Return.ToDetailedString();
}
}
/// <summary>
/// Provides an implementation of IExecutionModel that immediately submits market orders to achieve the desired portfolio targets
/// </summary>
private class CustomExecutionModel : ExecutionModel
{
private readonly PortfolioTargetCollection _targetsCollection = new PortfolioTargetCollection();
private Symbol _previousSymbol;
/// <summary>
/// Immediately submits orders for the specified portfolio targets.
/// </summary>
/// <param name="algorithm">The algorithm instance</param>
/// <param name="targets">The portfolio targets to be ordered</param>
public override void Execute(QCAlgorithm algorithm, IPortfolioTarget[] targets)
{
_targetsCollection.AddRange(targets);
foreach (var target in _targetsCollection.OrderByMarginImpact(algorithm))
{
var openQuantity = algorithm.Transactions.GetOpenOrders(target.Symbol)
.Sum(x => x.Quantity);
var existing = algorithm.Securities[target.Symbol].Holdings.Quantity + openQuantity;
var quantity = target.Quantity - existing;
// Liquidate positions in Crude Oil ETF that is no longer part of the highest-correlation pair
if (_previousSymbol != null && target.Symbol != _previousSymbol)
{
algorithm.Liquidate(_previousSymbol);
}
if (quantity != 0)
{
algorithm.MarketOrder(target.Symbol, quantity);
_previousSymbol = target.Symbol;
}
}
_targetsCollection.ClearFulfilled(algorithm);
}
}
}
}
@@ -0,0 +1,150 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using QuantConnect.Algorithm.Framework.Alphas;
using QuantConnect.Algorithm.Framework.Execution;
using QuantConnect.Algorithm.Framework.Portfolio;
using QuantConnect.Algorithm.Framework.Risk;
using QuantConnect.Algorithm.Framework.Selection;
using QuantConnect.Data;
using QuantConnect.Orders.Fees;
using System;
using System.Collections.Generic;
using System.Linq;
namespace QuantConnect.Algorithm.CSharp.Alphas
{
/// <summary>
/// Equity indices exhibit mean reversion in daily returns. The Internal Bar Strength indicator (IBS),
/// which relates the closing price of a security to its daily range can be used to identify overbought
/// and oversold securities.
///
/// This alpha ranks 33 global equity ETFs on its IBS value the previous day and predicts for the following day
/// that the ETF with the highest IBS value will decrease in price, and the ETF with the lowest IBS value
/// will increase in price.
///
/// Source: Kakushadze, Zura, and Juan Andrés Serur. “4. Exchange-Traded Funds (ETFs).” 151 Trading Strategies, Palgrave Macmillan, 2018, pp. 9091.
///
/// This alpha is part of the Benchmark Alpha Series created by QuantConnect which are open sourced so the community and client funds can see an example of an alpha.
///</summary>
public class GlobalEquityMeanReversionIBSAlpha : QCAlgorithm
{
public override void Initialize()
{
SetStartDate(2018, 1, 1);
SetCash(100000);
// Set zero transaction fees
SetSecurityInitializer(security => security.FeeModel = new ConstantFeeModel(0));
// Global Equity ETF tickers
var symbols = new[] {
"ECH", "EEM", "EFA", "EPHE", "EPP", "EWA", "EWC", "EWG",
"EWH", "EWI", "EWJ", "EWL", "EWM", "EWM", "EWO", "EWP",
"EWQ", "EWS", "EWT", "EWU", "EWY", "EWZ", "EZA", "FXI",
"GXG", "IDX", "ILF", "EWM", "QQQ", "RSX", "SPY", "THD"}
.Select(x => QuantConnect.Symbol.Create(x, SecurityType.Equity, Market.USA));
// Manually curated universe
UniverseSettings.Resolution = Resolution.Daily;
SetUniverseSelection(new ManualUniverseSelectionModel(symbols));
// Use MeanReversionIBSAlphaModel to establish insights
SetAlpha(new MeanReversionIBSAlphaModel());
// Equally weigh securities in portfolio, based on insights
SetPortfolioConstruction(new EqualWeightingPortfolioConstructionModel());
// Set Immediate Execution Model
SetExecution(new ImmediateExecutionModel());
// Set Null Risk Management Model
SetRiskManagement(new NullRiskManagementModel());
}
/// <summary>
/// Uses ranking of Internal Bar Strength (IBS) to create direction prediction for insights
/// </summary>
private class MeanReversionIBSAlphaModel : AlphaModel
{
private readonly int _numberOfStocks;
private readonly TimeSpan _predictionInterval;
public MeanReversionIBSAlphaModel(
int lookback = 1,
int numberOfStocks = 2,
Resolution resolution = Resolution.Daily)
{
_numberOfStocks = numberOfStocks;
_predictionInterval = resolution.ToTimeSpan().Multiply(lookback);
}
public override IEnumerable<Insight> Update(QCAlgorithm algorithm, Slice data)
{
var symbolsIBS = new Dictionary<Symbol, decimal>();
var returns = new Dictionary<Symbol, decimal>();
foreach (var kvp in algorithm.ActiveSecurities)
{
var security = kvp.Value;
if (security.HasData)
{
var high = security.High;
var low = security.Low;
var hilo = high - low;
// Do not consider symbol with zero open and avoid division by zero
if (security.Open * hilo != 0)
{
// Internal bar strength (IBS)
symbolsIBS.Add(security.Symbol, (security.Close - low) / hilo);
returns.Add(security.Symbol, security.Close / security.Open - 1);
}
}
}
var insights = new List<Insight>();
// Number of stocks cannot be higher than half of symbolsIBS length
var numberOfStocks = Math.Min((int)(symbolsIBS.Count / 2.0), _numberOfStocks);
if (numberOfStocks == 0)
{
return insights;
}
// Rank securities with the highest IBS value
var ordered = from entry in symbolsIBS
orderby Math.Round(entry.Value, 6) descending, entry.Key
select entry;
var highIBS = ordered.Take(numberOfStocks); // Get highest IBS
var lowIBS = ordered.Reverse().Take(numberOfStocks); // Get lowest IBS
// Emit "down" insight for the securities with the highest IBS value
foreach (var kvp in highIBS)
{
insights.Add(Insight.Price(kvp.Key, _predictionInterval, InsightDirection.Down, Math.Abs((double)returns[kvp.Key])));
}
// Emit "up" insight for the securities with the highest IBS value
foreach (var kvp in lowIBS)
{
insights.Add(Insight.Price(kvp.Key, _predictionInterval, InsightDirection.Up, Math.Abs((double)returns[kvp.Key])));
}
return insights;
}
}
}
}
@@ -0,0 +1,290 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using QuantConnect.Algorithm.Framework.Alphas;
using QuantConnect.Algorithm.Framework.Execution;
using QuantConnect.Algorithm.Framework.Portfolio;
using QuantConnect.Algorithm.Framework.Risk;
using QuantConnect.Algorithm.Framework.Selection;
using QuantConnect.Data;
using QuantConnect.Data.Consolidators;
using QuantConnect.Data.Fundamental;
using QuantConnect.Data.UniverseSelection;
using QuantConnect.Indicators;
using QuantConnect.Orders.Fees;
using System;
using System.Collections.Generic;
using System.Linq;
namespace QuantConnect.Algorithm.CSharp.Alphas
{
/// <summary>
/// This alpha picks stocks according to Joel Greenblatt's Magic Formula.
/// First, each stock is ranked depending on the relative value of the ratio EV/EBITDA. For example, a stock
/// that has the lowest EV/EBITDA ratio in the security universe receives a score of one while a stock that has
/// the tenth lowest EV/EBITDA score would be assigned 10 points.
///
/// Then, each stock is ranked and given a score for the second valuation ratio, Return on Capital (ROC).
/// Similarly, a stock that has the highest ROC value in the universe gets one score point.
/// The stocks that receive the lowest combined score are chosen for insights.
///
/// Source: Greenblatt, J. (2010) The Little Book That Beats the Market
///
/// This alpha is part of the Benchmark Alpha Series created by QuantConnect which are open
/// sourced so the community and client funds can see an example of an alpha.
///</summary>
public class GreenblattMagicFormulaAlpha : QCAlgorithm
{
public override void Initialize()
{
SetStartDate(2018, 1, 1);
SetCash(100000);
// Set zero transaction fees
SetSecurityInitializer(security => security.FeeModel = new ConstantFeeModel(0));
// Select stocks using MagicFormulaUniverseSelectionModel
SetUniverseSelection(new GreenBlattMagicFormulaUniverseSelectionModel());
// Use RateOfChangeAlphaModel to establish insights
SetAlpha(new RateOfChangeAlphaModel());
// Equally weigh securities in portfolio, based on insights
SetPortfolioConstruction(new EqualWeightingPortfolioConstructionModel());
// Set Immediate Execution Model
SetExecution(new ImmediateExecutionModel());
// Set Null Risk Management Model
SetRiskManagement(new NullRiskManagementModel());
}
/// <summary>
/// Uses Rate of Change (ROC) to create magnitude prediction for insights.
/// </summary>
private class RateOfChangeAlphaModel : AlphaModel
{
private readonly int _lookback;
private readonly Resolution _resolution;
private readonly TimeSpan _predictionInterval;
private readonly Dictionary<Symbol, SymbolData> _symbolDataBySymbol;
public RateOfChangeAlphaModel(
int lookback = 1,
Resolution resolution = Resolution.Daily)
{
_lookback = lookback;
_resolution = resolution;
_predictionInterval = resolution.ToTimeSpan().Multiply(lookback);
_symbolDataBySymbol = new Dictionary<Symbol, SymbolData>();
}
public override IEnumerable<Insight> Update(QCAlgorithm algorithm, Slice data)
{
var insights = new List<Insight>();
foreach (var kvp in _symbolDataBySymbol)
{
var symbolData = kvp.Value;
if (symbolData.CanEmit)
{
var magnitude = Convert.ToDouble(Math.Abs(symbolData.Return));
insights.Add(Insight.Price(kvp.Key, _predictionInterval, InsightDirection.Up, magnitude));
}
}
return insights;
}
public override void OnSecuritiesChanged(QCAlgorithm algorithm, SecurityChanges changes)
{
// Clean up data for removed securities
foreach (var removed in changes.RemovedSecurities)
{
SymbolData symbolData;
if (_symbolDataBySymbol.TryGetValue(removed.Symbol, out symbolData))
{
symbolData.RemoveConsolidators(algorithm);
_symbolDataBySymbol.Remove(removed.Symbol);
}
}
// Initialize data for added securities
var symbols = changes.AddedSecurities.Select(x => x.Symbol);
var history = algorithm.History(symbols, _lookback, _resolution);
if (symbols.Count() == 0 && history.Count() == 0)
{
return;
}
history.PushThrough(bar =>
{
SymbolData symbolData;
if (!_symbolDataBySymbol.TryGetValue(bar.Symbol, out symbolData))
{
symbolData = new SymbolData(algorithm, bar.Symbol, _lookback, _resolution);
_symbolDataBySymbol[bar.Symbol] = symbolData;
}
symbolData.WarmUpIndicators(bar);
});
}
/// <summary>
/// Contains data specific to a symbol required by this model
/// </summary>
private class SymbolData
{
private readonly Symbol _symbol;
private readonly IDataConsolidator _consolidator;
private long _previous = 0;
public RateOfChange Return { get; }
public bool CanEmit
{
get
{
if (_previous == Return.Samples)
{
return false;
}
_previous = Return.Samples;
return Return.IsReady;
}
}
public SymbolData(QCAlgorithm algorithm, Symbol symbol, int lookback, Resolution resolution)
{
_symbol = symbol;
Return = new RateOfChange($"{symbol}.ROC({lookback})", lookback);
_consolidator = algorithm.ResolveConsolidator(symbol, resolution);
algorithm.RegisterIndicator(symbol, Return, _consolidator);
}
internal void RemoveConsolidators(QCAlgorithm algorithm)
{
algorithm.SubscriptionManager.RemoveConsolidator(_symbol, _consolidator);
}
internal void WarmUpIndicators(BaseData bar)
{
Return.Update(bar.EndTime, bar.Value);
}
}
}
/// <summary>
/// Defines a universe according to Joel Greenblatt's Magic Formula, as a universe selection model for the framework algorithm.
/// From the universe QC500, stocks are ranked using the valuation ratios, Enterprise Value to EBITDA(EV/EBITDA) and Return on Assets(ROA).
/// </summary>
private class GreenBlattMagicFormulaUniverseSelectionModel : FundamentalUniverseSelectionModel
{
private const int _numberOfSymbolsCoarse = 500;
private const int _numberOfSymbolsFine = 20;
private const int _numberOfSymbolsInPortfolio = 10;
private int _lastMonth = -1;
private Dictionary<Symbol, double> _dollarVolumeBySymbol;
public GreenBlattMagicFormulaUniverseSelectionModel() : base(true)
{
_dollarVolumeBySymbol = new ();
}
/// <summary>
/// Performs coarse selection for constituents.
/// The stocks must have fundamental data
/// The stock must have positive previous-day close price
/// The stock must have positive volume on the previous trading day
/// </summary>
public override IEnumerable<Symbol> SelectCoarse(QCAlgorithm algorithm, IEnumerable<CoarseFundamental> coarse)
{
if (algorithm.Time.Month == _lastMonth)
{
return algorithm.Universe.Unchanged;
}
_lastMonth = algorithm.Time.Month;
_dollarVolumeBySymbol = (
from cf in coarse
where cf.HasFundamentalData
orderby cf.DollarVolume descending
select new { cf.Symbol, cf.DollarVolume }
)
.Take(_numberOfSymbolsCoarse)
.ToDictionary(x => x.Symbol, x => x.DollarVolume);
return _dollarVolumeBySymbol.Keys;
}
/// <summary>
/// QC500: Performs fine selection for the coarse selection constituents
/// The company's headquarter must in the U.S.
/// The stock must be traded on either the NYSE or NASDAQ
/// At least half a year since its initial public offering
/// The stock's market cap must be greater than 500 million
///
/// Magic Formula: Rank stocks by Enterprise Value to EBITDA(EV/EBITDA)
/// Rank subset of previously ranked stocks(EV/EBITDA), using the valuation ratio Return on Assets(ROA)
/// </summary>
public override IEnumerable<Symbol> SelectFine(QCAlgorithm algorithm, IEnumerable<FineFundamental> fine)
{
var filteredFine =
from x in fine
where x.CompanyReference.CountryId == "USA"
where x.CompanyReference.PrimaryExchangeID == "NYS" || x.CompanyReference.PrimaryExchangeID == "NAS"
where (algorithm.Time - x.SecurityReference.IPODate).TotalDays > 180
where x.EarningReports.BasicAverageShares.ThreeMonths * x.EarningReports.BasicEPS.TwelveMonths * x.ValuationRatios.PERatio > 5e8
select x;
double count = filteredFine.Count();
if (count == 0)
{
return Enumerable.Empty<Symbol>();
}
var percent = _numberOfSymbolsFine / count;
// Select stocks with top dollar volume in every single sector
var myDict = (
from x in filteredFine
group x by x.CompanyReference.IndustryTemplateCode into g
let y = (
from item in g
orderby _dollarVolumeBySymbol[item.Symbol] descending
select item
)
let c = (int)Math.Ceiling(y.Count() * percent)
select new { g.Key, Value = y.Take(c) }
)
.ToDictionary(x => x.Key, x => x.Value);
// Stocks in QC500 universe
var topFine = myDict.Values.SelectMany(x => x);
// Magic Formula:
// Rank stocks by Enterprise Value to EBITDA (EV/EBITDA)
// Rank subset of previously ranked stocks (EV/EBITDA), using the valuation ratio Return on Assets (ROA)
return topFine
// Sort stocks in the security universe of QC500 based on Enterprise Value to EBITDA valuation ratio
.OrderByDescending(x => x.ValuationRatios.EVToEBITDA)
.Take(_numberOfSymbolsFine)
// sort subset of stocks that have been sorted by Enterprise Value to EBITDA, based on the valuation ratio Return on Assets (ROA)
.OrderByDescending(x => x.ValuationRatios.ForwardROA)
.Take(_numberOfSymbolsInPortfolio)
.Select(x => x.Symbol);
}
}
}
}
@@ -0,0 +1,176 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using QuantConnect.Algorithm.Framework.Alphas;
using QuantConnect.Algorithm.Framework.Execution;
using QuantConnect.Algorithm.Framework.Portfolio;
using QuantConnect.Algorithm.Framework.Risk;
using QuantConnect.Algorithm.Framework.Selection;
using QuantConnect.Data;
using QuantConnect.Data.UniverseSelection;
using QuantConnect.Indicators;
using QuantConnect.Orders.Fees;
using System;
using System.Collections.Generic;
using System.Linq;
namespace QuantConnect.Algorithm.CSharp.Alphas
{
/// <summary>
/// Reversal strategy that goes long when price crosses below SMA and Short when price crosses above SMA.
/// The trading strategy is implemented only between 10AM - 3PM (NY time). Research suggests this is due to
/// institutional trades during market hours which need hedging with the USD. Source paper:
/// LeBaron, Zhao: Intraday Foreign Exchange Reversals
/// http://people.brandeis.edu/~blebaron/wps/fxnyc.pdf
/// http://www.fma.org/Reno/Papers/ForeignExchangeReversalsinNewYorkTime.pdf
///
/// This alpha is part of the Benchmark Alpha Series created by QuantConnect which are open sourced so the community and client funds can see an example of an alpha.
///</summary>
public class IntradayReversalCurrencyMarketsAlpha : QCAlgorithm
{
public override void Initialize()
{
SetStartDate(2015, 1, 1);
SetCash(100000);
// Set zero transaction fees
SetSecurityInitializer(security => security.FeeModel = new ConstantFeeModel(0));
// Select resolution
var resolution = Resolution.Hour;
// Reversion on the USD.
var symbols = new[] { QuantConnect.Symbol.Create("EURUSD", SecurityType.Forex, Market.Oanda) };
// Set requested data resolution
UniverseSettings.Resolution = resolution;
SetUniverseSelection(new ManualUniverseSelectionModel(symbols));
// Use IntradayReversalAlphaModel to establish insights
SetAlpha(new IntradayReversalAlphaModel(5, resolution));
// Equally weigh securities in portfolio, based on insights
SetPortfolioConstruction(new EqualWeightingPortfolioConstructionModel());
// Set Immediate Execution Model
SetExecution(new ImmediateExecutionModel());
// Set Null Risk Management Model
SetRiskManagement(new NullRiskManagementModel());
}
/// <summary>
/// Alpha model that uses a Price/SMA Crossover to create insights on Hourly Frequency.
/// Frequency: Hourly data with 5-hour simple moving average.
/// Strategy:
/// Reversal strategy that goes Long when price crosses below SMA and Short when price crosses above SMA.
/// The trading strategy is implemented only between 10AM - 3PM (NY time)
/// </summary>
private class IntradayReversalAlphaModel : AlphaModel
{
private readonly int _periodSma;
private readonly Resolution _resolution;
private readonly Dictionary<Symbol, SymbolData> _cache;
public IntradayReversalAlphaModel(
int periodSma = 5,
Resolution resolution = Resolution.Hour)
{
_periodSma = periodSma;
_resolution = resolution;
_cache = new Dictionary<Symbol, SymbolData>();
Name = "IntradayReversalAlphaModel";
}
public override IEnumerable<Insight> Update(QCAlgorithm algorithm, Slice data)
{
// Set the time to close all positions at 3PM
var timeToClose = algorithm.Time.Date.Add(new TimeSpan(0, 15, 1, 0));
var insights = new List<Insight>();
foreach (var kvp in algorithm.ActiveSecurities)
{
var symbol = kvp.Key;
SymbolData symbolData;
if (ShouldEmitInsight(algorithm, symbol) &&
_cache.TryGetValue(symbol, out symbolData))
{
var price = kvp.Value.Price;
var direction = symbolData.IsUptrend(price)
? InsightDirection.Up
: InsightDirection.Down;
// Ignore signal for same direction as previous signal (when no crossover)
if (direction == symbolData.PreviousDirection)
{
continue;
}
// Save the current Insight Direction to check when the crossover happens
symbolData.PreviousDirection = direction;
// Generate insight
insights.Add(Insight.Price(symbol, timeToClose, direction));
}
}
return insights;
}
private bool ShouldEmitInsight(QCAlgorithm algorithm, Symbol symbol)
{
var timeOfDay = algorithm.Time.TimeOfDay;
return algorithm.Securities[symbol].HasData &&
timeOfDay >= TimeSpan.FromHours(10) &&
timeOfDay <= TimeSpan.FromHours(15);
}
public override void OnSecuritiesChanged(QCAlgorithm algorithm, SecurityChanges changes)
{
foreach (var symbol in changes.AddedSecurities.Select(x => x.Symbol))
{
if (_cache.ContainsKey(symbol)) continue;
_cache.Add(symbol, new SymbolData(algorithm, symbol, _periodSma, _resolution));
}
}
/// <summary>
/// Contains data specific to a symbol required by this model
/// </summary>
private class SymbolData
{
private readonly SimpleMovingAverage _priceSMA;
public InsightDirection PreviousDirection { get; set; }
public SymbolData(QCAlgorithm algorithm, Symbol symbol, int periodSma, Resolution resolution)
{
PreviousDirection = InsightDirection.Flat;
_priceSMA = algorithm.SMA(symbol, periodSma, resolution);
}
public bool IsUptrend(decimal price)
{
return _priceSMA.IsReady && price < Math.Round(_priceSMA * 1.001m, 6);
}
}
}
}
}
@@ -0,0 +1,182 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using QuantConnect.Algorithm.Framework.Alphas;
using QuantConnect.Algorithm.Framework.Execution;
using QuantConnect.Algorithm.Framework.Portfolio;
using QuantConnect.Algorithm.Framework.Risk;
using QuantConnect.Algorithm.Framework.Selection;
using QuantConnect.Data;
using QuantConnect.Data.UniverseSelection;
using QuantConnect.Indicators;
using QuantConnect.Orders.Fees;
using System;
using System.Collections.Generic;
using System.Linq;
namespace QuantConnect.Algorithm.CSharp.Alphas
{
/// <summary>
/// This alpha aims to capture the mean-reversion effect of ETFs during lunch-break by ranking 20 ETFs
/// on their return between the close of the previous day to 12:00 the day after and predicting mean-reversion
/// in price during lunch-break.
///
/// Source: Lunina, V. (June 2011). The Intraday Dynamics of Stock Returns and Trading Activity: Evidence from OMXS 30 (Master's Essay, Lund University).
/// Retrieved from http://lup.lub.lu.se/luur/download?func=downloadFile&recordOId=1973850&fileOId=1973852
///
/// This alpha is part of the Benchmark Alpha Series created by QuantConnect which are open sourced so the community and client funds can see an example of an alpha.
///</summary>
public class MeanReversionLunchBreakAlpha : QCAlgorithm
{
public override void Initialize()
{
SetStartDate(2018, 1, 1);
SetCash(100000);
// Set zero transaction fees
SetSecurityInitializer(security => security.FeeModel = new ConstantFeeModel(0));
// Use Hourly Data For Simplicity
UniverseSettings.Resolution = Resolution.Hour;
SetUniverseSelection(new CoarseFundamentalUniverseSelectionModel(CoarseSelectionFunction));
// Use MeanReversionLunchBreakAlphaModel to establish insights
SetAlpha(new MeanReversionLunchBreakAlphaModel());
// Equally weigh securities in portfolio, based on insights
SetPortfolioConstruction(new EqualWeightingPortfolioConstructionModel());
// Set Immediate Execution Model
SetExecution(new ImmediateExecutionModel());
// Set Null Risk Management Model
SetRiskManagement(new NullRiskManagementModel());
}
/// <summary>
/// Sort the data by daily dollar volume and take the top '20' ETFs
/// </summary>
private IEnumerable<Symbol> CoarseSelectionFunction(IEnumerable<CoarseFundamental> coarse)
{
return (from cf in coarse
where !cf.HasFundamentalData
orderby cf.DollarVolume descending
select cf.Symbol).Take(20);
}
/// <summary>
/// Uses the price return between the close of previous day to 12:00 the day after to
/// predict mean-reversion of stock price during lunch break and creates direction prediction
/// for insights accordingly.
/// </summary>
private class MeanReversionLunchBreakAlphaModel : AlphaModel
{
private const Resolution _resolution = Resolution.Hour;
private readonly TimeSpan _predictionInterval;
private readonly Dictionary<Symbol, SymbolData> _symbolDataBySymbol;
public MeanReversionLunchBreakAlphaModel(int lookback = 1)
{
_predictionInterval = _resolution.ToTimeSpan().Multiply(lookback);
_symbolDataBySymbol = new Dictionary<Symbol, SymbolData>();
}
public override IEnumerable<Insight> Update(QCAlgorithm algorithm, Slice data)
{
foreach (var kvp in _symbolDataBySymbol)
{
if (data.Bars.ContainsKey(kvp.Key))
{
var bar = data.Bars.GetValue(kvp.Key);
kvp.Value.Update(bar.EndTime, bar.Close);
}
}
return algorithm.Time.Hour == 12
? _symbolDataBySymbol.Select(kvp => kvp.Value.Insight)
: Enumerable.Empty<Insight>();
}
public override void OnSecuritiesChanged(QCAlgorithm algorithm, SecurityChanges changes)
{
foreach (var security in changes.RemovedSecurities)
{
if (_symbolDataBySymbol.ContainsKey(security.Symbol))
{
_symbolDataBySymbol.Remove(security.Symbol);
}
}
// Retrieve price history for all securities in the security universe
// and update the indicators in the SymbolData object
var symbols = changes.AddedSecurities.Select(x => x.Symbol);
var history = algorithm.History(symbols, 1, _resolution);
if (symbols.Count() > 0 && history.Count() == 0)
{
algorithm.Debug($"No data on {algorithm.Time}");
}
history.PushThrough(bar =>
{
SymbolData symbolData;
if (!_symbolDataBySymbol.TryGetValue(bar.Symbol, out symbolData))
{
symbolData = new SymbolData(bar.Symbol, _predictionInterval);
}
symbolData.Update(bar.EndTime, bar.Price);
_symbolDataBySymbol[bar.Symbol] = symbolData;
});
}
/// <summary>
/// Contains data specific to a symbol required by this model
/// </summary>
private class SymbolData
{
// Mean value of returns for magnitude prediction
private readonly SimpleMovingAverage _meanOfPriceChange = new RateOfChangePercent(1).SMA(3);
// Price change from close price the previous day
private readonly RateOfChangePercent _priceChange = new RateOfChangePercent(3);
private readonly Symbol _symbol;
private readonly TimeSpan _period;
public Insight Insight
{
get
{
// Emit "down" insight for the securities that increased in value and
// emit "up" insight for securities that have decreased in value
var direction = _priceChange > 0 ? InsightDirection.Down : InsightDirection.Up;
var magnitude = Convert.ToDouble(Math.Abs(_meanOfPriceChange));
return Insight.Price(_symbol, _period, direction, magnitude);
}
}
public SymbolData(Symbol symbol, TimeSpan period)
{
_symbol = symbol;
_period = period;
}
public bool Update(DateTime time, decimal value)
{
return _meanOfPriceChange.Update(time, value) &
_priceChange.Update(time, value);
}
}
}
}
}
@@ -0,0 +1,213 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using QuantConnect.Algorithm.Framework.Alphas;
using QuantConnect.Algorithm.Framework.Execution;
using QuantConnect.Algorithm.Framework.Portfolio;
using QuantConnect.Algorithm.Framework.Risk;
using QuantConnect.Algorithm.Framework.Selection;
using QuantConnect.Data;
using QuantConnect.Interfaces;
using System;
using System.Collections.Generic;
using System.Linq;
namespace QuantConnect.Algorithm.CSharp.Alphas
{
///<summary>
/// Alpha Benchmark Strategy capitalizing on ETF rebalancing causing momentum during trending markets.
/// Strategy by Prof. Shum, reposted by Ernie Chan.
/// Source: http://epchan.blogspot.com/2012/10/a-leveraged-etfs-strategy.html
///</summary>
/// <meta name="tag" content="alphastream" />
/// <meta name="tag" content="algorithm framework" />
/// <meta name="tag" content="etf" />
public class RebalancingLeveragedETFAlpha : QCAlgorithm, IRegressionAlgorithmDefinition
{
private readonly List<ETFGroup> Groups = new List<ETFGroup>();
public override void Initialize()
{
SetStartDate(2017, 6, 1);
SetEndDate(2018, 8, 1);
SetCash(100000);
var underlying = new List<string> { "SPY", "QLD", "DIA", "IJR", "MDY", "IWM", "QQQ", "IYE", "EEM", "IYW", "EFA", "GAZB", "SLV", "IEF", "IYM", "IYF", "IYH", "IYR", "IYC", "IBB", "FEZ", "USO", "TLT" };
var ultraLong = new List<string> { "SSO", "UGL", "DDM", "SAA", "MZZ", "UWM", "QLD", "DIG", "EET", "ROM", "EFO", "BOIL", "AGQ", "UST", "UYM", "UYG", "RXL", "URE", "UCC", "BIB", "ULE", "UCO", "UBT" };
var ultraShort = new List<string> { "SDS", "GLL", "DXD", "SDD", "MVV", "TWM", "QID", "DUG", "EEV", "REW", "EFU", "KOLD", "ZSL", "PST", "SMN", "SKF", "RXD", "SRS", "SCC", "BIS", "EPV", "SCO", "TBT" };
for (var i = 0; i < underlying.Count; i++)
{
Groups.Add(new ETFGroup(AddEquity(underlying[i]).Symbol, AddEquity(ultraLong[i]).Symbol, AddEquity(ultraShort[i]).Symbol));
}
// Manually curated universe
SetUniverseSelection(new ManualUniverseSelectionModel());
// Select the demonstration alpha model
SetAlpha(new RebalancingLeveragedETFAlphaModel(Groups));
// Select our default model types
SetPortfolioConstruction(new EqualWeightingPortfolioConstructionModel());
// Equally weigh securities in portfolio, based on insights
SetPortfolioConstruction(new EqualWeightingPortfolioConstructionModel());
// Set Immediate Execution Model
SetExecution(new ImmediateExecutionModel());
// Set Null Risk Management Model
SetRiskManagement(new NullRiskManagementModel());
}
/// <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 List<Language> Languages { get; } = new() { Language.CSharp, Language.Python };
/// <summary>
/// Data Points count of all timeslices of algorithm
/// </summary>
public long DataPoints => 0;
/// </summary>
/// Data Points count of the algorithm history
/// </summary>
public int AlgorithmHistoryDataPoints => 0;
/// <summary>
/// Final status of the algorithm
/// </summary>
public AlgorithmStatus AlgorithmStatus => AlgorithmStatus.Completed;
/// <summary>
/// This is used by the regression test system to indicate what the expected statistics are from running the algorithm
/// </summary>
public Dictionary<string, string> ExpectedStatistics => new Dictionary<string, string>
{
{"Total Orders", "2465"},
{"Average Win", "0.26%"},
{"Average Loss", "-0.24%"},
{"Compounding Annual Return", "7.848%"},
{"Drawdown", "17.500%"},
{"Expectancy", "0.035"},
{"Net Profit", "9.233%"},
{"Sharpe Ratio", "0.492"},
{"Loss Rate", "50%"},
{"Win Rate", "50%"},
{"Profit-Loss Ratio", "1.06"},
{"Alpha", "0.585"},
{"Beta", "-24.639"},
{"Annual Standard Deviation", "0.19"},
{"Annual Variance", "0.036"},
{"Information Ratio", "0.387"},
{"Tracking Error", "0.19"},
{"Treynor Ratio", "-0.004"},
{"Total Fees", "$9029.33"}
};
}
/// <summary>
/// If the underlying ETF has experienced a return >= 1% since the previous day's close up to the current time at 14:15,
/// then buy it's ultra ETF right away, and exit at the close. If the return is &lt;= -1%, sell it's ultra-short ETF.
/// </summary>
class RebalancingLeveragedETFAlphaModel : AlphaModel
{
private DateTime _date;
private readonly List<ETFGroup> _etfGroups;
/// <summary>
/// Create a new leveraged ETF rebalancing alpha
/// </summary>
public RebalancingLeveragedETFAlphaModel(List<ETFGroup> etfGroups)
{
_etfGroups = etfGroups;
_date = DateTime.MinValue;
Name = "RebalancingLeveragedETFAlphaModel";
}
/// <summary>
/// Scan to see if the returns are greater than 1% at 2.15pm to emit an insight.
/// </summary>
public override IEnumerable<Insight> Update(QCAlgorithm algorithm, Slice data)
{
// Initialize:
var insights = new List<Insight>();
var magnitude = 0.0005;
// Paper suggests leveraged ETF's rebalance from 2.15pm - to close
// giving an insight period of 105 minutes.
var period = TimeSpan.FromMinutes(105);
if (algorithm.Time.Date != _date)
{
_date = algorithm.Time.Date;
// Save yesterday's price and reset the signal.
foreach (var group in _etfGroups)
{
var history = algorithm.History(group.Underlying, 1, Resolution.Daily);
group.YesterdayClose = history.Select(x => x.Close).FirstOrDefault();
}
}
// Check if the returns are > 1% at 14.15
if (algorithm.Time.Hour == 14 && algorithm.Time.Minute == 15)
{
foreach (var group in _etfGroups)
{
if (group.YesterdayClose == 0) continue;
var returns = (algorithm.Portfolio[group.Underlying].Price - group.YesterdayClose) / group.YesterdayClose;
if (returns > 0.01m)
{
insights.Add(Insight.Price(group.UltraLong, period, InsightDirection.Up, magnitude));
}
else if (returns < -0.01m)
{
insights.Add(Insight.Price(group.UltraShort, period, InsightDirection.Down, magnitude));
}
}
}
return insights;
}
}
class ETFGroup
{
public Symbol Underlying;
public Symbol UltraLong;
public Symbol UltraShort;
public decimal YesterdayClose;
/// <summary>
/// Group the underlying ETF and it's ultra ETFs
/// </summary>
/// <param name="underlying">The underlying indexETF</param>
/// <param name="ultraLong">The long-leveraged version of underlying ETF</param>
/// <param name="ultraShort">The short-leveraged version of the underlying ETF</param>
public ETFGroup(Symbol underlying, Symbol ultraLong, Symbol ultraShort)
{
Underlying = underlying;
UltraLong = ultraLong;
UltraShort = ultraShort;
}
}
}
@@ -0,0 +1,188 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using QuantConnect.Algorithm.Framework.Alphas;
using QuantConnect.Algorithm.Framework.Execution;
using QuantConnect.Algorithm.Framework.Portfolio;
using QuantConnect.Algorithm.Framework.Risk;
using QuantConnect.Algorithm.Framework.Selection;
using QuantConnect.Data;
using QuantConnect.Indicators;
using QuantConnect.Orders.Fees;
using System;
using System.Collections.Generic;
using System.Linq;
namespace QuantConnect.Algorithm.CSharp.Alphas
{
/// <summary>
/// A number of companies publicly trade two different classes of shares
/// in US equity markets. If both assets trade with reasonable volume, then
/// the underlying driving forces of each should be similar or the same. Given
/// this, we can create a relatively dollar-neutral long/short portfolio using
/// the dual share classes. Theoretically, any deviation of this portfolio from
/// its mean-value should be corrected, and so the motivating idea is based on
/// mean-reversion. Using a Simple Moving Average indicator, we can
/// compare the value of this portfolio against its SMA and generate insights
/// to buy the under-valued symbol and sell the over-valued symbol.
///
/// This alpha is part of the Benchmark Alpha Series created by QuantConnect which are open sourced so the community and client funds can see an example of an alpha.
/// </summary>
public class ShareClassMeanReversionAlpha : QCAlgorithm
{
public override void Initialize()
{
SetStartDate(2019, 1, 1);
SetCash(100000);
// Set zero transaction fees
SetSecurityInitializer(security => security.FeeModel = new ConstantFeeModel(0));
SetWarmUp(20);
// Setup Universe settings and tickers to be used
var symbols = new[] { "VIA", "VIAB" }
.Select(x => QuantConnect.Symbol.Create(x, SecurityType.Equity, Market.USA));
// Set requested data resolution
UniverseSettings.Resolution = Resolution.Minute;
SetUniverseSelection(new ManualUniverseSelectionModel(symbols));
// Use ShareClassMeanReversionAlphaModel to establish insights
SetAlpha(new ShareClassMeanReversionAlphaModel(symbols));
// Equally weigh securities in portfolio, based on insights
SetPortfolioConstruction(new EqualWeightingPortfolioConstructionModel());
// Set Immediate Execution Model
SetExecution(new ImmediateExecutionModel());
// Set Null Risk Management Model
SetRiskManagement(new NullRiskManagementModel());
}
private class ShareClassMeanReversionAlphaModel : AlphaModel
{
private const double _insightMagnitude = 0.001;
private readonly Symbol _longSymbol;
private readonly Symbol _shortSymbol;
private readonly TimeSpan _insightPeriod;
private readonly SimpleMovingAverage _sma;
private readonly RollingWindow<decimal> _positionWindow;
private decimal _alpha;
private decimal _beta;
private bool _invested;
public ShareClassMeanReversionAlphaModel(
IEnumerable<Symbol> symbols,
Resolution resolution = Resolution.Minute)
{
if (symbols.Count() != 2)
{
throw new ArgumentException("ShareClassMeanReversionAlphaModel: symbols parameter must contain 2 elements");
}
_longSymbol = symbols.ToArray()[0];
_shortSymbol = symbols.ToArray()[1];
_insightPeriod = resolution.ToTimeSpan().Multiply(5);
_sma = new SimpleMovingAverage(2);
_positionWindow = new RollingWindow<decimal>(2);
}
public override IEnumerable<Insight> Update(QCAlgorithm algorithm, Slice data)
{
// Check to see if either ticker will return a NoneBar, and skip the data slice if so
if (data.Bars.Count < 2)
{
return Enumerable.Empty<Insight>();
}
// If Alpha and Beta haven't been calculated yet, then do so
if (_alpha == 0 || _beta == 0)
{
CalculateAlphaBeta(algorithm);
}
// Update indicator and Rolling Window for each data slice passed into Update() method
if (!UpdateIndicators(data))
{
return Enumerable.Empty<Insight>();
}
// Check to see if the portfolio is invested. If no, then perform value comparisons and emit insights accordingly
if (!_invested)
{
//Reset invested boolean
_invested = true;
if (_positionWindow[0] > _sma)
{
return Insight.Group(new[]
{
Insight.Price(_longSymbol, _insightPeriod, InsightDirection.Down, _insightMagnitude),
Insight.Price(_shortSymbol, _insightPeriod, InsightDirection.Up, _insightMagnitude),
});
}
else
{
return Insight.Group(new[]
{
Insight.Price(_longSymbol, _insightPeriod, InsightDirection.Up, _insightMagnitude),
Insight.Price(_shortSymbol, _insightPeriod, InsightDirection.Down, _insightMagnitude),
});
}
}
// If the portfolio is invested and crossed back over the SMA, then emit flat insights
else if (_invested && CrossedMean())
{
_invested = false;
}
return Enumerable.Empty<Insight>();
}
/// <summary>
/// Calculate Alpha and Beta, the initial number of shares for each security needed to achieve a 50/50 weighting
/// </summary>
/// <param name="algorithm"></param>
private void CalculateAlphaBeta(QCAlgorithm algorithm)
{
_alpha = algorithm.CalculateOrderQuantity(_longSymbol, 0.5);
_beta = algorithm.CalculateOrderQuantity(_shortSymbol, 0.5);
algorithm.Log($"{algorithm.Time} :: Alpha: {_alpha} Beta: {_beta}");
}
/// <summary>
/// Calculate position value and update the SMA indicator and Rolling Window
/// </summary>
private bool UpdateIndicators(Slice data)
{
var positionValue = (_alpha * data[_longSymbol].Close) - (_beta * data[_shortSymbol].Close);
_sma.Update(data[_longSymbol].EndTime, positionValue);
_positionWindow.Add(positionValue);
return _sma.IsReady && _positionWindow.IsReady;
}
/// <summary>
/// Check to see if the position value has crossed the SMA and then return a boolean value
/// </summary>
/// <returns></returns>
private bool CrossedMean()
{
return (_positionWindow[0] >= _sma && _positionWindow[1] < _sma)
|| (_positionWindow[1] >= _sma && _positionWindow[0] < _sma);
}
}
}
}
@@ -0,0 +1,129 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using QuantConnect.Algorithm.Framework.Alphas;
using QuantConnect.Algorithm.Framework.Execution;
using QuantConnect.Algorithm.Framework.Portfolio;
using QuantConnect.Algorithm.Framework.Risk;
using QuantConnect.Algorithm.Framework.Selection;
using QuantConnect.Data;
using QuantConnect.Data.UniverseSelection;
using QuantConnect.Orders.Fees;
using System;
using System.Collections.Generic;
using System.Linq;
namespace QuantConnect.Algorithm.CSharp.Alphas
{
/// <summary>
/// Identify "pumped" penny stocks and predict that the price of a "Pumped" penny stock reverts to mean
///
/// This alpha is part of the Benchmark Alpha Series created by QuantConnect which are open sourced so the community and client funds can see an example of an alpha.
///</summary>
public class SykesShortMicroCapAlpha : QCAlgorithm
{
public override void Initialize()
{
SetStartDate(2018, 1, 1);
SetCash(100000);
// Set zero transaction fees
SetSecurityInitializer(security => security.FeeModel = new ConstantFeeModel(0));
// Select stocks using PennyStockUniverseSelectionModel
UniverseSettings.Resolution = Resolution.Daily;
SetUniverseSelection(new PennyStockUniverseSelectionModel());
// Use SykesShortMicroCapAlphaModel to establish insights
SetAlpha(new SykesShortMicroCapAlphaModel());
// Equally weigh securities in portfolio, based on insights
SetPortfolioConstruction(new EqualWeightingPortfolioConstructionModel());
// Set Immediate Execution Model
SetExecution(new ImmediateExecutionModel());
// Set Null Risk Management Model
SetRiskManagement(new NullRiskManagementModel());
}
/// <summary>
/// Performs coarse selection for constituents.
/// The stocks must have fundamental data
/// The stock must have positive previous-day close price
/// The stock must have volume between $1000000 and $10000 on the previous trading day
/// The stock must cost less than $5'''
/// </summary>
private class PennyStockUniverseSelectionModel : FundamentalUniverseSelectionModel
{
private const int _numberOfSymbolsCoarse = 500;
private int _lastMonth = -1;
public PennyStockUniverseSelectionModel() : base(false)
{
}
public override IEnumerable<Symbol> SelectCoarse(QCAlgorithm algorithm, IEnumerable<CoarseFundamental> coarse)
{
var month = algorithm.Time.Month;
if (month == _lastMonth)
{
return algorithm.Universe.Unchanged;
}
_lastMonth = month;
return (from cf in coarse
where cf.HasFundamentalData
where cf.Volume < 1000000
where cf.Volume > 10000
where cf.Price < 5
orderby cf.DollarVolume descending
select cf.Symbol).Take(_numberOfSymbolsCoarse);
}
}
/// <summary>
/// Uses ranking of intraday percentage difference between open price and close price to create magnitude and direction prediction for insights
/// </summary>
private class SykesShortMicroCapAlphaModel : AlphaModel
{
private readonly int _numberOfStocks;
private readonly TimeSpan _predictionInterval;
public SykesShortMicroCapAlphaModel(
int lookback = 1,
int numberOfStocks = 10,
Resolution resolution = Resolution.Daily)
{
_numberOfStocks = numberOfStocks;
_predictionInterval = resolution.ToTimeSpan().Multiply(lookback);
}
public override IEnumerable<Insight> Update(QCAlgorithm algorithm, Slice data)
{
return (
from entry in algorithm.ActiveSecurities
let security = entry.Value
where security.HasData && security.Open > 0
// Rank penny stocks on one day price change
let Magnitude = security.Close / security.Open - 1
orderby Math.Round(Magnitude, 6), security.Symbol descending
select Insight.Price(security.Symbol, _predictionInterval, InsightDirection.Down, Math.Abs((double)Magnitude)))
// Retrieve list of _numberOfStocks "pumped" penny stocks
.Take(_numberOfStocks);
}
}
}
}
@@ -0,0 +1,121 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using QuantConnect.Algorithm.Framework.Alphas;
using QuantConnect.Algorithm.Framework.Execution;
using QuantConnect.Algorithm.Framework.Portfolio;
using QuantConnect.Algorithm.Framework.Risk;
using QuantConnect.Algorithm.Framework.Selection;
using QuantConnect.Data;
using QuantConnect.Orders.Fees;
using System;
using System.Collections.Generic;
using System.Linq;
namespace QuantConnect.Algorithm.CSharp.Alphas
{
/// <summary>
/// In a perfect market, you could buy 100 EUR worth of USD, sell 100 EUR worth of GBP,
/// and then use the GBP to buy USD and wind up with the same amount in USD as you received when
/// you bought them with EUR. This relationship is expressed by the Triangle Exchange Rate, which is
///
/// Triangle Exchange Rate = (A/B) * (B/C) * (C/A)
///
/// where (A/B) is the exchange rate of A-to-B. In a perfect market, TER = 1, and so when
/// there is a mispricing in the market, then TER will not be 1 and there exists an arbitrage opportunity.
///
/// This alpha is part of the Benchmark Alpha Series created by QuantConnect which are open sourced so the community and client funds can see an example of an alpha.
/// </summary>
public class TriangleExchangeRateArbitrageAlpha : QCAlgorithm
{
public override void Initialize()
{
SetStartDate(2019, 2, 1);
SetCash(100000);
// Set zero transaction fees
SetSecurityInitializer(security => security.FeeModel = new ConstantFeeModel(0));
// Select trio of currencies to trade where
// Currency A = USD
// Currency B = EUR
// Currency C = GBP
var symbols = new[] { "EURUSD", "EURGBP", "GBPUSD" }
.Select(x => QuantConnect.Symbol.Create(x, SecurityType.Forex, Market.Oanda));
// Set requested data resolution
UniverseSettings.Resolution = Resolution.Minute;
SetUniverseSelection(new ManualUniverseSelectionModel(symbols));
// Use ForexTriangleArbitrageAlphaModel to establish insights
SetAlpha(new ForexTriangleArbitrageAlphaModel(symbols, Resolution.Minute));
// Equally weigh securities in portfolio, based on insights
SetPortfolioConstruction(new EqualWeightingPortfolioConstructionModel());
// Set Immediate Execution Model
SetExecution(new ImmediateExecutionModel());
// Set Null Risk Management Model
SetRiskManagement(new NullRiskManagementModel());
}
private class ForexTriangleArbitrageAlphaModel : AlphaModel
{
private readonly Symbol[] _symbols;
private readonly TimeSpan _insightPeriod;
public ForexTriangleArbitrageAlphaModel(
IEnumerable<Symbol> symbols,
Resolution resolution = Resolution.Minute)
{
_symbols = symbols.ToArray();
_insightPeriod = resolution.ToTimeSpan().Multiply(5);
}
public override IEnumerable<Insight> Update(QCAlgorithm algorithm, Slice data)
{
// Check to make sure all currency symbols are present
if (data.QuoteBars.Count < 3)
{
return Enumerable.Empty<Insight>();
}
// Extract QuoteBars for all three Forex securities
var barA = data[_symbols[0]];
var barB = data[_symbols[1]];
var barC = data[_symbols[2]];
// Calculate the triangle exchange rate
// Bid(Currency A -> Currency B) * Bid(Currency B -> Currency C) * Bid(Currency C -> Currency A)
// If exchange rates are priced perfectly, then this yield 1.If it is different than 1, then an arbitrage opportunity exists
var triangleRate = barA.Ask.Close / barB.Bid.Close / barC.Ask.Close;
// If the triangle rate is significantly different than 1, then emit insights
if (triangleRate > 1.0005m)
{
return Insight.Group(new[]
{
Insight.Price(_symbols[0], _insightPeriod, InsightDirection.Up, 0.0001),
Insight.Price(_symbols[1], _insightPeriod, InsightDirection.Down, 0.0001),
Insight.Price(_symbols[2], _insightPeriod, InsightDirection.Up, 0.0001)
});
}
return Enumerable.Empty<Insight>();
}
}
}
}
@@ -0,0 +1,102 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using QuantConnect.Algorithm.Framework.Alphas;
using QuantConnect.Algorithm.Framework.Execution;
using QuantConnect.Algorithm.Framework.Portfolio;
using QuantConnect.Algorithm.Framework.Risk;
using QuantConnect.Algorithm.Framework.Selection;
using QuantConnect.Data;
using QuantConnect.Orders.Fees;
using System;
using System.Collections.Generic;
namespace QuantConnect.Algorithm.CSharp.Alphas
{
/// <summary>
/// Leveraged ETFs (LETF) promise a fixed leverage ratio with respect to an underlying asset or an index.
/// A Triple-Leveraged ETF allows speculators to amplify their exposure to the daily returns of an underlying index by a factor of 3.
///
/// Increased volatility generally decreases the value of a LETF over an extended period of time as daily compounding is amplified.
///
/// This alpha emits short-biased insight to capitalize on volatility decay for each listed pair of TL-ETFs, by rebalancing the
/// ETFs with equal weights each day.
///
/// This alpha is part of the Benchmark Alpha Series created by QuantConnect which are open sourced so the community and client funds can see an example of an alpha.
/// </summary>
public class TripleLeveragedETFPairVolatilityDecayAlpha : QCAlgorithm
{
public override void Initialize()
{
SetStartDate(2018, 1, 1);
SetCash(100000);
// Set zero transaction fees
SetSecurityInitializer(security => security.FeeModel = new ConstantFeeModel(0));
// 3X ETF pair tickers
var ultraLong = QuantConnect.Symbol.Create("UGLD", SecurityType.Equity, Market.USA);
var ultraShort = QuantConnect.Symbol.Create("DGLD", SecurityType.Equity, Market.USA);
// Manually curated universe
UniverseSettings.Resolution = Resolution.Daily;
SetUniverseSelection(new ManualUniverseSelectionModel(new[] { ultraLong, ultraShort }));
// Select the demonstration alpha model
SetAlpha(new RebalancingTripleLeveragedETFAlphaModel(ultraLong, ultraShort));
// Equally weigh securities in portfolio, based on insights
SetPortfolioConstruction(new EqualWeightingPortfolioConstructionModel());
// Set Immediate Execution Model
SetExecution(new ImmediateExecutionModel());
// Set Null Risk Management Model
SetRiskManagement(new NullRiskManagementModel());
}
/// <summary>
/// Rebalance a pair of 3x leveraged ETFs and predict that the value of both ETFs in each pair will decrease.
/// </summary>
private class RebalancingTripleLeveragedETFAlphaModel : AlphaModel
{
private const double _magnitude = 0.001;
private readonly Symbol _ultraLong;
private readonly Symbol _ultraShort;
private readonly TimeSpan _period;
public RebalancingTripleLeveragedETFAlphaModel(Symbol ultraLong, Symbol ultraShort)
{
// Giving an insight period 1 days.
_period = QuantConnect.Time.OneDay;
_ultraLong = ultraLong;
_ultraShort = ultraShort;
Name = "RebalancingTripleLeveragedETFAlphaModel";
}
public override IEnumerable<Insight> Update(QCAlgorithm algorithm, Slice data)
{
return Insight.Group(new[]
{
Insight.Price(_ultraLong, _period, InsightDirection.Down, _magnitude),
Insight.Price(_ultraShort, _period, InsightDirection.Down, _magnitude)
});
}
}
}
}
@@ -0,0 +1,289 @@
/*
* 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.Algorithm.Framework.Alphas;
using QuantConnect.Algorithm.Framework.Execution;
using QuantConnect.Algorithm.Framework.Portfolio;
using QuantConnect.Algorithm.Framework.Risk;
using QuantConnect.Algorithm.Framework.Selection;
using QuantConnect.Brokerages;
using QuantConnect.Data;
using QuantConnect.Data.Consolidators;
using QuantConnect.Data.Market;
using QuantConnect.Data.UniverseSelection;
using QuantConnect.Indicators;
using QuantConnect.Orders.Fees;
namespace QuantConnect.Algorithm.CSharp.Alphas
{
/// <summary>
/// This is a demonstration algorithm. It trades UVXY.
/// Dual Thrust alpha model is used to produce insights.
/// Those input parameters have been chosen that gave acceptable results on a series
/// of random backtests run for the period from Oct, 2016 till Feb, 2019.
/// </summary>
class VIXDualThrustAlpha : QCAlgorithm
{
// -- STRATEGY INPUT PARAMETERS --
private decimal _k1 = 0.63m;
private decimal _k2 = 0.63m;
private int _rangePeriod = 20;
private int _consolidatorBars = 30;
// -- INITIALIZE --
public override void Initialize()
{
// Settings
SetStartDate(2016, 10, 01);
SetSecurityInitializer(s => s.SetFeeModel(new ConstantFeeModel(0m)));
SetBrokerageModel(BrokerageName.InteractiveBrokersBrokerage, AccountType.Margin);
// Universe Selection
UniverseSettings.Resolution = Resolution.Minute; // it's minute by default, but lets leave this param here
var symbols = new[] { QuantConnect.Symbol.Create("UVXY", SecurityType.Equity, Market.USA) };
SetUniverseSelection(new ManualUniverseSelectionModel(symbols));
// Warming up
var resolutionInTimeSpan = UniverseSettings.Resolution.ToTimeSpan();
var warmUpTimeSpan = resolutionInTimeSpan.Multiply(_consolidatorBars).Multiply(_rangePeriod);
SetWarmUp(warmUpTimeSpan);
// Alpha Model
SetAlpha(new DualThrustAlphaModel(_k1, _k2, _rangePeriod, UniverseSettings.Resolution, _consolidatorBars));
// Portfolio Construction
SetPortfolioConstruction(new EqualWeightingPortfolioConstructionModel());
// Execution
SetExecution(new ImmediateExecutionModel());
// Risk Management
SetRiskManagement(new MaximumDrawdownPercentPerSecurity(0.03m));
}
}
/// <summary>
/// Alpha model that uses dual-thrust strategy to create insights
/// https://medium.com/@FMZ_Quant/dual-thrust-trading-strategy-2cc74101a626
/// or here:
/// https://www.quantconnect.com/tutorials/strategy-library/dual-thrust-trading-algorithm
/// </summary>
public class DualThrustAlphaModel : AlphaModel
{
private readonly decimal _k1;
private readonly decimal _k2;
private readonly TimeSpan _consolidatorTimeSpan;
private readonly int _rangePeriod;
private readonly Dictionary<Symbol, SymbolData> _symbolDataBySymbol;
/// <summary>
/// Initializes a new instance of the class
/// </summary>
/// <param name="k1">Coefficient for upper band</param>
/// <param name="k2">Coefficient for lower band</param>
/// <param name="rangePeriod">Amount of last bars to calculate the range</param>
/// <param name="resolution">The resolution of data sent into the EMA indicators</param>
/// <param name="barsToConsolidate">If we want alpha o work on trade bars whose length is
/// different from the standard resolution - 1m 1h etc. - we need to pass this parameters along
/// with proper data resolution</param>
public DualThrustAlphaModel(
decimal k1,
decimal k2,
int rangePeriod,
Resolution resolution = Resolution.Daily,
int barsToConsolidate = 1
)
{
// coefficient that used to determine upper and lower borders of a breakout channel
_k1 = k1;
_k2 = k2;
// period the range is calculated over
_rangePeriod = rangePeriod;
// initialize with empty dict.
_symbolDataBySymbol = new Dictionary<Symbol, SymbolData>();
// time for bars we make the calculations on
_consolidatorTimeSpan = resolution.ToTimeSpan().Multiply(barsToConsolidate);
}
/// <summary>
/// Updates this alpha model with the latest data from the algorithm.
/// This is called each time the algorithm receives data for subscribed securities
/// </summary>
/// <param name="algorithm">The algorithm instance</param>
/// <param name="data">The new data available</param>
/// <returns>The new insights generated</returns>
public override IEnumerable<Insight> Update(QCAlgorithm algorithm, Slice data)
{
var insights = new List<Insight>();
// in 5 days after emission an insight is to be considered expired
int insightCloseAddDays = 5;
foreach (var symbolData in _symbolDataBySymbol.Values)
{
var range = symbolData.Range;
var symbol = symbolData.Symbol;
var security = algorithm.Securities[symbol];
if (symbolData.IsReady)
{
// buying condition
// - (1) price is above upper line
// - (2) and we are not long. this is a first time we crossed the line lately
if (security.Price > symbolData.UpperLine && !algorithm.Portfolio[symbol].IsLong)
{
DateTime insightCloseTimeUtc = algorithm.UtcTime.AddDays(insightCloseAddDays);
insights.Add(Insight.Price(symbolData.Symbol, insightCloseTimeUtc, InsightDirection.Up));
}
// selling condition
// - (1) price is lower that lower line
// - (2) and we are not short. this is a first time we crossed the line lately
if (security.Price < symbolData.LowerLine && !algorithm.Portfolio[symbol].IsShort)
{
DateTime insightCloseTimeUtc = algorithm.UtcTime.AddDays(insightCloseAddDays);
insights.Add(Insight.Price(symbolData.Symbol, insightCloseTimeUtc, InsightDirection.Down));
}
}
}
return insights;
}
/// <summary>
/// Event fired each time the we add/remove securities from the data feed
/// </summary>
/// <param name="algorithm">The algorithm instance that experienced the change in securities</param>
/// <param name="changes">The security additions and removals from the algorithm</param>
public override void OnSecuritiesChanged(QCAlgorithm algorithm, SecurityChanges changes)
{
// added
foreach (var added in changes.AddedSecurities)
{
SymbolData symbolData;
if (!_symbolDataBySymbol.TryGetValue(added.Symbol, out symbolData))
{
// add symbol/symbolData pair to collection
symbolData = new SymbolData(_rangePeriod, _consolidatorTimeSpan)
{
Symbol = added.Symbol,
K1 = _k1,
K2 = _k2
};
_symbolDataBySymbol[added.Symbol] = symbolData;
//register consolidator
algorithm.SubscriptionManager.AddConsolidator(added.Symbol, symbolData.GetConsolidator());
}
}
// removed
foreach (var removed in changes.RemovedSecurities)
{
SymbolData symbolData;
if (_symbolDataBySymbol.TryGetValue(removed.Symbol, out symbolData))
{
// unsubscribe consolidator from data updates
algorithm.SubscriptionManager.RemoveConsolidator(removed.Symbol, symbolData.GetConsolidator());
// remove item from dictionary collection
if (!_symbolDataBySymbol.Remove(removed.Symbol))
{
algorithm.Error("Unable to remove data from collection: DualThrustAlphaModel");
}
}
}
}
/// <summary>
/// Contains data specific to a symbol required by this model
/// </summary>
private class SymbolData
{
// rolling to contain items over the looking back period
private readonly RollingWindow<TradeBar> _rangeWindow;
// we calculate our logic on bars
private readonly TradeBarConsolidator _consolidator;
// current range value
public decimal Range { get; private set; }
// upper Line
public decimal UpperLine { get; private set; }
// lower Line
public decimal LowerLine { get; private set; }
// symbol value
public Symbol Symbol { get; set; }
// k1
public decimal K1 { private get; set; }
// k2
public decimal K2 { private get; set; }
// data is ready when rolling window is ready
public bool IsReady => _rangeWindow.IsReady;
/// <summary>
/// Main constructor for the class
/// </summary>
/// <param name="rangePeriod">Range period</param>
/// <param name="consolidatorResolution">Time length of consolidator</param>
public SymbolData(int rangePeriod, TimeSpan consolidatorResolution)
{
_rangeWindow = new RollingWindow<TradeBar>(rangePeriod);
_consolidator = new TradeBarConsolidator(consolidatorResolution);
// event fired at new consolidated trade bar
_consolidator.DataConsolidated += (sender, consolidated) =>
{
// add new tradebar to
_rangeWindow.Add(consolidated);
if (IsReady)
{
var hh = _rangeWindow.Select(x => x.High).Max();
var hc = _rangeWindow.Select(x => x.Close).Max();
var lc = _rangeWindow.Select(x => x.Close).Min();
var ll = _rangeWindow.Select(x => x.Low).Min();
Range = Math.Max(hh - lc, hc - ll);
UpperLine = consolidated.Close + K1 * Range;
LowerLine = consolidated.Close - K2 * Range;
}
};
}
/// <summary>
/// Returns the interior consolidator
/// </summary>
public TradeBarConsolidator GetConsolidator()
{
return _consolidator;
}
}
}
}
@@ -0,0 +1,33 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
namespace QuantConnect.Algorithm.CSharp
{
/// <summary>
/// Example algorithm using the asynchronous universe selection functionality
/// </summary>
public class AsynchronousUniverseRegressionAlgorithm : FundamentalRegressionAlgorithm
{
/// <summary>
/// Initialise the data and resolution required, as well as the cash and start-end dates for your algorithm. All algorithms must initialized.
/// </summary>
public override void Initialize()
{
base.Initialize();
UniverseSettings.Asynchronous = true;
}
}
}
@@ -0,0 +1,126 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.Collections.Generic;
using QuantConnect.Data;
using QuantConnect.Indicators;
using QuantConnect.Interfaces;
namespace QuantConnect.Algorithm.CSharp
{
/// <summary>
/// Regression algorithm to test the behaviour of ARMA versus AR models at the same order of differencing.
/// In particular, an ARIMA(1,1,1) and ARIMA(1,1,0) are instantiated while orders are placed if their difference
/// is sufficiently large (which would be due to the inclusion of the MA(1) term).
/// </summary>
public class AutoRegressiveIntegratedMovingAverageRegressionAlgorithm : QCAlgorithm, IRegressionAlgorithmDefinition
{
private AutoRegressiveIntegratedMovingAverage _arima;
private AutoRegressiveIntegratedMovingAverage _ar;
private decimal _last;
public override void Initialize()
{
SetStartDate(2013, 1, 07);
SetEndDate(2013, 12, 11);
Settings.AutomaticIndicatorWarmUp = true;
AddEquity("SPY", Resolution.Daily);
_arima = ARIMA("SPY", 1, 1, 1, 50);
_ar = ARIMA("SPY", 1, 1, 0, 50);
}
public override void OnData(Slice slice)
{
if (_arima.IsReady)
{
if (Math.Abs(_ar.Current.Value - _arima.Current.Value) > 1) // Difference due to MA(1) being included.
{
if (_arima.Current.Value > _last)
{
MarketOrder("SPY", 1);
}
else
{
MarketOrder("SPY", -1);
}
}
_last = _arima.Current.Value;
}
}
/// <summary>
/// This is used by the regression test system to indicate if the open source Lean repository has the required data to run this algorithm.
/// </summary>
public bool CanRunLocally { get; } = true;
/// <summary>
/// This is used by the regression test system to indicate which languages this algorithm is written in.
/// </summary>
public List<Language> Languages { get; } = new() { Language.CSharp, Language.Python };
/// <summary>
/// Data Points count of all timeslices of algorithm
/// </summary>
public long DataPoints => 1893;
/// <summary>
/// Data Points count of the algorithm history
/// </summary>
public int AlgorithmHistoryDataPoints => 100;
/// <summary>
/// Final status of the algorithm
/// </summary>
public AlgorithmStatus AlgorithmStatus => AlgorithmStatus.Completed;
/// <summary>
/// This is used by the regression test system to indicate what the expected statistics are from running the algorithm
/// </summary>
public Dictionary<string, string> ExpectedStatistics => new Dictionary<string, string>
{
{"Total Orders", "53"},
{"Average Win", "0.00%"},
{"Average Loss", "0.00%"},
{"Compounding Annual Return", "0.076%"},
{"Drawdown", "0.100%"},
{"Expectancy", "2.933"},
{"Start Equity", "100000"},
{"End Equity", "100070.90"},
{"Net Profit", "0.071%"},
{"Sharpe Ratio", "-9.164"},
{"Sortino Ratio", "-9.852"},
{"Probabilistic Sharpe Ratio", "0%"},
{"Loss Rate", "27%"},
{"Win Rate", "73%"},
{"Profit-Loss Ratio", "4.41"},
{"Alpha", "-0.008"},
{"Beta", "0.008"},
{"Annual Standard Deviation", "0.001"},
{"Annual Variance", "0"},
{"Information Ratio", "-1.961"},
{"Tracking Error", "0.092"},
{"Treynor Ratio", "-0.911"},
{"Total Fees", "$53.00"},
{"Estimated Strategy Capacity", "$16000000000.00"},
{"Lowest Capacity Asset", "SPY R735QTJ8XC9X"},
{"Portfolio Turnover", "0.02%"},
{"Drawdown Recovery", "50"},
{"OrderListHash", "685c37df6e4c49b75792c133be189094"}
};
}
}
@@ -0,0 +1,196 @@
/*
* 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.Data.Market;
using QuantConnect.Indicators;
using QuantConnect.Interfaces;
using QuantConnect.Securities;
namespace QuantConnect.Algorithm.CSharp
{
/// <summary>
/// Algorithm which tests indicator warm up using different data types, related to GH issue 4205
/// </summary>
public class AutomaticIndicatorWarmupDataTypeRegressionAlgorithm : QCAlgorithm, IRegressionAlgorithmDefinition
{
private Symbol _symbol;
public override void Initialize()
{
UniverseSettings.DataNormalizationMode = DataNormalizationMode.Raw;
Settings.AutomaticIndicatorWarmUp = true;
SetStartDate(2013, 10, 08);
SetEndDate(2013, 10, 10);
var SP500 = QuantConnect.Symbol.Create(Futures.Indices.SP500EMini, SecurityType.Future, Market.CME);
_symbol = FuturesChain(SP500).OrderBy(x => x.Symbol.ID.Date).First();
// Test case: custom IndicatorBase<QuoteBar> indicator using Future unsubscribed symbol
var indicator1 = new CustomIndicator();
AssertIndicatorState(indicator1, isReady: false);
WarmUpIndicator(_symbol, indicator1);
AssertIndicatorState(indicator1, isReady: true);
// Test case: SimpleMovingAverage<IndicatorDataPoint> using Future unsubscribed symbol (should use TradeBar)
var sma1 = new SimpleMovingAverage(10);
AssertIndicatorState(sma1, isReady: false);
WarmUpIndicator(_symbol, sma1);
AssertIndicatorState(sma1, isReady: true);
// Test case: SimpleMovingAverage<IndicatorDataPoint> using Equity unsubscribed symbol
var spy = QuantConnect.Symbol.Create("SPY", SecurityType.Equity, Market.USA);
var sma = new SimpleMovingAverage(10);
AssertIndicatorState(sma, isReady: false);
WarmUpIndicator(spy, sma);
AssertIndicatorState(sma, isReady: true);
// We add the symbol
AddFutureContract(_symbol);
AddEquity("SPY");
// force spy for use Raw data mode so that it matches the used when unsubscribed which uses the universe settings
SubscriptionManager.SubscriptionDataConfigService.GetSubscriptionDataConfigs(spy).SetDataNormalizationMode(DataNormalizationMode.Raw);
// Test case: custom IndicatorBase<QuoteBar> indicator using Future subscribed symbol
var indicator = new CustomIndicator();
var consolidator = CreateConsolidator(TimeSpan.FromMinutes(2), typeof(QuoteBar));
RegisterIndicator(_symbol, indicator, consolidator);
AssertIndicatorState(indicator, isReady: false);
WarmUpIndicator(_symbol, indicator);
AssertIndicatorState(indicator, isReady: true);
// Test case: SimpleMovingAverage<IndicatorDataPoint> using Future Subscribed symbol (should use TradeBar)
var sma11 = new SimpleMovingAverage(10);
AssertIndicatorState(sma11, isReady: false);
WarmUpIndicator(_symbol, sma11);
AssertIndicatorState(sma11, isReady: true);
if (!sma11.Current.Equals(sma1.Current))
{
throw new RegressionTestException("Expected SMAs warmed up before and after adding the Future to the algorithm to have the same current value. " +
"The result of 'WarmUpIndicator' shouldn't change if the symbol is or isn't subscribed");
}
// Test case: SimpleMovingAverage<IndicatorDataPoint> using Equity unsubscribed symbol
var smaSpy = new SimpleMovingAverage(10);
AssertIndicatorState(smaSpy, isReady: false);
WarmUpIndicator(spy, smaSpy);
AssertIndicatorState(smaSpy, isReady: true);
if (!smaSpy.Current.Equals(sma.Current))
{
throw new RegressionTestException("Expected SMAs warmed up before and after adding the Equity to the algorithm to have the same current value. " +
"The result of 'WarmUpIndicator' shouldn't change if the symbol is or isn't subscribed");
}
}
private void AssertIndicatorState(IIndicator indicator, bool isReady)
{
if (indicator.IsReady != isReady)
{
throw new RegressionTestException($"Expected indicator state, expected {isReady} but was {indicator.IsReady}");
}
}
/// <summary>
/// OnData event is the primary entry point for your algorithm. Each new data point will be pumped in here.
/// </summary>
/// <param name="data">Slice object keyed by symbol containing the stock data</param>
public override void OnData(Slice slice)
{
if (!Portfolio.Invested)
{
SetHoldings(_symbol, 0.5);
}
}
private class CustomIndicator : IndicatorBase<QuoteBar>, IIndicatorWarmUpPeriodProvider
{
private bool _isReady;
public int WarmUpPeriod => 1;
public override bool IsReady => _isReady;
public CustomIndicator() : base("Pepe")
{ }
protected override decimal ComputeNextValue(QuoteBar input)
{
_isReady = true;
return input.Ask.High;
}
}
/// <summary>
/// This is used by the regression test system to indicate if the open source Lean repository has the required data to run this algorithm.
/// </summary>
public bool CanRunLocally { get; } = true;
/// <summary>
/// This is used by the regression test system to indicate which languages this algorithm is written in.
/// </summary>
public List<Language> Languages { get; } = new() { Language.CSharp };
/// <summary>
/// Data Points count of all timeslices of algorithm
/// </summary>
public long DataPoints => 6426;
/// <summary>
/// Data Points count of the algorithm history
/// </summary>
public int AlgorithmHistoryDataPoints => 85;
/// <summary>
/// Final status of the algorithm
/// </summary>
public AlgorithmStatus AlgorithmStatus => AlgorithmStatus.Completed;
/// <summary>
/// This is used by the regression test system to indicate what the expected statistics are from running the algorithm
/// </summary>
public Dictionary<string, string> ExpectedStatistics => new Dictionary<string, string>
{
{"Total Orders", "1"},
{"Average Win", "0%"},
{"Average Loss", "0%"},
{"Compounding Annual Return", "733913.744%"},
{"Drawdown", "15.900%"},
{"Expectancy", "0"},
{"Start Equity", "100000"},
{"End Equity", "106827.7"},
{"Net Profit", "6.828%"},
{"Sharpe Ratio", "203744786353.299"},
{"Sortino Ratio", "0"},
{"Probabilistic Sharpe Ratio", "0%"},
{"Loss Rate", "0%"},
{"Win Rate", "0%"},
{"Profit-Loss Ratio", "0"},
{"Alpha", "456382350698.622"},
{"Beta", "9.229"},
{"Annual Standard Deviation", "2.24"},
{"Annual Variance", "5.017"},
{"Information Ratio", "228504036840.953"},
{"Tracking Error", "1.997"},
{"Treynor Ratio", "49450701625.717"},
{"Total Fees", "$23.65"},
{"Estimated Strategy Capacity", "$200000000.00"},
{"Lowest Capacity Asset", "ES VMKLFZIH2MTD"},
{"Portfolio Turnover", "351.80%"},
{"Drawdown Recovery", "1"},
{"OrderListHash", "dfd9a280d3c6470b305c03e0b72c234e"}
};
}
}
@@ -0,0 +1,127 @@
/*
* 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.Indicators;
using QuantConnect.Interfaces;
using System.Collections.Generic;
namespace QuantConnect.Algorithm.CSharp
{
/// <summary>
/// Regression algorithm asserting the behavior of the AutomaticIndicatorWarmUp on option greeks
/// </summary>
public class AutomaticIndicatorWarmupOptionIndicatorsMirrorContractsRegressionAlgorithm : QCAlgorithm, IRegressionAlgorithmDefinition
{
public override void Initialize()
{
SetStartDate(2015, 12, 24);
SetEndDate(2015, 12, 24);
Settings.AutomaticIndicatorWarmUp = true;
var underlying = "GOOG";
var resolution = Resolution.Minute;
var expiration = new DateTime(2015, 12, 24);
var strike = 650m;
var equity = AddEquity(underlying, resolution).Symbol;
var option = QuantConnect.Symbol.CreateOption(underlying, Market.USA, OptionStyle.American, OptionRight.Put, strike, expiration);
AddOptionContract(option, resolution);
// add the call counter side of the mirrored pair
var mirrorOption = QuantConnect.Symbol.CreateOption(underlying, Market.USA, OptionStyle.American, OptionRight.Call, strike, expiration);
AddOptionContract(mirrorOption, resolution);
var impliedVolatility = IV(option, mirrorOption);
var delta = D(option, mirrorOption, optionModel: OptionPricingModelType.BinomialCoxRossRubinstein, ivModel: OptionPricingModelType.BlackScholes);
var gamma = G(option, mirrorOption, optionModel: OptionPricingModelType.ForwardTree, ivModel: OptionPricingModelType.BlackScholes);
var vega = V(option, mirrorOption, optionModel: OptionPricingModelType.ForwardTree, ivModel: OptionPricingModelType.BlackScholes);
var theta = T(option, mirrorOption, optionModel: OptionPricingModelType.ForwardTree, ivModel: OptionPricingModelType.BlackScholes);
var rho = R(option, mirrorOption, optionModel: OptionPricingModelType.ForwardTree, ivModel: OptionPricingModelType.BlackScholes);
if (impliedVolatility == 0m || delta == 0m || gamma == 0m || vega == 0m || theta == 0m || rho == 0m)
{
throw new RegressionTestException("Expected IV/greeks calculated");
}
if (!impliedVolatility.IsReady || !delta.IsReady || !gamma.IsReady || !vega.IsReady || !theta.IsReady || !rho.IsReady)
{
throw new RegressionTestException("Expected IV/greeks to be ready");
}
Quit($"Implied Volatility: {impliedVolatility}, Delta: {delta}, Gamma: {gamma}, Vega: {vega}, Theta: {theta}, Rho: {rho}");
}
/// <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 => true;
/// <summary>
/// This is used by the regression test system to indicate which languages this algorithm is written in.
/// </summary>
public List<Language> Languages { get; } = new() { Language.CSharp };
/// <summary>
/// Data Points count of all timeslices of algorithm
/// </summary>
public long DataPoints => 0;
/// <summary>
/// Data Points count of the algorithm history
/// </summary>
public int AlgorithmHistoryDataPoints => 18;
/// <summary>
/// Final status of the algorithm
/// </summary>
public AlgorithmStatus AlgorithmStatus => AlgorithmStatus.Completed;
/// <summary>
/// This is used by the regression test system to indicate what the expected statistics are from running the algorithm
/// </summary>
public Dictionary<string, string> ExpectedStatistics => new Dictionary<string, string>
{
{"Total Orders", "0"},
{"Average Win", "0%"},
{"Average Loss", "0%"},
{"Compounding Annual Return", "0%"},
{"Drawdown", "0%"},
{"Expectancy", "0"},
{"Start Equity", "100000"},
{"End Equity", "100000"},
{"Net Profit", "0%"},
{"Sharpe Ratio", "0"},
{"Sortino Ratio", "0"},
{"Probabilistic Sharpe Ratio", "0%"},
{"Loss Rate", "0%"},
{"Win Rate", "0%"},
{"Profit-Loss Ratio", "0"},
{"Alpha", "0"},
{"Beta", "0"},
{"Annual Standard Deviation", "0"},
{"Annual Variance", "0"},
{"Information Ratio", "0"},
{"Tracking Error", "0"},
{"Treynor Ratio", "0"},
{"Total Fees", "$0.00"},
{"Estimated Strategy Capacity", "$0"},
{"Lowest Capacity Asset", ""},
{"Portfolio Turnover", "0%"},
{"Drawdown Recovery", "0"},
{"OrderListHash", "d41d8cd98f00b204e9800998ecf8427e"}
};
}
}
@@ -0,0 +1,158 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.Collections.Generic;
using System.Linq;
using QuantConnect.Data;
using QuantConnect.Indicators;
using QuantConnect.Interfaces;
namespace QuantConnect.Algorithm.CSharp
{
/// <summary>
/// Algorithm which reproduces GH issue 3861, where in some cases 2 consolidators were added when
/// using the automatic indicator warmup feature
/// </summary>
public class AutomaticIndicatorWarmupRegressionAlgorithm : QCAlgorithm, IRegressionAlgorithmDefinition
{
private Symbol _spy;
public override void Initialize()
{
SetStartDate(2013, 10, 07);
SetEndDate(2013, 10, 11);
Settings.AutomaticIndicatorWarmUp = true;
// Test case 1
_spy = AddEquity("SPY").Symbol;
var sma = SMA(_spy, 10);
if (!sma.IsReady)
{
throw new RegressionTestException("Expected SMA to be warmed up");
}
// Test case 2
var indicator = new CustomIndicator(10);
RegisterIndicator(_spy, indicator, Resolution.Minute, (Func<IBaseData, decimal>) null);
if (indicator.IsReady)
{
throw new RegressionTestException("Expected CustomIndicator Not to be warmed up");
}
WarmUpIndicator(_spy, indicator);
if (!indicator.IsReady)
{
throw new RegressionTestException("Expected CustomIndicator to be warmed up");
}
}
/// <summary>
/// OnData event is the primary entry point for your algorithm. Each new data point will be pumped in here.
/// </summary>
/// <param name="slice">Slice object keyed by symbol containing the stock data</param>
public override void OnData(Slice slice)
{
if (!Portfolio.Invested)
{
var subscription = SubscriptionManager.SubscriptionDataConfigService.GetSubscriptionDataConfigs(_spy).First(config => config.TickType == TickType.Trade);
// we expect 1 consolidator per indicator
if (subscription.Consolidators.Count != 2)
{
throw new RegressionTestException($"Unexpected consolidator count for subscription: {subscription.Consolidators.Count}");
}
SetHoldings(_spy, 1);
}
}
private class CustomIndicator : SimpleMovingAverage
{
private IndicatorDataPoint _previous;
public CustomIndicator(int period) : base(period)
{
}
protected override decimal ComputeNextValue(IReadOnlyWindow<IndicatorDataPoint> window, IndicatorDataPoint input)
{
if (_previous != null && input.EndTime == _previous.EndTime)
{
throw new RegressionTestException($"Unexpected indicator double data point call: {_previous}");
}
_previous = input;
return base.ComputeNextValue(window, input);
}
}
/// <summary>
/// This is used by the regression test system to indicate if the open source Lean repository has the required data to run this algorithm.
/// </summary>
public bool CanRunLocally { get; } = true;
/// <summary>
/// This is used by the regression test system to indicate which languages this algorithm is written in.
/// </summary>
public List<Language> Languages { get; } = new() { Language.CSharp };
/// <summary>
/// Data Points count of all timeslices of algorithm
/// </summary>
public long DataPoints => 3943;
/// <summary>
/// Data Points count of the algorithm history
/// </summary>
public int AlgorithmHistoryDataPoints => 40;
/// <summary>
/// Final status of the algorithm
/// </summary>
public AlgorithmStatus AlgorithmStatus => AlgorithmStatus.Completed;
/// <summary>
/// This is used by the regression test system to indicate what the expected statistics are from running the algorithm
/// </summary>
public Dictionary<string, string> ExpectedStatistics => new Dictionary<string, string>
{
{"Total Orders", "1"},
{"Average Win", "0%"},
{"Average Loss", "0%"},
{"Compounding Annual Return", "271.453%"},
{"Drawdown", "2.200%"},
{"Expectancy", "0"},
{"Start Equity", "100000"},
{"End Equity", "101691.92"},
{"Net Profit", "1.692%"},
{"Sharpe Ratio", "8.854"},
{"Sortino Ratio", "0"},
{"Probabilistic Sharpe Ratio", "67.459%"},
{"Loss Rate", "0%"},
{"Win Rate", "0%"},
{"Profit-Loss Ratio", "0"},
{"Alpha", "-0.005"},
{"Beta", "0.996"},
{"Annual Standard Deviation", "0.222"},
{"Annual Variance", "0.049"},
{"Information Ratio", "-14.565"},
{"Tracking Error", "0.001"},
{"Treynor Ratio", "1.97"},
{"Total Fees", "$3.44"},
{"Estimated Strategy Capacity", "$56000000.00"},
{"Lowest Capacity Asset", "SPY R735QTJ8XC9X"},
{"Portfolio Turnover", "19.93%"},
{"Drawdown Recovery", "3"},
{"OrderListHash", "3da9fa60bf95b9ed148b95e02e0cfc9e"}
};
}
}
@@ -0,0 +1,140 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
using System.Collections.Generic;
using System.Linq;
using QuantConnect.Interfaces;
using QuantConnect.Data.UniverseSelection;
using QuantConnect.Data.Market;
using QuantConnect.Securities;
namespace QuantConnect.Algorithm.CSharp
{
/// <summary>
/// Regression algorithm asserting that security are automatically seeded by default
/// </summary>
public abstract class AutomaticSeedBaseRegressionAlgorithm : QCAlgorithm, IRegressionAlgorithmDefinition
{
protected virtual bool ShouldHaveTradeData { get; }
protected virtual bool ShouldHaveQuoteData { get; }
protected virtual bool ShouldHaveOpenInterestData { get; }
protected virtual List<string> SecuritiesToIgnoreForChecking => Enumerable.Empty<string>().ToList();
public override void OnSecuritiesChanged(SecurityChanges changes)
{
var gotTrades = false;
var gotQuotes = false;
var gotOpenInterest = false;
var securitiesToCheck = changes.AddedSecurities.Where(x => (!x.Symbol.IsCanonical() || x.Symbol.SecurityType == SecurityType.Future) && !SecuritiesToIgnoreForChecking.Contains(x.Symbol.Value)).ToList();
foreach (var addedSecurity in securitiesToCheck)
{
if (addedSecurity.Price == 0)
{
throw new RegressionTestException("Security was not seeded");
}
if (!addedSecurity.HasData)
{
throw new RegressionTestException("Security does not have TradeBar or QuoteBar or OpenInterest data");
}
gotTrades |= addedSecurity.Cache.GetData<TradeBar>() != null;
gotQuotes |= addedSecurity.Cache.GetData<QuoteBar>() != null;
gotOpenInterest |= addedSecurity.Cache.GetData<OpenInterest>() != null;
}
if (securitiesToCheck.Count > 0)
{
if (ShouldHaveTradeData && !gotTrades)
{
throw new RegressionTestException("No contract had TradeBar data");
}
if (ShouldHaveQuoteData && !gotQuotes)
{
throw new RegressionTestException("No contract had QuoteBar data");
}
if (ShouldHaveOpenInterestData && !gotOpenInterest)
{
throw new RegressionTestException("No contract had OpenInterest 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 List<Language> Languages { get; } = new() { Language.CSharp };
/// <summary>
/// Data Points count of all timeslices of algorithm
/// </summary>
public abstract long DataPoints { get; }
/// <summary>
/// Data Points count of the algorithm history
/// </summary>
public abstract int AlgorithmHistoryDataPoints { get; }
/// <summary>
/// Final status of the algorithm
/// </summary>
public AlgorithmStatus AlgorithmStatus => AlgorithmStatus.Completed;
/// <summary>
/// This is used by the regression test system to indicate what the expected statistics are from running the algorithm
/// </summary>
public virtual Dictionary<string, string> ExpectedStatistics => new Dictionary<string, string>
{
{"Total Orders", "0"},
{"Average Win", "0%"},
{"Average Loss", "0%"},
{"Compounding Annual Return", "0%"},
{"Drawdown", "0%"},
{"Expectancy", "0"},
{"Start Equity", "100000"},
{"End Equity", "100000"},
{"Net Profit", "0%"},
{"Sharpe Ratio", "0"},
{"Sortino Ratio", "0"},
{"Probabilistic Sharpe Ratio", "0%"},
{"Loss Rate", "0%"},
{"Win Rate", "0%"},
{"Profit-Loss Ratio", "0"},
{"Alpha", "0"},
{"Beta", "0"},
{"Annual Standard Deviation", "0"},
{"Annual Variance", "0"},
{"Information Ratio", "0"},
{"Tracking Error", "0"},
{"Treynor Ratio", "0"},
{"Total Fees", "$0.00"},
{"Estimated Strategy Capacity", "$0"},
{"Lowest Capacity Asset", ""},
{"Portfolio Turnover", "0%"},
{"Drawdown Recovery", "0"},
{"OrderListHash", "d41d8cd98f00b204e9800998ecf8427e"}
};
}
}
@@ -0,0 +1,169 @@
/*
* 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.Interfaces;
using QuantConnect.Data.Market;
using System.Collections.Generic;
namespace QuantConnect.Algorithm.CSharp
{
/// <summary>
/// Example algorithm using and asserting the behavior of auxiliary Data handlers
/// </summary>
public class AuxiliaryDataHandlersRegressionAlgorithm : QCAlgorithm, IRegressionAlgorithmDefinition
{
private bool _onSplits;
private bool _onDividends;
private bool _onDelistingsCalled;
private bool _onSymbolChangedEvents;
/// <summary>
/// Initialise the data and resolution required, as well as the cash and start-end dates for your algorithm. All algorithms must initialized.
/// </summary>
public override void Initialize()
{
SetStartDate(2007, 05, 16);
SetEndDate(2015, 1, 1);
UniverseSettings.Resolution = Resolution.Daily;
// will get delisted
AddEquity("AAA.1");
// get's remapped
AddEquity("SPWR");
// has a split & dividends
AddEquity("AAPL");
}
public override void OnDelistings(Delistings delistings)
{
if (!delistings.ContainsKey("AAA.1"))
{
throw new RegressionTestException("Unexpected OnDelistings call");
}
_onDelistingsCalled = true;
}
public override void OnSymbolChangedEvents(SymbolChangedEvents symbolsChanged)
{
if (!symbolsChanged.ContainsKey("SPWR"))
{
throw new RegressionTestException("Unexpected OnSymbolChangedEvents call");
}
_onSymbolChangedEvents = true;
}
public override void OnSplits(Splits splits)
{
if (!splits.ContainsKey("AAPL"))
{
throw new RegressionTestException("Unexpected OnSplits call");
}
_onSplits = true;
}
public override void OnDividends(Dividends dividends)
{
if (!dividends.ContainsKey("AAPL"))
{
throw new RegressionTestException("Unexpected OnDividends call");
}
_onDividends = true;
}
public override void OnEndOfAlgorithm()
{
if (!_onDelistingsCalled)
{
throw new RegressionTestException("OnDelistings was not called!");
}
if (!_onSymbolChangedEvents)
{
throw new RegressionTestException("OnSymbolChangedEvents was not called!");
}
if (!_onSplits)
{
throw new RegressionTestException("OnSplits was not called!");
}
if (!_onDividends)
{
throw new RegressionTestException("OnDividends was not called!");
}
}
/// <summary>
/// This is used by the regression test system to indicate if the open source Lean repository has the required data to run this algorithm.
/// </summary>
public bool CanRunLocally { get; } = true;
/// <summary>
/// This is used by the regression test system to indicate which languages this algorithm is written in.
/// </summary>
public List<Language> Languages { get; } = new() { Language.CSharp, Language.Python };
/// <summary>
/// Data Points count of all timeslices of algorithm
/// </summary>
public long DataPoints => 15347;
/// <summary>
/// Data Points count of the algorithm history
/// </summary>
public int AlgorithmHistoryDataPoints => 0;
/// <summary>
/// Final status of the algorithm
/// </summary>
public AlgorithmStatus AlgorithmStatus => AlgorithmStatus.Completed;
/// <summary>
/// This is used by the regression test system to indicate what the expected statistics are from running the algorithm
/// </summary>
public Dictionary<string, string> ExpectedStatistics => new Dictionary<string, string>
{
{"Total Orders", "0"},
{"Average Win", "0%"},
{"Average Loss", "0%"},
{"Compounding Annual Return", "0%"},
{"Drawdown", "0%"},
{"Expectancy", "0"},
{"Start Equity", "100000"},
{"End Equity", "100000"},
{"Net Profit", "0%"},
{"Sharpe Ratio", "0"},
{"Sortino Ratio", "0"},
{"Probabilistic Sharpe Ratio", "0%"},
{"Loss Rate", "0%"},
{"Win Rate", "0%"},
{"Profit-Loss Ratio", "0"},
{"Alpha", "0"},
{"Beta", "0"},
{"Annual Standard Deviation", "0"},
{"Annual Variance", "0"},
{"Information Ratio", "-0.332"},
{"Tracking Error", "0.183"},
{"Treynor Ratio", "0"},
{"Total Fees", "$0.00"},
{"Estimated Strategy Capacity", "$0"},
{"Lowest Capacity Asset", ""},
{"Portfolio Turnover", "0%"},
{"Drawdown Recovery", "0"},
{"OrderListHash", "d41d8cd98f00b204e9800998ecf8427e"}
};
}
}
@@ -0,0 +1,156 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System.Collections.Generic;
using QuantConnect.Data;
using QuantConnect.Interfaces;
using QuantConnect.Orders;
namespace QuantConnect.Algorithm.CSharp
{
/// <summary>
/// Regression algorithm asserting that in backtesting, orders are submitted in the same time step even when asynchronous
/// </summary>
public class BacktestingAsynchronousOrdersRegressionAlgorithm : QCAlgorithm, IRegressionAlgorithmDefinition
{
private Symbol _symbol;
public override void Initialize()
{
SetStartDate(2013, 10, 07);
SetEndDate(2013, 10, 08);
SetCash(100000);
_symbol = AddEquity("SPY").Symbol;
}
public override void OnData(Slice slice)
{
if (!Portfolio.Invested)
{
var marketOrderTicket = MarketOrder(_symbol, 100, asynchronous: false);
AssertMarketOrderStatus(marketOrderTicket);
var asyncMarketOrderTicket = MarketOrder(_symbol, -100, asynchronous: true);
AssertMarketOrderStatus(asyncMarketOrderTicket);
var limitPrice = Securities[_symbol].Price * 0.95m;
var limitOrderTicket = LimitOrder(_symbol, 100, limitPrice, asynchronous: false);
AssertLimitOrderStatus(limitOrderTicket);
var asyncLimitOrderTicket = LimitOrder(_symbol, -100, limitPrice, asynchronous: true);
AssertLimitOrderStatus(asyncLimitOrderTicket);
}
}
private static void AssertMarketOrderStatus(OrderTicket ticket)
{
// In backtesting the order should be submitted and filled right away.
// Note that OrderSet event will not be fired if there is an error when processing the order submission,
// but this is a happy case
if (!ticket.OrderSet.WaitOne(0))
{
throw new RegressionTestException("Order was not submitted immediately in backtesting mode");
}
if (!ticket.OrderClosed.WaitOne(0))
{
throw new RegressionTestException("Order was not filled immediately in backtesting mode");
}
if (ticket.Status != OrderStatus.Filled)
{
throw new RegressionTestException($"Order status is not filled: {ticket.Status}");
}
}
private static void AssertLimitOrderStatus(OrderTicket ticket)
{
// In backtesting the order should be submitted right away but not filled since price hasn't moved even when asynchronous
// Note that OrderSet event will not be fired if there is an error when processing the order submission,
// but this is a happy case
if (!ticket.OrderSet.WaitOne(0))
{
throw new RegressionTestException("Asynchronous limit order was not submitted immediately in backtesting mode");
}
if (ticket.OrderClosed.WaitOne(0))
{
throw new RegressionTestException("Asynchronous limit order was filled immediately in backtesting mode when it shouldn't");
}
if (ticket.Status != OrderStatus.Submitted)
{
throw new RegressionTestException($"Order status is not submitted: {ticket.Status}");
}
}
/// <summary>
/// This is used by the regression test system to indicate if the open source Lean repository has the required data to run this algorithm.
/// </summary>
public bool CanRunLocally { get; } = true;
/// <summary>
/// This is used by the regression test system to indicate which languages this algorithm is written in.
/// </summary>
public List<Language> Languages { get; } = new() { Language.CSharp };
/// <summary>
/// Data Points count of all timeslices of algorithm
/// </summary>
public long DataPoints => 1582;
/// <summary>
/// Data Points count of the algorithm history
/// </summary>
public int AlgorithmHistoryDataPoints => 0;
/// <summary>
/// Final status of the algorithm
/// </summary>
public AlgorithmStatus AlgorithmStatus => AlgorithmStatus.Completed;
/// <summary>
/// This is used by the regression test system to indicate what the expected statistics are from running the algorithm
/// </summary>
public Dictionary<string, string> ExpectedStatistics => new Dictionary<string, string>
{
{"Total Orders", "4"},
{"Average Win", "0%"},
{"Average Loss", "0%"},
{"Compounding Annual Return", "0%"},
{"Drawdown", "0%"},
{"Expectancy", "0"},
{"Start Equity", "100000"},
{"End Equity", "100168.20"},
{"Net Profit", "0%"},
{"Sharpe Ratio", "0"},
{"Sortino Ratio", "0"},
{"Probabilistic Sharpe Ratio", "0%"},
{"Loss Rate", "0%"},
{"Win Rate", "0%"},
{"Profit-Loss Ratio", "0"},
{"Alpha", "0"},
{"Beta", "0"},
{"Annual Standard Deviation", "0"},
{"Annual Variance", "0"},
{"Information Ratio", "0"},
{"Tracking Error", "0"},
{"Treynor Ratio", "0"},
{"Total Fees", "$3.00"},
{"Estimated Strategy Capacity", "$22000000.00"},
{"Lowest Capacity Asset", "SPY R735QTJ8XC9X"},
{"Portfolio Turnover", "21.72%"},
{"Drawdown Recovery", "0"},
{"OrderListHash", "65f010e904a929e5383f0920a3c5b797"}
};
}
}
@@ -0,0 +1,346 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using QuantConnect.Data;
using QuantConnect.Data.Market;
using QuantConnect.Interfaces;
using QuantConnect.Orders;
using QuantConnect.Orders.Fees;
using QuantConnect.Orders.Fills;
using QuantConnect.Securities;
using QuantConnect.Securities.Option;
using System;
using System.Collections.Generic;
using System.Linq;
namespace QuantConnect.Algorithm.CSharp
{
/// <summary>
/// This regression algorithm tests the order processing of the backtesting brokerage.
/// We open an equity position that should fill in two parts, on two different bars.
/// We open a long option position and let it expire so we can exercise the position.
/// To check the orders we use OnOrderEvent and throw exceptions if verification fails.
/// </summary>
/// <meta name="tag" content="backtesting brokerage" />
/// <meta name="tag" content="regression test" />
/// <meta name="tag" content="options" />
class BacktestingBrokerageRegressionAlgorithm : QCAlgorithm, IRegressionAlgorithmDefinition
{
private Security _security;
private Symbol _spy;
private OrderTicket _equityBuy;
private Option _option;
private Symbol _optionSymbol;
private OrderTicket _optionBuy;
private bool _optionBought = false;
private bool _equityBought = false;
private decimal _optionStrikePrice;
/// <summary>
/// Initialize the algorithm
/// </summary>
public override void Initialize()
{
SetCash(100000);
SetStartDate(2015, 12, 24);
SetEndDate(2015, 12, 28);
// Get our equity
_security = AddEquity("SPY", Resolution.Hour);
_security.SetFillModel(new PartialMarketFillModel(2));
_spy = _security.Symbol;
// Get our option
_option = AddOption("GOOG");
_option.SetFilter(u => u.IncludeWeeklys()
.Strikes(-2, +2)
.Expiration(TimeSpan.Zero, TimeSpan.FromDays(10)));
_optionSymbol = _option.Symbol;
}
/// <summary>
/// OnData event is the primary entry point for your algorithm. Each new data point will be pumped in here.
/// </summary>
/// <param name="data">Slice object keyed by symbol containing the stock data</param>
public override void OnData(Slice data)
{
if (!_equityBought && data.ContainsKey(_spy))
{
//Buy our Equity.
//Quantity is rounded down to an even number since it will be split in two equal halves
var quantity = Math.Floor(CalculateOrderQuantity(_spy, .1m) / 2) * 2;
_equityBuy = MarketOrder(_spy, quantity, asynchronous: true);
_equityBought = true;
}
if (!_optionBought)
{
// Buy our option
OptionChain chain;
if (data.OptionChains.TryGetValue(_optionSymbol, out chain))
{
// Find the second call strike under market price expiring today
var contracts = (
from optionContract in chain.OrderByDescending(x => x.Strike)
where optionContract.Right == OptionRight.Call
where optionContract.Expiry == Time.Date
where optionContract.Strike < chain.Underlying.Price
select optionContract
).Take(2);
if (contracts.Any())
{
var optionToBuy = contracts.FirstOrDefault();
_optionStrikePrice = optionToBuy.Strike;
_optionBuy = MarketOrder(optionToBuy.Symbol, 1);
_optionBought = true;
}
}
}
}
/// <summary>
/// All order events get pushed through this function
/// </summary>
/// <param name="orderEvent">OrderEvent object that contains all the information about the event</param>
public override void OnOrderEvent(OrderEvent orderEvent)
{
// Get the order from our transactions
var order = Transactions.GetOrderById(orderEvent.OrderId);
// Based on the type verify the order
switch (order.Type)
{
case OrderType.Market:
VerifyMarketOrder(order, orderEvent);
break;
case OrderType.OptionExercise:
VerifyOptionExercise(order, orderEvent);
break;
default:
throw new ArgumentOutOfRangeException();
}
}
/// <summary>
/// To verify Market orders is process correctly
/// </summary>
/// <param name="order">Order object to analyze</param>
public void VerifyMarketOrder(Order order, OrderEvent orderEvent)
{
switch (order.Status)
{
case OrderStatus.Submitted:
break;
// All PartiallyFilled orders should have a LastFillTime
case OrderStatus.PartiallyFilled:
if (order.LastFillTime == null)
{
throw new RegressionTestException("LastFillTime should not be null");
}
if (order.Quantity / 2 != orderEvent.FillQuantity)
{
throw new RegressionTestException("Order size should be half");
}
break;
// All filled equity orders should have filled after creation because of our fill model!
case OrderStatus.Filled:
if (order.SecurityType == SecurityType.Equity && order.CreatedTime == order.LastFillTime)
{
throw new RegressionTestException("Order should not finish during the CreatedTime bar");
}
break;
default:
throw new ArgumentOutOfRangeException();
}
}
/// <summary>
/// To verify OptionExercise orders is process correctly
/// </summary>
/// <param name="order">Order object to analyze</param>
public void VerifyOptionExercise(Order order, OrderEvent orderEvent)
{
// If the option price isn't the same as the strike price, its incorrect
if (order.Price != _optionStrikePrice)
{
throw new RegressionTestException("OptionExercise order price should be strike price!!");
}
if (orderEvent.Quantity != -1)
{
throw new RegressionTestException("OrderEvent Quantity should be -1");
}
}
/// <summary>
/// Runs after algorithm, used to check our portfolio and orders
/// </summary>
public override void OnEndOfAlgorithm()
{
if (!Portfolio.ContainsKey(_optionBuy.Symbol) || !Portfolio.ContainsKey(_optionBuy.Symbol.Underlying) || !Portfolio.ContainsKey(_equityBuy.Symbol))
{
throw new RegressionTestException("Portfolio does not contain the Symbols we purchased");
}
//Check option holding, should not be invested since it expired, profit should be -400
var optionHolding = Portfolio[_optionBuy.Symbol];
if (optionHolding.Invested || optionHolding.Profit != -400)
{
throw new RegressionTestException("Options holding does not match expected outcome");
}
//Check the option underlying symbol since we should have bought it at exercise
//Quantity should be 100, AveragePrice should be option strike price
var optionExerciseHolding = Portfolio[_optionBuy.Symbol.Underlying];
if (!optionExerciseHolding.Invested || optionExerciseHolding.Quantity != 100 || optionExerciseHolding.AveragePrice != _optionBuy.Symbol.ID.StrikePrice)
{
throw new RegressionTestException("Equity holding for exercised option does not match expected outcome");
}
//Check equity holding, should be invested, profit should be
//Quantity should be 52, AveragePrice should be ticket AverageFillPrice
var equityHolding = Portfolio[_equityBuy.Symbol];
if (!equityHolding.Invested || equityHolding.Quantity != 52 || equityHolding.AveragePrice != _equityBuy.AverageFillPrice)
{
throw new RegressionTestException("Equity holding does not match expected outcome");
}
}
/// <summary>
/// PartialMarketFillModel that allows the user to set the number of fills and restricts
/// the fill to only one per bar.
/// </summary>
private class PartialMarketFillModel : ImmediateFillModel
{
private readonly decimal _percent;
private readonly Dictionary<long, decimal> _absoluteRemainingByOrderId = new Dictionary<long, decimal>();
/// <param name="numberOfFills"></param>
public PartialMarketFillModel(int numberOfFills = 1)
{
_percent = 1m / numberOfFills;
}
/// <summary>
/// Performs partial market fills once per time step
/// </summary>
/// <param name="asset">The security being ordered</param>
/// <param name="order">The order</param>
/// <returns>The order fill</returns>
public override OrderEvent MarketFill(Security asset, MarketOrder order)
{
var currentUtcTime = asset.LocalTime.ConvertToUtc(asset.Exchange.TimeZone);
// Only fill once a time slice
if (order.LastFillTime != null && currentUtcTime <= order.LastFillTime)
{
return new OrderEvent(order, currentUtcTime, OrderFee.Zero);
}
decimal absoluteRemaining;
if (!_absoluteRemainingByOrderId.TryGetValue(order.Id, out absoluteRemaining))
{
absoluteRemaining = order.AbsoluteQuantity;
_absoluteRemainingByOrderId.Add(order.Id, order.AbsoluteQuantity);
}
var fill = base.MarketFill(asset, order);
var absoluteFillQuantity = (int)(Math.Min(absoluteRemaining, (int)(_percent * order.Quantity)));
fill.FillQuantity = Math.Sign(order.Quantity) * absoluteFillQuantity;
if (absoluteRemaining == absoluteFillQuantity)
{
fill.Status = OrderStatus.Filled;
_absoluteRemainingByOrderId.Remove(order.Id);
}
else
{
absoluteRemaining = absoluteRemaining - absoluteFillQuantity;
_absoluteRemainingByOrderId[order.Id] = absoluteRemaining;
fill.Status = OrderStatus.PartiallyFilled;
}
return fill;
}
}
/// <summary>
/// This is used by the regression test system to indicate if the open source Lean repository has the required data to run this algorithm.
/// </summary>
public bool CanRunLocally { get; } = true;
/// <summary>
/// This is used by the regression test system to indicate which languages this algorithm is written in.
/// </summary>
public List<Language> Languages { get; } = new() { Language.CSharp };
/// <summary>
/// Data Points count of all timeslices of algorithm
/// </summary>
public long DataPoints => 27071;
/// <summary>
/// Data Points count of the algorithm history
/// </summary>
public int AlgorithmHistoryDataPoints => 0;
/// <summary>
/// Final status of the algorithm
/// </summary>
public AlgorithmStatus AlgorithmStatus => AlgorithmStatus.Completed;
/// <summary>
/// This is used by the regression test system to indicate what the expected statistics are from running the algorithm
/// </summary>
public Dictionary<string, string> ExpectedStatistics => new Dictionary<string, string>
{
{"Total Orders", "3"},
{"Average Win", "0%"},
{"Average Loss", "-0.40%"},
{"Compounding Annual Return", "119.386%"},
{"Drawdown", "0.800%"},
{"Expectancy", "-1"},
{"Start Equity", "100000"},
{"End Equity", "101082.06"},
{"Net Profit", "1.082%"},
{"Sharpe Ratio", "12.594"},
{"Sortino Ratio", "0"},
{"Probabilistic Sharpe Ratio", "95.481%"},
{"Loss Rate", "100%"},
{"Win Rate", "0%"},
{"Profit-Loss Ratio", "0"},
{"Alpha", "0.504"},
{"Beta", "-6.672"},
{"Annual Standard Deviation", "0.111"},
{"Annual Variance", "0.012"},
{"Information Ratio", "12.001"},
{"Tracking Error", "0.127"},
{"Treynor Ratio", "-0.209"},
{"Total Fees", "$2.00"},
{"Estimated Strategy Capacity", "$0"},
{"Lowest Capacity Asset", "GOOCV VP83T1ZUHROL"},
{"Portfolio Turnover", "17.02%"},
{"Drawdown Recovery", "4"},
{"OrderListHash", "1be5073f2cf8802ffa163f7dab7d040e"}
};
}
}
@@ -0,0 +1,100 @@
/*
* 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.Algorithm.Framework.Alphas;
using QuantConnect.Algorithm.Framework.Execution;
using QuantConnect.Algorithm.Framework.Portfolio;
using QuantConnect.Algorithm.Framework.Risk;
using QuantConnect.Algorithm.Framework.Selection;
using QuantConnect.Interfaces;
namespace QuantConnect.Algorithm.CSharp
{
/// <summary>
/// Abstract regression framework algorithm for multiple framework regression tests
/// </summary>
public abstract class BaseFrameworkRegressionAlgorithm : QCAlgorithm, IRegressionAlgorithmDefinition
{
public override void Initialize()
{
SetStartDate(2014, 6, 1);
SetEndDate(2014, 6, 30);
UniverseSettings.Resolution = Resolution.Hour;
UniverseSettings.DataNormalizationMode = DataNormalizationMode.Raw;
var symbols = new[] { "AAPL", "AIG", "BAC", "SPY" }
.Select(ticker => QuantConnect.Symbol.Create(ticker, SecurityType.Equity, Market.USA))
.ToList();
// Manually add AAPL and AIG when the algorithm starts
SetUniverseSelection(new ManualUniverseSelectionModel(symbols.Take(2)));
// At midnight, add all securities every day except on the last data
// With this procedure, the Alpha Model will experience multiple universe changes
AddUniverseSelection(new ScheduledUniverseSelectionModel(
DateRules.EveryDay(), TimeRules.Midnight,
dt => dt < EndDate.AddDays(-1) ? symbols : Enumerable.Empty<Symbol>()));
SetAlpha(new ConstantAlphaModel(InsightType.Price, InsightDirection.Up, TimeSpan.FromDays(31), 0.025, null));
SetPortfolioConstruction(new EqualWeightingPortfolioConstructionModel());
SetExecution(new ImmediateExecutionModel());
SetRiskManagement(new NullRiskManagementModel());
}
public override void OnEndOfAlgorithm()
{
// The base implementation checks for active insights
var insightsCount = Insights.GetInsights(insight => insight.IsActive(UtcTime)).Count;
if (insightsCount != 0)
{
throw new RegressionTestException($"The number of active insights should be 0. Actual: {insightsCount}");
}
}
/// <summary>
/// This is used by the regression test system to indicate if the open source Lean repository has the required data to run this algorithm.
/// </summary>
public bool CanRunLocally { get; } = true;
/// <summary>
/// This is used by the regression test system to indicate which languages this algorithm is written in.
/// </summary>
public virtual List<Language> Languages { get; } = new() { Language.CSharp, Language.Python };
/// <summary>
/// Data Points count of all timeslices of algorithm
/// </summary>
public virtual long DataPoints => 764;
/// <summary>
/// Data Points count of the algorithm history
/// </summary>
public virtual int AlgorithmHistoryDataPoints => 0;
/// <summary>
/// Final status of the algorithm
/// </summary>
public AlgorithmStatus AlgorithmStatus => AlgorithmStatus.Completed;
/// <summary>
/// This is used by the regression test system to indicate what the expected statistics are from running the algorithm
/// </summary>
public abstract Dictionary<string, string> ExpectedStatistics { get; }
}
}
@@ -0,0 +1,66 @@
/*
* 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 Python.Runtime;
namespace QuantConnect.Algorithm.CSharp
{
public class BasicPythonIntegrationTemplateAlgorithm : QCAlgorithm
{
// Create class field for numpy library
private dynamic _numpy;
public override void Initialize()
{
SetStartDate(2013, 10, 7); // Set Start Date
SetEndDate(2013, 10, 11); // Set End Date
SetCash(100000); //Set Strategy Cash
AddEquity("SPY", Resolution.Minute);
// Assign numpy library
using (Py.GIL())
{
_numpy = Py.Import("numpy");
}
}
private decimal ComputeSin(decimal value)
{
// Calculate python sin(10)
using (Py.GIL())
{
return (decimal)_numpy.sin(value);
}
}
/// OnData event is the primary entry point for your algorithm. Each new data point will be pumped in here.
/// Slice object keyed by symbol containing the stock data
public override void OnData(Slice slice)
{
if (!Portfolio.Invested)
{
SetHoldings("SPY", 1);
var sin = ComputeSin(10);
// Calculate C# sin(10)
var sinOfTen = Math.Sin(10);
Debug($"According to Python, the value of sin(10) is: {sin}");
Debug($"According to C#, the value of sin(10) is: {sinOfTen}");
}
}
}
}
@@ -0,0 +1,122 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System.Collections.Generic;
using QuantConnect.Brokerages;
using QuantConnect.Data;
using QuantConnect.Interfaces;
namespace QuantConnect.Algorithm.CSharp
{
/// <summary>
/// Basic algorithm using SetAccountCurrency
/// </summary>
public class BasicSetAccountCurrencyAlgorithm : QCAlgorithm, IRegressionAlgorithmDefinition
{
private Symbol _btcEur;
/// <summary>
/// Initialise the data and resolution required, as well as the cash and start-end dates for your algorithm. All algorithms must initialized.
/// </summary>
public override void Initialize()
{
SetStartDate(2018, 04, 04); //Set Start Date
SetEndDate(2018, 04, 04); //Set End Date
SetBrokerageModel(BrokerageName.GDAX, AccountType.Cash);
SetAccountCurrency();
_btcEur = AddCrypto("BTCEUR").Symbol;
}
public virtual void SetAccountCurrency()
{
//Before setting any cash or adding a Security call SetAccountCurrency
SetAccountCurrency("EUR");
SetCash(100000); //Set Strategy Cash
}
/// <summary>
/// OnData event is the primary entry point for your algorithm. Each new data point will be pumped in here.
/// </summary>
/// <param name="data">Slice object keyed by symbol containing the stock data</param>
public override void OnData(Slice slice)
{
if (!Portfolio.Invested)
{
SetHoldings(_btcEur, 1);
Debug("Purchased Stock");
}
}
/// <summary>
/// This is used by the regression test system to indicate if the open source Lean repository has the required data to run this algorithm.
/// </summary>
public bool CanRunLocally { get; } = true;
/// <summary>
/// This is used by the regression test system to indicate which languages this algorithm is written in.
/// </summary>
public List<Language> Languages { get; } = new() { Language.CSharp, Language.Python };
/// <summary>
/// Data Points count of all timeslices of algorithm
/// </summary>
public long DataPoints => 4319;
/// <summary>
/// Data Points count of the algorithm history
/// </summary>
public int AlgorithmHistoryDataPoints => 15;
/// <summary>
/// Final status of the algorithm
/// </summary>
public AlgorithmStatus AlgorithmStatus => AlgorithmStatus.Completed;
/// <summary>
/// This is used by the regression test system to indicate what the expected statistics are from running the algorithm
/// </summary>
public Dictionary<string, string> ExpectedStatistics => new Dictionary<string, string>
{
{"Total Orders", "1"},
{"Average Win", "0%"},
{"Average Loss", "0%"},
{"Compounding Annual Return", "0%"},
{"Drawdown", "0%"},
{"Expectancy", "0"},
{"Start Equity", "100000.00"},
{"End Equity", "92395.59"},
{"Net Profit", "0%"},
{"Sharpe Ratio", "0"},
{"Sortino Ratio", "0"},
{"Probabilistic Sharpe Ratio", "0%"},
{"Loss Rate", "0%"},
{"Win Rate", "0%"},
{"Profit-Loss Ratio", "0"},
{"Alpha", "0"},
{"Beta", "0"},
{"Annual Standard Deviation", "0"},
{"Annual Variance", "0"},
{"Information Ratio", "0"},
{"Tracking Error", "0"},
{"Treynor Ratio", "0"},
{"Total Fees", "€298.35"},
{"Estimated Strategy Capacity", "€85000.00"},
{"Lowest Capacity Asset", "BTCEUR 2XR"},
{"Portfolio Turnover", "107.64%"},
{"Drawdown Recovery", "0"},
{"OrderListHash", "6819dc936b86af6e4b89b6017b7d5284"}
};
}
}
@@ -0,0 +1,92 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System.Collections.Generic;
using QuantConnect.Interfaces;
namespace QuantConnect.Algorithm.CSharp
{
/// <summary>
/// Basic algorithm using SetAccountCurrency with an amount
/// </summary>
public class BasicSetAccountCurrencyWithAmountAlgorithm : BasicSetAccountCurrencyAlgorithm, IRegressionAlgorithmDefinition
{
public override void SetAccountCurrency()
{
//Before setting any cash or adding a Security call SetAccountCurrency
SetAccountCurrency("EUR", 200000);
}
/// <summary>
/// This is used by the regression test system to indicate if the open source Lean repository has the required data to run this algorithm.
/// </summary>
public bool CanRunLocally { get; } = true;
/// <summary>
/// This is used by the regression test system to indicate which languages this algorithm is written in.
/// </summary>
public List<Language> Languages { get; } = new() { Language.CSharp, Language.Python };
/// <summary>
/// Data Points count of all timeslices of algorithm
/// </summary>
public long DataPoints => 4319;
/// <summary>
/// Data Points count of the algorithm history
/// </summary>
public int AlgorithmHistoryDataPoints => 15;
/// <summary>
/// Final status of the algorithm
/// </summary>
public AlgorithmStatus AlgorithmStatus => AlgorithmStatus.Completed;
/// <summary>
/// This is used by the regression test system to indicate what the expected statistics are from running the algorithm
/// </summary>
public Dictionary<string, string> ExpectedStatistics => new Dictionary<string, string>
{
{"Total Orders", "1"},
{"Average Win", "0%"},
{"Average Loss", "0%"},
{"Compounding Annual Return", "0%"},
{"Drawdown", "0%"},
{"Expectancy", "0"},
{"Start Equity", "200000.00"},
{"End Equity", "184791.19"},
{"Net Profit", "0%"},
{"Sharpe Ratio", "0"},
{"Sortino Ratio", "0"},
{"Probabilistic Sharpe Ratio", "0%"},
{"Loss Rate", "0%"},
{"Win Rate", "0%"},
{"Profit-Loss Ratio", "0"},
{"Alpha", "0"},
{"Beta", "0"},
{"Annual Standard Deviation", "0"},
{"Annual Variance", "0"},
{"Information Ratio", "0"},
{"Tracking Error", "0"},
{"Treynor Ratio", "0"},
{"Total Fees", "€596.71"},
{"Estimated Strategy Capacity", "€85000.00"},
{"Lowest Capacity Asset", "BTCEUR 2XR"},
{"Portfolio Turnover", "107.64%"},
{"Drawdown Recovery", "0"},
{"OrderListHash", "3d450fd418a0e845b3eaaac17fcd13fc"}
};
}
}
+125
View File
@@ -0,0 +1,125 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System.Collections.Generic;
using QuantConnect.Data;
using QuantConnect.Interfaces;
namespace QuantConnect.Algorithm.CSharp
{
/// <summary>
/// Basic template algorithm simply initializes the date range and cash. This is a skeleton
/// framework you can use for designing an algorithm.
/// </summary>
/// <meta name="tag" content="using data" />
/// <meta name="tag" content="using quantconnect" />
/// <meta name="tag" content="trading and orders" />
public class BasicTemplateAlgorithm : QCAlgorithm, IRegressionAlgorithmDefinition
{
private Symbol _spy = QuantConnect.Symbol.Create("SPY", SecurityType.Equity, Market.USA);
/// <summary>
/// Initialise the data and resolution required, as well as the cash and start-end dates for your algorithm. All algorithms must initialized.
/// </summary>
public override void Initialize()
{
SetStartDate(2013, 10, 07); //Set Start Date
SetEndDate(2013, 10, 11); //Set End Date
SetCash(100000); //Set Strategy Cash
// Find more symbols here: http://quantconnect.com/data
// Forex, CFD, Equities Resolutions: Tick, Second, Minute, Hour, Daily.
// Futures Resolution: Tick, Second, Minute
// Options Resolution: Minute Only.
AddEquity("SPY", Resolution.Minute);
// There are other assets with similar methods. See "Selecting Options" etc for more details.
// AddFuture, AddForex, AddCfd, AddOption
}
/// <summary>
/// OnData event is the primary entry point for your algorithm. Each new data point will be pumped in here.
/// </summary>
/// <param name="data">Slice object keyed by symbol containing the stock data</param>
public override void OnData(Slice slice)
{
if (!Portfolio.Invested)
{
SetHoldings(_spy, 1);
Debug("Purchased Stock");
}
}
/// <summary>
/// This is used by the regression test system to indicate if the open source Lean repository has the required data to run this algorithm.
/// </summary>
public bool CanRunLocally { get; } = true;
/// <summary>
/// This is used by the regression test system to indicate which languages this algorithm is written in.
/// </summary>
public List<Language> Languages { get; } = new() { Language.CSharp, Language.Python };
/// <summary>
/// Data Points count of all timeslices of algorithm
/// </summary>
public long DataPoints => 3943;
/// <summary>
/// Data Points count of the algorithm history
/// </summary>
public int AlgorithmHistoryDataPoints => 0;
/// <summary>
/// Final status of the algorithm
/// </summary>
public AlgorithmStatus AlgorithmStatus => AlgorithmStatus.Completed;
/// <summary>
/// This is used by the regression test system to indicate what the expected statistics are from running the algorithm
/// </summary>
public Dictionary<string, string> ExpectedStatistics => new Dictionary<string, string>
{
{"Total Orders", "1"},
{"Average Win", "0%"},
{"Average Loss", "0%"},
{"Compounding Annual Return", "271.453%"},
{"Drawdown", "2.200%"},
{"Expectancy", "0"},
{"Start Equity", "100000"},
{"End Equity", "101691.92"},
{"Net Profit", "1.692%"},
{"Sharpe Ratio", "8.854"},
{"Sortino Ratio", "0"},
{"Probabilistic Sharpe Ratio", "67.459%"},
{"Loss Rate", "0%"},
{"Win Rate", "0%"},
{"Profit-Loss Ratio", "0"},
{"Alpha", "-0.005"},
{"Beta", "0.996"},
{"Annual Standard Deviation", "0.222"},
{"Annual Variance", "0.049"},
{"Information Ratio", "-14.565"},
{"Tracking Error", "0.001"},
{"Treynor Ratio", "1.97"},
{"Total Fees", "$3.44"},
{"Estimated Strategy Capacity", "$56000000.00"},
{"Lowest Capacity Asset", "SPY R735QTJ8XC9X"},
{"Portfolio Turnover", "19.93%"},
{"Drawdown Recovery", "3"},
{"OrderListHash", "3da9fa60bf95b9ed148b95e02e0cfc9e"}
};
}
}
@@ -0,0 +1,119 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using QuantConnect.Data;
using QuantConnect.Interfaces;
using QuantConnect.Brokerages;
using System.Collections.Generic;
namespace QuantConnect.Algorithm.CSharp
{
/// <summary>
/// Basic template algorithm for the Axos brokerage
/// </summary>
/// <meta name="tag" content="using data" />
/// <meta name="tag" content="using quantconnect" />
/// <meta name="tag" content="trading and orders" />
public class BasicTemplateAxosAlgorithm : QCAlgorithm, IRegressionAlgorithmDefinition
{
/// <summary>
/// Initialise the data and resolution required, as well as the cash and start-end dates for your algorithm. All algorithms must initialized.
/// </summary>
public override void Initialize()
{
SetStartDate(2013, 10, 07);
SetEndDate(2013, 10, 11);
SetCash(100000);
SetBrokerageModel(BrokerageName.Axos);
AddEquity("SPY", Resolution.Minute);
}
/// <summary>
/// OnData event is the primary entry point for your algorithm. Each new data point will be pumped in here.
/// </summary>
/// <param name="slice">Slice object keyed by symbol containing the stock data</param>
public override void OnData(Slice slice)
{
if (!Portfolio.Invested)
{
// will set 25% of our buying power with a market order
SetHoldings("SPY", 0.25m);
Debug("Purchased SPY!");
}
}
/// <summary>
/// This is used by the regression test system to indicate if the open source Lean repository has the required data to run this algorithm.
/// </summary>
public bool CanRunLocally { get; } = true;
/// <summary>
/// This is used by the regression test system to indicate which languages this algorithm is written in.
/// </summary>
public List<Language> Languages { get; } = new() { Language.CSharp, Language.Python };
/// <summary>
/// Data Points count of all timeslices of algorithm
/// </summary>
public long DataPoints => 3901;
/// <summary>
/// Data Points count of the algorithm history
/// </summary>
public int AlgorithmHistoryDataPoints => 0;
/// <summary>
/// Final status of the algorithm
/// </summary>
public AlgorithmStatus AlgorithmStatus => AlgorithmStatus.Completed;
/// <summary>
/// This is used by the regression test system to indicate what the expected statistics are from running the algorithm
/// </summary>
public Dictionary<string, string> ExpectedStatistics => new Dictionary<string, string>
{
{"Total Orders", "1"},
{"Average Win", "0%"},
{"Average Loss", "0%"},
{"Compounding Annual Return", "39.143%"},
{"Drawdown", "0.500%"},
{"Expectancy", "0"},
{"Start Equity", "100000"},
{"End Equity", "100423.24"},
{"Net Profit", "0.423%"},
{"Sharpe Ratio", "5.498"},
{"Sortino Ratio", "0"},
{"Probabilistic Sharpe Ratio", "66.898%"},
{"Loss Rate", "0%"},
{"Win Rate", "0%"},
{"Profit-Loss Ratio", "0"},
{"Alpha", "0"},
{"Beta", "0"},
{"Annual Standard Deviation", "0.055"},
{"Annual Variance", "0.003"},
{"Information Ratio", "5.634"},
{"Tracking Error", "0.055"},
{"Treynor Ratio", "0"},
{"Total Fees", "$0.60"},
{"Estimated Strategy Capacity", "$150000000.00"},
{"Lowest Capacity Asset", "SPY R735QTJ8XC9X"},
{"Portfolio Turnover", "4.98%"},
{"Drawdown Recovery", "3"},
{"OrderListHash", "8774049eb5141a2b6956d9432426f837"}
};
}
}
@@ -0,0 +1,72 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System.Linq;
using QuantConnect.Data;
using QuantConnect.Orders;
namespace QuantConnect.Algorithm.CSharp
{
/// <summary>
/// Algorithm demonstrating CFD asset types and requesting history.
/// </summary>
/// <meta name="tag" content="using data" />
/// <meta name="tag" content="history" />
/// <meta name="tag" content="cfd" />
public class BasicTemplateCfdAlgorithm : QCAlgorithm
{
private Symbol _symbol;
/// <summary>
/// Initialise the data and resolution required, as well as the cash and start-end dates for your algorithm. All algorithms must initialized.
/// </summary>
public override void Initialize()
{
SetAccountCurrency("EUR");
SetStartDate(2019, 2, 20);
SetEndDate(2019, 2, 21);
SetCash("EUR", 100000);
_symbol = AddCfd("DE30EUR").Symbol;
// Historical Data
var history = History(_symbol, 60, Resolution.Daily);
Log($"Received {history.Count()} bars from CFD historical data call.");
}
/// <summary>
/// OnData event is the primary entry point for your algorithm. Each new data point will be pumped in here.
/// </summary>
/// <param name="data">Slice object keyed by symbol containing the stock data</param>
public override void OnData(Slice slice)
{
// Access Data
if (slice.QuoteBars.ContainsKey(_symbol))
{
var quoteBar = slice.QuoteBars[_symbol];
Log($"{quoteBar.EndTime} :: {quoteBar.Close}");
}
if (!Portfolio.Invested)
SetHoldings(_symbol, 1);
}
public override void OnOrderEvent(OrderEvent orderEvent)
{
Debug($"{Time} {orderEvent.ToString()}");
}
}
}
@@ -0,0 +1,172 @@
/*
* 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 QuantConnect.Orders;
using QuantConnect.Interfaces;
using System.Collections.Generic;
using QuantConnect.Data.UniverseSelection;
using QuantConnect.Indicators;
using QuantConnect.Securities;
using QuantConnect.Securities.Future;
using Futures = QuantConnect.Securities.Futures;
namespace QuantConnect.Algorithm.CSharp
{
/// <summary>
/// Basic Continuous Futures Template Algorithm
/// </summary>
public class BasicTemplateContinuousFutureAlgorithm : QCAlgorithm, IRegressionAlgorithmDefinition
{
private Future _continuousContract;
private Security _currentContract;
private SimpleMovingAverage _fast;
private SimpleMovingAverage _slow;
// Minimum SMA gap required before acting on a cross; see the workaround note in OnData.
private const decimal CrossThreshold = 0.001m;
/// <summary>
/// Initialise the data and resolution required, as well as the cash and start-end dates for your algorithm. All algorithms must initialized.
/// </summary>
public override void Initialize()
{
SetStartDate(2013, 7, 1);
SetEndDate(2014, 1, 1);
_continuousContract = AddFuture(Futures.Indices.SP500EMini,
dataNormalizationMode: DataNormalizationMode.BackwardsRatio,
dataMappingMode: DataMappingMode.LastTradingDay,
contractDepthOffset: 0
);
_fast = SMA(_continuousContract.Symbol, 4, Resolution.Daily);
_slow = SMA(_continuousContract.Symbol, 10, Resolution.Daily);
}
/// <summary>
/// OnData event is the primary entry point for your algorithm. Each new data point will be pumped in here.
/// </summary>
/// <param name="data">Slice object keyed by symbol containing the stock data</param>
public override void OnData(Slice slice)
{
foreach (var changedEvent in slice.SymbolChangedEvents.Values)
{
Debug($"{Time} - SymbolChanged event: {changedEvent}");
if (Time.TimeOfDay != TimeSpan.Zero)
{
throw new RegressionTestException($"{Time} unexpected symbol changed event {changedEvent}!");
}
}
// Workaround so the C# and Python versions take the exact same trades on the limited
// sample data in the repository (decimal vs double rounding can disagree at a cross).
if (!Portfolio.Invested)
{
if(_fast.Current.Value - _slow.Current.Value > CrossThreshold)
{
_currentContract = Securities[_continuousContract.Mapped];
Buy(_currentContract.Symbol, 1);
}
}
else if(_slow.Current.Value - _fast.Current.Value > CrossThreshold)
{
Liquidate();
}
// We check exchange hours because the contract mapping can call OnData outside of regular hours.
if (_currentContract != null && _currentContract.Symbol != _continuousContract.Mapped && _continuousContract.Exchange.ExchangeOpen)
{
Log($"{Time} - rolling position from {_currentContract.Symbol} to {_continuousContract.Mapped}");
var currentPositionSize = _currentContract.Holdings.Quantity;
Liquidate(_currentContract.Symbol);
Buy(_continuousContract.Mapped, currentPositionSize);
_currentContract = Securities[_continuousContract.Mapped];
}
}
public override void OnOrderEvent(OrderEvent orderEvent)
{
Debug($"{orderEvent}");
}
public override void OnSecuritiesChanged(SecurityChanges changes)
{
Debug($"{Time}-{changes}");
}
/// <summary>
/// This is used by the regression test system to indicate if the open source Lean repository has the required data to run this algorithm.
/// </summary>
public bool CanRunLocally { get; } = true;
/// <summary>
/// This is used by the regression test system to indicate which languages this algorithm is written in.
/// </summary>
public List<Language> Languages { get; } = new() { Language.CSharp, Language.Python };
/// <summary>
/// Data Points count of all timeslices of algorithm
/// </summary>
public long DataPoints => 162575;
/// <summary>
/// Data Points count of the algorithm history
/// </summary>
public int AlgorithmHistoryDataPoints => 0;
/// <summary>
/// Final status of the algorithm
/// </summary>
public AlgorithmStatus AlgorithmStatus => AlgorithmStatus.Completed;
/// <summary>
/// This is used by the regression test system to indicate what the expected statistics are from running the algorithm
/// </summary>
public Dictionary<string, string> ExpectedStatistics => new Dictionary<string, string>
{
{"Total Orders", "9"},
{"Average Win", "2.85%"},
{"Average Loss", "-0.43%"},
{"Compounding Annual Return", "11.019%"},
{"Drawdown", "0.900%"},
{"Expectancy", "2.818"},
{"Start Equity", "100000"},
{"End Equity", "105403.5"},
{"Net Profit", "5.404%"},
{"Sharpe Ratio", "1.531"},
{"Sortino Ratio", "2.106"},
{"Probabilistic Sharpe Ratio", "74.321%"},
{"Loss Rate", "50%"},
{"Win Rate", "50%"},
{"Profit-Loss Ratio", "6.64"},
{"Alpha", "0.067"},
{"Beta", "0.009"},
{"Annual Standard Deviation", "0.045"},
{"Annual Variance", "0.002"},
{"Information Ratio", "-1.606"},
{"Tracking Error", "0.093"},
{"Treynor Ratio", "7.237"},
{"Total Fees", "$19.35"},
{"Estimated Strategy Capacity", "$1000000000.00"},
{"Lowest Capacity Asset", "ES VMKLFZIH2MTD"},
{"Portfolio Turnover", "4.18%"},
{"Drawdown Recovery", "19"},
{"OrderListHash", "eb3bed9886f79a56c631225a6445adb2"}
};
}
}
@@ -0,0 +1,183 @@
/*
* 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 QuantConnect.Orders;
using QuantConnect.Interfaces;
using System.Collections.Generic;
using System.Linq;
using QuantConnect.Data.UniverseSelection;
using QuantConnect.Indicators;
using QuantConnect.Securities;
using QuantConnect.Securities.Future;
using Futures = QuantConnect.Securities.Futures;
namespace QuantConnect.Algorithm.CSharp
{
/// <summary>
/// Basic Continuous Futures Template Algorithm with extended market hours
/// </summary>
public class BasicTemplateContinuousFutureWithExtendedMarketAlgorithm : QCAlgorithm, IRegressionAlgorithmDefinition
{
private Future _continuousContract;
private Security _currentContract;
private SimpleMovingAverage _fast;
private SimpleMovingAverage _slow;
// Minimum SMA gap required before acting on a cross; see the workaround note in OnData.
private const decimal CrossThreshold = 0.001m;
/// <summary>
/// Initialise the data and resolution required, as well as the cash and start-end dates for your algorithm. All algorithms must initialized.
/// </summary>
public override void Initialize()
{
SetStartDate(2013, 7, 1);
SetEndDate(2014, 1, 1);
_continuousContract = AddFuture(Futures.Indices.SP500EMini,
dataNormalizationMode: DataNormalizationMode.BackwardsRatio,
dataMappingMode: DataMappingMode.LastTradingDay,
contractDepthOffset: 0,
extendedMarketHours: true
);
_fast = SMA(_continuousContract.Symbol, 4, Resolution.Daily);
_slow = SMA(_continuousContract.Symbol, 10, Resolution.Daily);
}
/// <summary>
/// OnData event is the primary entry point for your algorithm. Each new data point will be pumped in here.
/// </summary>
/// <param name="slice">Slice object keyed by symbol containing the stock data</param>
public override void OnData(Slice slice)
{
foreach (var changedEvent in slice.SymbolChangedEvents.Values)
{
Debug($"{Time} - SymbolChanged event: {changedEvent}");
if (Time.TimeOfDay != TimeSpan.Zero)
{
throw new RegressionTestException($"{Time} unexpected symbol changed event {changedEvent}!");
}
}
if (!IsMarketOpen(_continuousContract.Symbol))
{
return;
}
// This is just to limit the amount of orders done in this regression test, since data in the repo is limited.
// Also limit it to 3 orders so that the continuous contract rolls happens with an open position.
if (Time < new DateTime(2013, 11, 12) && Transactions.OrdersCount < 3)
{
// Workaround so the C# and Python versions take the exact same trades on the limited
// sample data in the repository (decimal vs double rounding can disagree at a cross).
if (!Portfolio.Invested)
{
if (_fast.Current.Value - _slow.Current.Value > CrossThreshold)
{
_currentContract = Securities[_continuousContract.Mapped];
Buy(_currentContract.Symbol, 1);
}
}
else if (_slow.Current.Value - _fast.Current.Value > CrossThreshold)
{
Liquidate();
}
}
if (_currentContract != null && _currentContract.Symbol != _continuousContract.Mapped)
{
Log($"{Time} - rolling position from {_currentContract.Symbol} to {_continuousContract.Mapped}");
var currentPositionSize = _currentContract.Holdings.Quantity;
Liquidate(_currentContract.Symbol);
Buy(_continuousContract.Mapped, currentPositionSize);
_currentContract = Securities[_continuousContract.Mapped];
}
}
public override void OnOrderEvent(OrderEvent orderEvent)
{
Debug($"{orderEvent}");
}
public override void OnSecuritiesChanged(SecurityChanges changes)
{
Debug($"{Time}-{changes}");
}
/// <summary>
/// This is used by the regression test system to indicate if the open source Lean repository has the required data to run this algorithm.
/// </summary>
public bool CanRunLocally { get; } = true;
/// <summary>
/// This is used by the regression test system to indicate which languages this algorithm is written in.
/// </summary>
public List<Language> Languages { get; } = new() { Language.CSharp, Language.Python };
/// <summary>
/// Data Points count of all timeslices of algorithm
/// </summary>
public long DataPoints => 504530;
/// <summary>
/// Data Points count of the algorithm history
/// </summary>
public int AlgorithmHistoryDataPoints => 0;
/// <summary>
/// Final status of the algorithm
/// </summary>
public AlgorithmStatus AlgorithmStatus => AlgorithmStatus.Completed;
/// <summary>
/// This is used by the regression test system to indicate what the expected statistics are from running the algorithm
/// </summary>
public Dictionary<string, string> ExpectedStatistics => new Dictionary<string, string>
{
{"Total Orders", "3"},
{"Average Win", "6.15%"},
{"Average Loss", "0%"},
{"Compounding Annual Return", "13.813%"},
{"Drawdown", "1.400%"},
{"Expectancy", "0"},
{"Start Equity", "100000"},
{"End Equity", "106741.4"},
{"Net Profit", "6.741%"},
{"Sharpe Ratio", "2.003"},
{"Sortino Ratio", "2.845"},
{"Probabilistic Sharpe Ratio", "87.787%"},
{"Loss Rate", "0%"},
{"Win Rate", "100%"},
{"Profit-Loss Ratio", "0"},
{"Alpha", "0.069"},
{"Beta", "0.086"},
{"Annual Standard Deviation", "0.044"},
{"Annual Variance", "0.002"},
{"Information Ratio", "-1.506"},
{"Tracking Error", "0.086"},
{"Treynor Ratio", "1.023"},
{"Total Fees", "$6.45"},
{"Estimated Strategy Capacity", "$3700000000.00"},
{"Lowest Capacity Asset", "ES VMKLFZIH2MTD"},
{"Portfolio Turnover", "1.37%"},
{"Drawdown Recovery", "18"},
{"OrderListHash", "764ab9f6ea662a60e41daedb9613b246"}
};
}
}
@@ -0,0 +1,247 @@
/*
* 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.Brokerages;
using QuantConnect.Indicators;
using QuantConnect.Orders;
using QuantConnect.Interfaces;
namespace QuantConnect.Algorithm.CSharp
{
/// <summary>
/// The demonstration algorithm shows some of the most common order methods when working with Crypto assets.
/// </summary>
/// <meta name="tag" content="using data" />
/// <meta name="tag" content="using quantconnect" />
/// <meta name="tag" content="trading and orders" />
public class BasicTemplateCryptoAlgorithm : QCAlgorithm, IRegressionAlgorithmDefinition
{
private ExponentialMovingAverage _fast;
private ExponentialMovingAverage _slow;
/// <summary>
/// Initialise the data and resolution required, as well as the cash and start-end dates for your algorithm. All algorithms must initialized.
/// </summary>
public override void Initialize()
{
SetStartDate(2018, 4, 4); // Set Start Date
SetEndDate(2018, 4, 4); // Set End Date
// Although typically real brokerages as GDAX only support a single account currency,
// here we add both USD and EUR to demonstrate how to handle non-USD account currencies.
// Set Strategy Cash (USD)
SetCash(10000);
// Set Strategy Cash (EUR)
// EUR/USD conversion rate will be updated dynamically
SetCash("EUR", 10000);
// Add some coins as initial holdings
// When connected to a real brokerage, the amount specified in SetCash
// will be replaced with the amount in your actual account.
SetCash("BTC", 1m);
SetCash("ETH", 5m);
SetBrokerageModel(BrokerageName.GDAX, AccountType.Cash);
// You can uncomment the following line when live trading with GDAX,
// to ensure limit orders will only be posted to the order book and never executed as a taker (incurring fees).
// Please note this statement has no effect in backtesting or paper trading.
// DefaultOrderProperties = new GDAXOrderProperties { PostOnly = true };
// Find more symbols here: http://quantconnect.com/data
AddCrypto("BTCUSD");
AddCrypto("ETHUSD");
AddCrypto("BTCEUR");
var symbol = AddCrypto("LTCUSD").Symbol;
// create two moving averages
_fast = EMA(symbol, 30, Resolution.Minute);
_slow = EMA(symbol, 60, Resolution.Minute);
}
/// <summary>
/// OnData event is the primary entry point for your algorithm. Each new data point will be pumped in here.
/// </summary>
/// <param name="slice">Slice object keyed by symbol containing the stock data</param>
public override void OnData(Slice slice)
{
if (Portfolio.CashBook["EUR"].ConversionRate == 0
|| Portfolio.CashBook["BTC"].ConversionRate == 0
|| Portfolio.CashBook["ETH"].ConversionRate == 0
|| Portfolio.CashBook["LTC"].ConversionRate == 0)
{
Log($"EUR conversion rate: {Portfolio.CashBook["EUR"].ConversionRate}");
Log($"BTC conversion rate: {Portfolio.CashBook["BTC"].ConversionRate}");
Log($"LTC conversion rate: {Portfolio.CashBook["LTC"].ConversionRate}");
Log($"ETH conversion rate: {Portfolio.CashBook["ETH"].ConversionRate}");
throw new RegressionTestException("Conversion rate is 0");
}
if (Time.Hour == 1 && Time.Minute == 0)
{
// Sell all ETH holdings with a limit order at 1% above the current price
var limitPrice = Math.Round(Securities["ETHUSD"].Price * 1.01m, 2);
var quantity = Portfolio.CashBook["ETH"].Amount;
LimitOrder("ETHUSD", -quantity, limitPrice);
}
else if (Time.Hour == 2 && Time.Minute == 0)
{
// Submit a buy limit order for BTC at 5% below the current price
var usdTotal = Portfolio.CashBook["USD"].Amount;
var limitPrice = Math.Round(Securities["BTCUSD"].Price * 0.95m, 2);
// use only half of our total USD
var quantity = usdTotal * 0.5m / limitPrice;
LimitOrder("BTCUSD", quantity, limitPrice);
}
else if (Time.Hour == 2 && Time.Minute == 1)
{
// Get current USD available, subtracting amount reserved for buy open orders
var usdTotal = Portfolio.CashBook["USD"].Amount;
var usdReserved = Transactions.GetOpenOrders(x => x.Direction == OrderDirection.Buy && x.Type == OrderType.Limit)
.Where(x => x.Symbol == "BTCUSD" || x.Symbol == "ETHUSD")
.Sum(x => x.Quantity * ((LimitOrder) x).LimitPrice);
var usdAvailable = usdTotal - usdReserved;
// Submit a marketable buy limit order for ETH at 1% above the current price
var limitPrice = Math.Round(Securities["ETHUSD"].Price * 1.01m, 2);
// use all of our available USD
var quantity = usdAvailable / limitPrice;
// this order will be rejected for insufficient funds
LimitOrder("ETHUSD", quantity, limitPrice);
// use only half of our available USD
quantity = usdAvailable * 0.5m / limitPrice;
LimitOrder("ETHUSD", quantity, limitPrice);
}
else if (Time.Hour == 11 && Time.Minute == 0)
{
// Liquidate our BTC holdings (including the initial holding)
SetHoldings("BTCUSD", 0m);
}
else if (Time.Hour == 12 && Time.Minute == 0)
{
// Submit a market buy order for 1 BTC using EUR
Buy("BTCEUR", 1m);
// Submit a sell limit order at 10% above market price
var limitPrice = Math.Round(Securities["BTCEUR"].Price * 1.1m, 2);
LimitOrder("BTCEUR", -1, limitPrice);
}
else if (Time.Hour == 13 && Time.Minute == 0)
{
// Cancel the limit order if not filled
Transactions.CancelOpenOrders("BTCEUR");
}
else if (Time.Hour > 13)
{
// To include any initial holdings, we read the LTC amount from the cashbook
// instead of using Portfolio["LTCUSD"].Quantity
if (_fast > _slow)
{
if (Portfolio.CashBook["LTC"].Amount == 0)
{
Buy("LTCUSD", 10);
}
}
else
{
if (Portfolio.CashBook["LTC"].Amount > 0)
{
Liquidate("LTCUSD");
}
}
}
}
public override void OnOrderEvent(OrderEvent orderEvent)
{
Debug(Time + " " + orderEvent);
}
public override void OnEndOfAlgorithm()
{
Log($"{Time} - TotalPortfolioValue: {Portfolio.TotalPortfolioValue}");
Log($"{Time} - CashBook: {Portfolio.CashBook}");
}
/// <summary>
/// This is used by the regression test system to indicate if the open source Lean repository has the required data to run this algorithm.
/// </summary>
public bool CanRunLocally { get; } = true;
/// <summary>
/// This is used by the regression test system to indicate which languages this algorithm is written in.
/// </summary>
public List<Language> Languages { get; } = new() { Language.CSharp, Language.Python };
/// <summary>
/// Data Points count of all timeslices of algorithm
/// </summary>
public long DataPoints => 12965;
/// <summary>
/// Data Points count of the algorithm history
/// </summary>
public int AlgorithmHistoryDataPoints => 35;
/// <summary>
/// Final status of the algorithm
/// </summary>
public AlgorithmStatus AlgorithmStatus => AlgorithmStatus.Completed;
/// <summary>
/// This is used by the regression test system to indicate what the expected statistics are from running the algorithm
/// </summary>
public Dictionary<string, string> ExpectedStatistics => new Dictionary<string, string>
{
{"Total Orders", "12"},
{"Average Win", "0%"},
{"Average Loss", "0%"},
{"Compounding Annual Return", "0%"},
{"Drawdown", "0%"},
{"Expectancy", "0"},
{"Start Equity", "31592.84"},
{"End Equity", "30866.71"},
{"Net Profit", "0%"},
{"Sharpe Ratio", "0"},
{"Sortino Ratio", "0"},
{"Probabilistic Sharpe Ratio", "0%"},
{"Loss Rate", "0%"},
{"Win Rate", "0%"},
{"Profit-Loss Ratio", "0"},
{"Alpha", "0"},
{"Beta", "0"},
{"Annual Standard Deviation", "0"},
{"Annual Variance", "0"},
{"Information Ratio", "0"},
{"Tracking Error", "0"},
{"Treynor Ratio", "0"},
{"Total Fees", "$85.34"},
{"Estimated Strategy Capacity", "$0"},
{"Lowest Capacity Asset", "BTCEUR 2XR"},
{"Portfolio Turnover", "118.08%"},
{"Drawdown Recovery", "0"},
{"OrderListHash", "26b9a07ace86b6a0e0eb2ff8c168cee0"}
};
}
}
@@ -0,0 +1,67 @@
/*
* 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.Algorithm.Framework.Alphas;
using QuantConnect.Algorithm.Framework.Execution;
using QuantConnect.Algorithm.Framework.Portfolio;
using QuantConnect.Algorithm.Framework.Risk;
using QuantConnect.Algorithm.Framework.Selection;
using QuantConnect.Orders;
namespace QuantConnect.Algorithm.CSharp
{
/// <summary>
/// Basic template framework algorithm uses framework components to define the algorithm.
/// </summary>
/// <meta name="tag" content="using data" />
/// <meta name="tag" content="using quantconnect" />
/// <meta name="tag" content="trading and orders" />
public class BasicTemplateFrameworkCryptoAlgorithm : QCAlgorithm
{
/// <summary>
/// Initialise the data and resolution required, as well as the cash and start-end dates for your algorithm. All algorithms must initialized.
/// </summary>
public override void Initialize()
{
// Set requested data resolution
UniverseSettings.Resolution = Resolution.Minute;
SetStartDate(2016, 10, 7); //Set Start Date
SetEndDate(2016, 10, 7); //Set End Date
SetCash(100000); //Set Strategy Cash
// Find more symbols here: http://quantconnect.com/data
// Forex, CFD, Equities Resolutions: Tick, Second, Minute, Hour, Daily.
// Futures Resolution: Tick, Second, Minute
// Options Resolution: Minute Only.
// set algorithm framework models
SetUniverseSelection(new ManualUniverseSelectionModel(QuantConnect.Symbol.Create("BTCUSD", SecurityType.Crypto, Market.GDAX)));
SetAlpha(new ConstantAlphaModel(InsightType.Price, InsightDirection.Up, TimeSpan.FromMinutes(20), 0.025, null));
SetPortfolioConstruction(new EqualWeightingPortfolioConstructionModel());
SetExecution(new ImmediateExecutionModel());
SetRiskManagement(new NullRiskManagementModel());
}
public override void OnOrderEvent(OrderEvent orderEvent)
{
if (orderEvent.Status.IsFill())
{
Debug($"Purchased Stock: {orderEvent.Symbol}");
}
}
}
}
@@ -0,0 +1,280 @@
/*
* 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 QuantConnect.Orders;
using QuantConnect.Brokerages;
using QuantConnect.Indicators;
using QuantConnect.Interfaces;
using QuantConnect.Securities;
using QuantConnect.Data.Market;
using System.Collections.Generic;
using QuantConnect.Securities.CryptoFuture;
namespace QuantConnect.Algorithm.CSharp
{
/// <summary>
/// Minute resolution regression algorithm trading Coin and USDT binance futures long and short asserting the behavior
/// </summary>
public class BasicTemplateCryptoFutureAlgorithm : QCAlgorithm, IRegressionAlgorithmDefinition
{
private Dictionary<Symbol, int> _interestPerSymbol = new();
private CryptoFuture _btcUsd;
private CryptoFuture _adaUsdt;
private ExponentialMovingAverage _fast;
private ExponentialMovingAverage _slow;
/// <summary>
/// Initialise the data and resolution required, as well as the cash and start-end dates for your algorithm. All algorithms must initialized.
/// </summary>
public override void Initialize()
{
SetStartDate(2022, 12, 13); // Set Start Date
SetEndDate(2022, 12, 13); // Set End Date
SetTimeZone(TimeZones.Utc);
try
{
SetBrokerageModel(BrokerageName.BinanceFutures, AccountType.Cash);
}
catch (InvalidOperationException)
{
// expected, we don't allow cash account type
}
SetBrokerageModel(BrokerageName.BinanceFutures, AccountType.Margin);
_btcUsd = AddCryptoFuture("BTCUSD");
_adaUsdt = AddCryptoFuture("ADAUSDT");
_fast = EMA(_btcUsd.Symbol, 30, Resolution.Minute);
_slow = EMA(_btcUsd.Symbol, 60, Resolution.Minute);
_interestPerSymbol[_btcUsd.Symbol] = 0;
_interestPerSymbol[_adaUsdt.Symbol] = 0;
// Default USD cash, set 1M but it wont be used
SetCash(1000000);
// the amount of BTC we need to hold to trade 'BTCUSD'
_btcUsd.BaseCurrency.SetAmount(0.005m);
// the amount of USDT we need to hold to trade 'ADAUSDT'
_adaUsdt.QuoteCurrency.SetAmount(200);
}
/// <summary>
/// OnData event is the primary entry point for your algorithm. Each new data point will be pumped in here.
/// </summary>
/// <param name="data">Slice object keyed by symbol containing the stock data</param>
public override void OnData(Slice slice)
{
var interestRates = slice.Get<MarginInterestRate>();
foreach (var interestRate in interestRates)
{
_interestPerSymbol[interestRate.Key]++;
var cachedInterestRate = Securities[interestRate.Key].Cache.GetData<MarginInterestRate>();
if (cachedInterestRate != interestRate.Value)
{
throw new RegressionTestException($"Unexpected cached margin interest rate for {interestRate.Key}!");
}
}
if (_fast > _slow)
{
if (!Portfolio.Invested && Transactions.OrdersCount == 0)
{
var ticket = Buy(_btcUsd.Symbol, 50);
if (ticket.Status != OrderStatus.Invalid)
{
throw new RegressionTestException($"Unexpected valid order {ticket}, should fail due to margin not sufficient");
}
Buy(_btcUsd.Symbol, 1);
var marginUsed = Portfolio.TotalMarginUsed;
var btcUsdHoldings = _btcUsd.Holdings;
// Coin futures value is 100 USD
var holdingsValueBtcUsd = 100;
if (Math.Abs(btcUsdHoldings.TotalSaleVolume - holdingsValueBtcUsd) > 1)
{
throw new RegressionTestException($"Unexpected TotalSaleVolume {btcUsdHoldings.TotalSaleVolume}");
}
if (Math.Abs(btcUsdHoldings.AbsoluteHoldingsCost - holdingsValueBtcUsd) > 1)
{
throw new RegressionTestException($"Unexpected holdings cost {btcUsdHoldings.HoldingsCost}");
}
if (_btcUsd.BuyingPowerModel.GetMaintenanceMargin(_btcUsd) != marginUsed)
{
throw new RegressionTestException($"Unexpected margin used {marginUsed}");
}
Buy(_adaUsdt.Symbol, 1000);
marginUsed = Portfolio.TotalMarginUsed - marginUsed;
var adaUsdtHoldings = _adaUsdt.Holdings;
// USDT/BUSD futures value is based on it's price
var holdingsValueUsdt = _adaUsdt.Price * _adaUsdt.SymbolProperties.ContractMultiplier * 1000;
if (Math.Abs(adaUsdtHoldings.TotalSaleVolume - holdingsValueUsdt) > 1)
{
throw new RegressionTestException($"Unexpected TotalSaleVolume {adaUsdtHoldings.TotalSaleVolume}");
}
if (Math.Abs(adaUsdtHoldings.AbsoluteHoldingsCost - holdingsValueUsdt) > 1)
{
throw new RegressionTestException($"Unexpected holdings cost {adaUsdtHoldings.HoldingsCost}");
}
if (_adaUsdt.BuyingPowerModel.GetMaintenanceMargin(_adaUsdt) != marginUsed)
{
throw new RegressionTestException($"Unexpected margin used {marginUsed}");
}
// position just opened should be just spread here
var profit = Portfolio.TotalUnrealizedProfit;
if ((5 - Math.Abs(profit)) < 0)
{
throw new RegressionTestException($"Unexpected TotalUnrealizedProfit {Portfolio.TotalUnrealizedProfit}");
}
if (Portfolio.TotalProfit != 0)
{
throw new RegressionTestException($"Unexpected TotalProfit {Portfolio.TotalProfit}");
}
}
}
else
{
// let's revert our position and double
if (Time.Hour > 10 && Transactions.OrdersCount == 3)
{
Sell(_btcUsd.Symbol, 3);
var btcUsdHoldings = _btcUsd.Holdings;
if (Math.Abs(btcUsdHoldings.AbsoluteHoldingsCost - 100 * 2) > 1)
{
throw new RegressionTestException($"Unexpected holdings cost {btcUsdHoldings.HoldingsCost}");
}
Sell(_adaUsdt.Symbol, 3000);
var adaUsdtHoldings = _adaUsdt.Holdings;
// USDT/BUSD futures value is based on it's price
var holdingsValueUsdt = _adaUsdt.Price * _adaUsdt.SymbolProperties.ContractMultiplier * 2000;
if (Math.Abs(adaUsdtHoldings.AbsoluteHoldingsCost - holdingsValueUsdt) > 1)
{
throw new RegressionTestException($"Unexpected holdings cost {adaUsdtHoldings.HoldingsCost}");
}
// position just opened should be just spread here
var profit = Portfolio.TotalUnrealizedProfit;
if ((5 - Math.Abs(profit)) < 0)
{
throw new RegressionTestException($"Unexpected TotalUnrealizedProfit {Portfolio.TotalUnrealizedProfit}");
}
// we barely did any difference on the previous trade
if ((5 - Math.Abs(Portfolio.TotalProfit)) < 0)
{
throw new RegressionTestException($"Unexpected TotalProfit {Portfolio.TotalProfit}");
}
}
}
}
public override void OnEndOfAlgorithm()
{
if (_interestPerSymbol[_adaUsdt.Symbol] != 1)
{
throw new RegressionTestException($"Unexpected interest rate count {_interestPerSymbol[_adaUsdt.Symbol]}");
}
if (_interestPerSymbol[_btcUsd.Symbol] != 3)
{
throw new RegressionTestException($"Unexpected interest rate count {_interestPerSymbol[_btcUsd.Symbol]}");
}
}
public override void OnOrderEvent(OrderEvent orderEvent)
{
Debug(Time + " " + orderEvent);
}
/// <summary>
/// This is used by the regression test system to indicate if the open source Lean repository has the required data to run this algorithm.
/// </summary>
public bool CanRunLocally { get; } = true;
/// <summary>
/// This is used by the regression test system to indicate which languages this algorithm is written in.
/// </summary>
public List<Language> Languages { get; } = new() { Language.CSharp, Language.Python };
/// <summary>
/// Data Points count of all timeslices of algorithm
/// </summary>
public long DataPoints => 7205;
/// <summary>
/// Data Points count of the algorithm history
/// </summary>
public int AlgorithmHistoryDataPoints => 0;
/// <summary>
/// Final status of the algorithm
/// </summary>
public AlgorithmStatus AlgorithmStatus => AlgorithmStatus.Completed;
/// <summary>
/// This is used by the regression test system to indicate what the expected statistics are from running the algorithm
/// </summary>
public Dictionary<string, string> ExpectedStatistics => new Dictionary<string, string>
{
{"Total Orders", "5"},
{"Average Win", "0%"},
{"Average Loss", "0%"},
{"Compounding Annual Return", "0%"},
{"Drawdown", "0%"},
{"Expectancy", "0"},
{"Start Equity", "1000200.00"},
{"End Equity", "1000278.02"},
{"Net Profit", "0%"},
{"Sharpe Ratio", "0"},
{"Sortino Ratio", "0"},
{"Probabilistic Sharpe Ratio", "0%"},
{"Loss Rate", "0%"},
{"Win Rate", "0%"},
{"Profit-Loss Ratio", "0"},
{"Alpha", "0"},
{"Beta", "0"},
{"Annual Standard Deviation", "0"},
{"Annual Variance", "0"},
{"Information Ratio", "0"},
{"Tracking Error", "0"},
{"Treynor Ratio", "0"},
{"Total Fees", "$0.65"},
{"Estimated Strategy Capacity", "$620000000.00"},
{"Lowest Capacity Asset", "ADAUSDT 18R"},
{"Portfolio Turnover", "0.16%"},
{"Drawdown Recovery", "0"},
{"OrderListHash", "dcc4f964b5549c753123848c32eaee41"}
};
}
}
@@ -0,0 +1,245 @@
/*
* 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 QuantConnect.Orders;
using QuantConnect.Indicators;
using QuantConnect.Interfaces;
using QuantConnect.Securities;
using QuantConnect.Brokerages;
using QuantConnect.Data.Market;
using System.Collections.Generic;
using QuantConnect.Securities.CryptoFuture;
namespace QuantConnect.Algorithm.CSharp
{
/// <summary>
/// Hourly regression algorithm trading ADAUSDT binance futures long and short asserting the behavior
/// </summary>
public class BasicTemplateCryptoFutureHourlyAlgorithm : QCAlgorithm, IRegressionAlgorithmDefinition
{
private Dictionary<Symbol, int> _interestPerSymbol = new();
private CryptoFuture _adaUsdt;
private ExponentialMovingAverage _fast;
private ExponentialMovingAverage _slow;
/// <summary>
/// Initialise the data and resolution required, as well as the cash and start-end dates for your algorithm. All algorithms must initialized.
/// </summary>
public override void Initialize()
{
SetStartDate(2022, 12, 13);
SetEndDate(2022, 12, 13);
SetTimeZone(TimeZones.Utc);
try
{
SetBrokerageModel(BrokerageName.BinanceCoinFutures, AccountType.Cash);
}
catch (InvalidOperationException)
{
// expected, we don't allow cash account type
}
SetBrokerageModel(BrokerageName.BinanceCoinFutures, AccountType.Margin);
_adaUsdt = AddCryptoFuture("ADAUSDT", Resolution.Hour);
_fast = EMA(_adaUsdt.Symbol, 3, Resolution.Hour);
_slow = EMA(_adaUsdt.Symbol, 6, Resolution.Hour);
_interestPerSymbol[_adaUsdt.Symbol] = 0;
// Default USD cash, set 1M but it wont be used
SetCash(1000000);
// the amount of USDT we need to hold to trade 'ADAUSDT'
_adaUsdt.QuoteCurrency.SetAmount(200);
}
/// <summary>
/// OnData event is the primary entry point for your algorithm. Each new data point will be pumped in here.
/// </summary>
/// <param name="data">Slice object keyed by symbol containing the stock data</param>
public override void OnData(Slice slice)
{
var interestRates = slice.Get<MarginInterestRate>();
foreach (var interestRate in interestRates)
{
_interestPerSymbol[interestRate.Key]++;
var cachedInterestRate = Securities[interestRate.Key].Cache.GetData<MarginInterestRate>();
if (cachedInterestRate != interestRate.Value)
{
throw new RegressionTestException($"Unexpected cached margin interest rate for {interestRate.Key}!");
}
}
if (_fast > _slow)
{
if (!Portfolio.Invested && Transactions.OrdersCount == 0)
{
var ticket = Buy(_adaUsdt.Symbol, 100000);
if (ticket.Status != OrderStatus.Invalid)
{
throw new RegressionTestException($"Unexpected valid order {ticket}, should fail due to margin not sufficient");
}
Buy(_adaUsdt.Symbol, 1000);
var marginUsed = Portfolio.TotalMarginUsed;
var adaUsdtHoldings = _adaUsdt.Holdings;
// USDT/BUSD futures value is based on it's price
var holdingsValueUsdt = _adaUsdt.Price * _adaUsdt.SymbolProperties.ContractMultiplier * 1000;
if (Math.Abs(adaUsdtHoldings.TotalSaleVolume - holdingsValueUsdt) > 1)
{
throw new RegressionTestException($"Unexpected TotalSaleVolume {adaUsdtHoldings.TotalSaleVolume}");
}
if (Math.Abs(adaUsdtHoldings.AbsoluteHoldingsCost - holdingsValueUsdt) > 1)
{
throw new RegressionTestException($"Unexpected holdings cost {adaUsdtHoldings.HoldingsCost}");
}
if (_adaUsdt.BuyingPowerModel.GetMaintenanceMargin(_adaUsdt) != marginUsed)
{
throw new RegressionTestException($"Unexpected margin used {marginUsed}");
}
// position just opened should be just spread here
var profit = Portfolio.TotalUnrealizedProfit;
if ((5 - Math.Abs(profit)) < 0)
{
throw new RegressionTestException($"Unexpected TotalUnrealizedProfit {Portfolio.TotalUnrealizedProfit}");
}
if (Portfolio.TotalProfit != 0)
{
throw new RegressionTestException($"Unexpected TotalProfit {Portfolio.TotalProfit}");
}
}
}
else
{
// let's revert our position and double
if (Time.Hour > 10 && Transactions.OrdersCount == 2)
{
Sell(_adaUsdt.Symbol, 3000);
var adaUsdtHoldings = _adaUsdt.Holdings;
// USDT/BUSD futures value is based on it's price
var holdingsValueUsdt = _adaUsdt.Price * _adaUsdt.SymbolProperties.ContractMultiplier * 2000;
if (Math.Abs(adaUsdtHoldings.AbsoluteHoldingsCost - holdingsValueUsdt) > 1)
{
throw new RegressionTestException($"Unexpected holdings cost {adaUsdtHoldings.HoldingsCost}");
}
// position just opened should be just spread here
var profit = Portfolio.TotalUnrealizedProfit;
if ((5 - Math.Abs(profit)) < 0)
{
throw new RegressionTestException($"Unexpected TotalUnrealizedProfit {Portfolio.TotalUnrealizedProfit}");
}
// we barely did any difference on the previous trade
if ((5 - Math.Abs(Portfolio.TotalProfit)) < 0)
{
throw new RegressionTestException($"Unexpected TotalProfit {Portfolio.TotalProfit}");
}
}
if (Time.Hour >= 22 && Transactions.OrdersCount == 3)
{
Liquidate();
}
}
}
public override void OnEndOfAlgorithm()
{
if (_interestPerSymbol[_adaUsdt.Symbol] != 1)
{
throw new RegressionTestException($"Unexpected interest rate count {_interestPerSymbol[_adaUsdt.Symbol]}");
}
}
public override void OnOrderEvent(OrderEvent orderEvent)
{
Debug(Time + " " + orderEvent);
}
/// <summary>
/// This is used by the regression test system to indicate if the open source Lean repository has the required data to run this algorithm.
/// </summary>
public bool CanRunLocally { get; } = true;
/// <summary>
/// This is used by the regression test system to indicate which languages this algorithm is written in.
/// </summary>
public List<Language> Languages { get; } = new() { Language.CSharp, Language.Python };
/// <summary>
/// Data Points count of all timeslices of algorithm
/// </summary>
public long DataPoints => 50;
/// <summary>
/// Data Points count of the algorithm history
/// </summary>
public int AlgorithmHistoryDataPoints => 0;
/// <summary>
/// Final status of the algorithm
/// </summary>
public AlgorithmStatus AlgorithmStatus => AlgorithmStatus.Completed;
/// <summary>
/// This is used by the regression test system to indicate what the expected statistics are from running the algorithm
/// </summary>
public Dictionary<string, string> ExpectedStatistics => new Dictionary<string, string>
{
{"Total Orders", "3"},
{"Average Win", "0%"},
{"Average Loss", "0%"},
{"Compounding Annual Return", "0%"},
{"Drawdown", "0%"},
{"Expectancy", "0"},
{"Start Equity", "1000200"},
{"End Equity", "1000189.47"},
{"Net Profit", "0%"},
{"Sharpe Ratio", "0"},
{"Sortino Ratio", "0"},
{"Probabilistic Sharpe Ratio", "0%"},
{"Loss Rate", "0%"},
{"Win Rate", "0%"},
{"Profit-Loss Ratio", "0"},
{"Alpha", "0"},
{"Beta", "0"},
{"Annual Standard Deviation", "0"},
{"Annual Variance", "0"},
{"Information Ratio", "0"},
{"Tracking Error", "0"},
{"Treynor Ratio", "0"},
{"Total Fees", "$0.61"},
{"Estimated Strategy Capacity", "$460000000.00"},
{"Lowest Capacity Asset", "ADAUSDT 18R"},
{"Portfolio Turnover", "0.12%"},
{"Drawdown Recovery", "0"},
{"OrderListHash", "50a51d06d03a5355248a6bccef1ca521"}
};
}
}
@@ -0,0 +1,116 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System.Collections.Generic;
using QuantConnect.Data;
using QuantConnect.Interfaces;
namespace QuantConnect.Algorithm.CSharp
{
/// <summary>
/// Demonstration of requesting daily resolution data for US Equities.
/// This is a simple regression test algorithm using a skeleton algorithm and requesting daily data.
/// </summary>
/// <meta name="tag" content="using data" />
public class BasicTemplateDailyAlgorithm : QCAlgorithm, IRegressionAlgorithmDefinition
{
private Symbol _spy = QuantConnect.Symbol.Create("SPY", SecurityType.Equity, Market.USA);
/// <summary>
/// Initialise the data and resolution required, as well as the cash and start-end dates for your algorithm. All algorithms must initialized.
/// </summary>
public override void Initialize()
{
SetStartDate(2013, 10, 08); //Set Start Date
SetEndDate(2013, 10, 17); //Set End Date
SetCash(100000); //Set Strategy Cash
// Find more symbols here: http://quantconnect.com/data
AddEquity("SPY", Resolution.Daily);
}
/// <summary>
/// OnData event is the primary entry point for your algorithm. Each new data point will be pumped in here.
/// </summary>
/// <param name="slice">Slice object keyed by symbol containing the stock data</param>
public override void OnData(Slice slice)
{
if (!Portfolio.Invested)
{
SetHoldings(_spy, 1);
Debug("Purchased Stock");
}
}
/// <summary>
/// This is used by the regression test system to indicate if the open source Lean repository has the required data to run this algorithm.
/// </summary>
public bool CanRunLocally { get; } = true;
/// <summary>
/// This is used by the regression test system to indicate which languages this algorithm is written in.
/// </summary>
public List<Language> Languages { get; } = new() { Language.CSharp, Language.Python };
/// <summary>
/// Data Points count of all timeslices of algorithm
/// </summary>
public long DataPoints => 72;
/// <summary>
/// Data Points count of the algorithm history
/// </summary>
public int AlgorithmHistoryDataPoints => 0;
/// <summary>
/// Final status of the algorithm
/// </summary>
public AlgorithmStatus AlgorithmStatus => AlgorithmStatus.Completed;
/// <summary>
/// This is used by the regression test system to indicate what the expected statistics are from running the algorithm
/// </summary>
public Dictionary<string, string> ExpectedStatistics => new Dictionary<string, string>
{
{"Total Orders", "1"},
{"Average Win", "0%"},
{"Average Loss", "0%"},
{"Compounding Annual Return", "424.375%"},
{"Drawdown", "0.800%"},
{"Expectancy", "0"},
{"Start Equity", "100000"},
{"End Equity", "104486.22"},
{"Net Profit", "4.486%"},
{"Sharpe Ratio", "17.304"},
{"Sortino Ratio", "35.217"},
{"Probabilistic Sharpe Ratio", "96.710%"},
{"Loss Rate", "0%"},
{"Win Rate", "0%"},
{"Profit-Loss Ratio", "0"},
{"Alpha", "-0.249"},
{"Beta", "1.015"},
{"Annual Standard Deviation", "0.141"},
{"Annual Variance", "0.02"},
{"Information Ratio", "-19"},
{"Tracking Error", "0.011"},
{"Treynor Ratio", "2.403"},
{"Total Fees", "$3.49"},
{"Estimated Strategy Capacity", "$1200000000.00"},
{"Lowest Capacity Asset", "SPY R735QTJ8XC9X"},
{"Portfolio Turnover", "10.01%"},
{"Drawdown Recovery", "1"},
{"OrderListHash", "70f21e930175a2ec9d465b21edc1b6d9"}
};
}
}
@@ -0,0 +1,240 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
using System;
using System.Collections.Generic;
using QuantConnect.Data;
using QuantConnect.Data.UniverseSelection;
using QuantConnect.Interfaces;
using QuantConnect.Orders;
using QuantConnect.Securities;
using QuantConnect.Securities.Future;
namespace QuantConnect.Algorithm.CSharp
{
/// <summary>
/// This algorithm tests and demonstrates EUREX futures subscription and trading:
/// - It tests contracts rollover by adding a continuous future and asserting that mapping happens at some point.
/// - It tests basic trading by buying a contract and holding it until expiration.
/// - It tests delisting and asserts the holdings are liquidated after that.
/// </summary>
public class BasicTemplateEurexFuturesAlgorithm : QCAlgorithm, IRegressionAlgorithmDefinition
{
private Future _continuousContract;
private Symbol _mappedSymbol;
private Symbol _contractToTrade;
private int _mappingsCount;
private decimal _boughtQuantity;
private decimal _liquidatedQuantity;
private bool _delisted;
public override void Initialize()
{
SetStartDate(2024, 5, 30);
SetEndDate(2024, 6, 23);
SetAccountCurrency(Currencies.EUR);
SetCash(1000000);
_continuousContract = AddFuture(Futures.Indices.EuroStoxx50, Resolution.Minute,
dataNormalizationMode: DataNormalizationMode.BackwardsRatio,
dataMappingMode: DataMappingMode.FirstDayMonth,
contractDepthOffset: 0);
_continuousContract.SetFilter(TimeSpan.Zero, TimeSpan.FromDays(180));
_mappedSymbol = _continuousContract.Mapped;
var benchmark = AddIndex("SX5E");
SetBenchmark(benchmark.Symbol);
var seeder = new FuncSecuritySeeder(GetLastKnownPrices);
SetSecurityInitializer(security => seeder.SeedSecurity(security));
}
public override void OnData(Slice slice)
{
foreach (var changedEvent in slice.SymbolChangedEvents.Values)
{
if (++_mappingsCount > 1)
{
throw new RegressionTestException($"{Time} - Unexpected number of symbol changed events (mappings): {_mappingsCount}. " +
$"Expected only 1.");
}
Debug($"{Time} - SymbolChanged event: {changedEvent}");
if (changedEvent.OldSymbol != _mappedSymbol.ID.ToString())
{
throw new RegressionTestException($"{Time} - Unexpected symbol changed event old symbol: {changedEvent}");
}
if (changedEvent.NewSymbol != _continuousContract.Mapped.ID.ToString())
{
throw new RegressionTestException($"{Time} - Unexpected symbol changed event new symbol: {changedEvent}");
}
// Let's trade the previous mapped contract, so we can hold it until expiration for testing
// (will be sooner than the new mapped contract)
_contractToTrade = _mappedSymbol;
_mappedSymbol = _continuousContract.Mapped;
}
// Let's trade after the mapping is done
if (_contractToTrade != null && _boughtQuantity == 0 && Securities[_contractToTrade].Exchange.ExchangeOpen)
{
Buy(_contractToTrade, 1);
}
if (_contractToTrade != null && slice.Delistings.TryGetValue(_contractToTrade, out var delisting))
{
if (delisting.Type == DelistingType.Delisted)
{
_delisted = true;
if (Portfolio.Invested)
{
throw new RegressionTestException($"{Time} - Portfolio should not be invested after the traded contract is delisted.");
}
}
}
}
public override void OnOrderEvent(OrderEvent orderEvent)
{
if (orderEvent.Symbol != _contractToTrade)
{
throw new RegressionTestException($"{Time} - Unexpected order event symbol: {orderEvent.Symbol}. Expected {_contractToTrade}");
}
if (orderEvent.Direction == OrderDirection.Buy)
{
if (orderEvent.Status == OrderStatus.Filled)
{
if (_boughtQuantity != 0 && _liquidatedQuantity != 0)
{
throw new RegressionTestException($"{Time} - Unexpected buy order event status: {orderEvent.Status}");
}
_boughtQuantity = orderEvent.Quantity;
}
}
else if (orderEvent.Direction == OrderDirection.Sell)
{
if (orderEvent.Status == OrderStatus.Filled)
{
if (_boughtQuantity <= 0 && _liquidatedQuantity != 0)
{
throw new RegressionTestException($"{Time} - Unexpected sell order event status: {orderEvent.Status}");
}
_liquidatedQuantity = orderEvent.Quantity;
if (_liquidatedQuantity != -_boughtQuantity)
{
throw new RegressionTestException($"{Time} - Unexpected liquidated quantity: {_liquidatedQuantity}. Expected: {-_boughtQuantity}");
}
}
}
}
public override void OnSecuritiesChanged(SecurityChanges changes)
{
foreach (var addedSecurity in changes.AddedSecurities)
{
if (addedSecurity.Symbol.SecurityType == SecurityType.Future && addedSecurity.Symbol.IsCanonical())
{
_mappedSymbol = _continuousContract.Mapped;
}
}
}
public override void OnEndOfAlgorithm()
{
if (_mappingsCount == 0)
{
throw new RegressionTestException($"Unexpected number of symbol changed events (mappings): {_mappingsCount}. Expected 1.");
}
if (!_delisted)
{
throw new RegressionTestException("Contract was not delisted");
}
// Make sure we traded and that the position was liquidated on delisting
if (_boughtQuantity <= 0 || _liquidatedQuantity >= 0)
{
throw new RegressionTestException($"Unexpected sold quantity: {_boughtQuantity} and liquidated quantity: {_liquidatedQuantity}");
}
}
/// <summary>
/// This is used by the regression test system to indicate if the open source Lean repository has the required data to run this algorithm.
/// </summary>
public bool CanRunLocally { get; } = true;
/// <summary>
/// This is used by the regression test system to indicate which languages this algorithm is written in.
/// </summary>
public List<Language> Languages { get; } = new() { Language.CSharp, Language.Python };
/// <summary>
/// Data Points count of all timeslices of algorithm
/// </summary>
public long DataPoints => 94326;
/// <summary>
/// Data Points count of the algorithm history
/// </summary>
public int AlgorithmHistoryDataPoints => 0;
/// <summary>
/// Final status of the algorithm
/// </summary>
public AlgorithmStatus AlgorithmStatus => AlgorithmStatus.Completed;
/// <summary>
/// This is used by the regression test system to indicate what the expected statistics are from running the algorithm
/// </summary>
public Dictionary<string, string> ExpectedStatistics => new Dictionary<string, string>
{
{"Total Orders", "2"},
{"Average Win", "0%"},
{"Average Loss", "-0.11%"},
{"Compounding Annual Return", "-1.667%"},
{"Drawdown", "0.100%"},
{"Expectancy", "-1"},
{"Start Equity", "1000000"},
{"End Equity", "998849.48"},
{"Net Profit", "-0.115%"},
{"Sharpe Ratio", "-34.455"},
{"Sortino Ratio", "-57.336"},
{"Probabilistic Sharpe Ratio", "0%"},
{"Loss Rate", "100%"},
{"Win Rate", "0%"},
{"Profit-Loss Ratio", "0"},
{"Alpha", "0"},
{"Beta", "0"},
{"Annual Standard Deviation", "0.002"},
{"Annual Variance", "0"},
{"Information Ratio", "-6.176"},
{"Tracking Error", "0.002"},
{"Treynor Ratio", "0"},
{"Total Fees", "€1.02"},
{"Estimated Strategy Capacity", "€2300000000.00"},
{"Lowest Capacity Asset", "FESX YJHOAMPYKRS5"},
{"Portfolio Turnover", "0.40%"},
{"Drawdown Recovery", "0"},
{"OrderListHash", "ac9acc478ba1afe53993cdbb92f8ec6e"}
};
}
}
@@ -0,0 +1,55 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using QuantConnect.Data;
using QuantConnect.Data.Market;
namespace QuantConnect.Algorithm.CSharp
{
/// <summary>
/// Skeleton algorithm demonstrating filling forward data through gaps and inconsistent data. By default LEAN fills the previous bar forward
/// so you get regular bars.
/// </summary>
/// <meta name="tag" content="using data" />
public class BasicTemplateFillForwardAlgorithm : QCAlgorithm
{
private Symbol _asur = QuantConnect.Symbol.Create("ASUR", SecurityType.Equity, Market.USA);
/// <summary>
/// Initialise the data and resolution required, as well as the cash and start-end dates for your algorithm. All algorithms must initialized.
/// </summary>
public override void Initialize()
{
SetStartDate(2013, 10, 01); //Set Start Date
SetEndDate(2013, 11, 30); //Set End Date
SetCash(100000); //Set Strategy Cash
// Find more symbols here: http://quantconnect.com/data
AddSecurity(SecurityType.Equity, "ASUR", Resolution.Second);
}
/// <summary>
/// OnData event is the primary entry point for your algorithm. Each new data point will be pumped in here.
/// </summary>
/// <param name="slice">Slice object keyed by symbol containing the stock data</param>
public override void OnData(Slice slice)
{
if (!Portfolio.Invested)
{
SetHoldings(_asur, 1);
Debug("Purchased Stock");
}
}
}
}
@@ -0,0 +1,72 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using QuantConnect.Data;
using System;
namespace QuantConnect.Algorithm.CSharp
{
/// <summary>
/// Algorithm demonstrating FOREX asset types and requesting history on them in bulk. As FOREX uses
/// QuoteBars you should request slices or
/// </summary>
/// <meta name="tag" content="using data" />
/// <meta name="tag" content="history and warm up" />
/// <meta name="tag" content="history" />
/// <meta name="tag" content="forex" />
public class BasicTemplateForexAlgorithm : QCAlgorithm
{
/// <summary>
/// Initialise the data and resolution required, as well as the cash and start-end dates for your algorithm. All algorithms must initialized.
/// </summary>
public override void Initialize()
{
SetStartDate(2014, 5, 7); //Set Start Date
SetEndDate(2014, 5, 15); //Set End Date
SetCash(100000); //Set Strategy Cash
// Find more symbols here: http://quantconnect.com/data
AddForex("EURUSD");
AddForex("NZDUSD");
var dailyHistory = History(5, Resolution.Daily);
var hourHistory = History(5, Resolution.Hour);
var minuteHistory = History(5, Resolution.Minute);
var secondHistory = History(5, Resolution.Second);
// Log values from history request of second-resolution data
foreach (var data in secondHistory)
{
foreach (var key in data.Keys)
{
Log(key.Value + ": " + data.Time + " > " + data[key].Value);
}
}
}
/// <summary>
/// OnData event is the primary entry point for your algorithm. Each new data point will be pumped in here.
/// </summary>
/// <param name="data">Slice object keyed by symbol containing the stock data</param>
public override void OnData(Slice slice)
{
if (!Portfolio.Invested)
{
SetHoldings("EURUSD", .5);
SetHoldings("NZDUSD", .5);
Log(string.Join(", ", slice.Values));
}
}
}
}
@@ -0,0 +1,137 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.Collections.Generic;
using QuantConnect.Algorithm.Framework.Alphas;
using QuantConnect.Algorithm.Framework.Execution;
using QuantConnect.Algorithm.Framework.Portfolio;
using QuantConnect.Algorithm.Framework.Risk;
using QuantConnect.Algorithm.Framework.Selection;
using QuantConnect.Orders;
using QuantConnect.Interfaces;
namespace QuantConnect.Algorithm.CSharp
{
/// <summary>
/// Basic template framework algorithm uses framework components to define the algorithm.
/// </summary>
/// <meta name="tag" content="using data" />
/// <meta name="tag" content="using quantconnect" />
/// <meta name="tag" content="trading and orders" />
public class BasicTemplateFrameworkAlgorithm : QCAlgorithm, IRegressionAlgorithmDefinition
{
/// <summary>
/// Initialise the data and resolution required, as well as the cash and start-end dates for your algorithm. All algorithms must initialized.
/// </summary>
public override void Initialize()
{
// Set requested data resolution
UniverseSettings.Resolution = Resolution.Minute;
SetStartDate(2013, 10, 07); //Set Start Date
SetEndDate(2013, 10, 11); //Set End Date
SetCash(100000); //Set Strategy Cash
// Find more symbols here: http://quantconnect.com/data
// Forex, CFD, Equities Resolutions: Tick, Second, Minute, Hour, Daily.
// Futures Resolution: Tick, Second, Minute
// Options Resolution: Minute Only.
// set algorithm framework models
SetUniverseSelection(new ManualUniverseSelectionModel(QuantConnect.Symbol.Create("SPY", SecurityType.Equity, Market.USA)));
SetAlpha(new ConstantAlphaModel(InsightType.Price, InsightDirection.Up, TimeSpan.FromMinutes(20), 0.025, null));
// We can define who often the EWPCM will rebalance if no new insight is submitted using:
// Resolution Enum:
SetPortfolioConstruction(new EqualWeightingPortfolioConstructionModel(Resolution.Daily));
// TimeSpan
// SetPortfolioConstruction(new EqualWeightingPortfolioConstructionModel(TimeSpan.FromDays(2)));
// A Func<DateTime, DateTime>. In this case, we can use the pre-defined func at Expiry helper class
// SetPortfolioConstruction(new EqualWeightingPortfolioConstructionModel(Expiry.EndOfWeek));
SetExecution(new ImmediateExecutionModel());
SetRiskManagement(new MaximumDrawdownPercentPerSecurity(0.01m));
}
public override void OnOrderEvent(OrderEvent orderEvent)
{
if (orderEvent.Status.IsFill())
{
Debug($"Purchased Stock: {orderEvent.Symbol}");
}
}
/// <summary>
/// This is used by the regression test system to indicate if the open source Lean repository has the required data to run this algorithm.
/// </summary>
public bool CanRunLocally { get; } = true;
/// <summary>
/// This is used by the regression test system to indicate which languages this algorithm is written in.
/// </summary>
public virtual List<Language> Languages { get; } = new() { Language.CSharp, Language.Python };
/// <summary>
/// Data Points count of all timeslices of algorithm
/// </summary>
public long DataPoints => 3943;
/// <summary>
/// Data Points count of the algorithm history
/// </summary>
public int AlgorithmHistoryDataPoints => 0;
/// <summary>
/// Final status of the algorithm
/// </summary>
public AlgorithmStatus AlgorithmStatus => AlgorithmStatus.Completed;
/// <summary>
/// This is used by the regression test system to indicate what the expected statistics are from running the algorithm
/// </summary>
public Dictionary<string, string> ExpectedStatistics => new Dictionary<string, string>
{
{"Total Orders", "3"},
{"Average Win", "0%"},
{"Average Loss", "-1.01%"},
{"Compounding Annual Return", "261.134%"},
{"Drawdown", "2.200%"},
{"Expectancy", "-1"},
{"Start Equity", "100000"},
{"End Equity", "101655.30"},
{"Net Profit", "1.655%"},
{"Sharpe Ratio", "8.472"},
{"Sortino Ratio", "0"},
{"Probabilistic Sharpe Ratio", "66.693%"},
{"Loss Rate", "100%"},
{"Win Rate", "0%"},
{"Profit-Loss Ratio", "0"},
{"Alpha", "-0.091"},
{"Beta", "1.006"},
{"Annual Standard Deviation", "0.224"},
{"Annual Variance", "0.05"},
{"Information Ratio", "-33.445"},
{"Tracking Error", "0.002"},
{"Treynor Ratio", "1.885"},
{"Total Fees", "$10.32"},
{"Estimated Strategy Capacity", "$27000000.00"},
{"Lowest Capacity Asset", "SPY R735QTJ8XC9X"},
{"Portfolio Turnover", "59.86%"},
{"Drawdown Recovery", "3"},
{"OrderListHash", "f209ed42701b0419858e0100595b40c0"}
};
}
}
@@ -0,0 +1,95 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.Linq;
using QuantConnect.Data;
using QuantConnect.Orders;
using QuantConnect.Securities;
namespace QuantConnect.Algorithm.CSharp
{
/// <summary>
/// Algorithm demonstrating FutureOption asset types and requesting history.
/// </summary>
/// <meta name="tag" content="using data" />
/// <meta name="tag" content="history" />
/// <meta name="tag" content="future option" />
public class BasicTemplateFutureOptionAlgorithm : QCAlgorithm
{
private Symbol _symbol;
/// <summary>
/// Initialise the data and resolution required, as well as the cash and start-end dates for your algorithm. All algorithms must initialized.
/// </summary>
public override void Initialize()
{
SetStartDate(2022, 1, 1);
SetEndDate(2022, 2, 1);
SetCash(100000);
var gold_futures = AddFuture(Futures.Metals.Gold, Resolution.Minute);
gold_futures.SetFilter(0, 180);
_symbol = gold_futures.Symbol;
AddFutureOption(_symbol, universe => universe.Strikes(-5, +5)
.CallsOnly()
.BackMonth()
.OnlyApplyFilterAtMarketOpen());
// Historical Data
var history = History(_symbol, 60, Resolution.Daily);
Log($"Received {history.Count()} bars from {_symbol} FutureOption historical data call.");
}
/// <summary>
/// OnData event is the primary entry point for your algorithm. Each new data point will be pumped in here.
/// </summary>
/// <param name="data">Slice object keyed by symbol containing the stock data</param>
public override void OnData(Slice slice)
{
// Access Data
foreach(var kvp in slice.OptionChains)
{
var underlyingFutureContract = kvp.Key.Underlying;
var chain = kvp.Value;
if (chain.Count() == 0) continue;
foreach(var contract in chain)
{
Log($@"Canonical Symbol: {kvp.Key};
Contract: {contract};
Right: {contract.Right};
Expiry: {contract.Expiry};
Bid price: {contract.BidPrice};
Ask price: {contract.AskPrice};
Implied Volatility: {contract.ImpliedVolatility}");
}
if (!Portfolio.Invested)
{
var atmStrike = chain.OrderBy(x => Math.Abs(chain.Underlying.Price - x.Strike)).First().Strike;
var selectedContract = chain.Where(x => x.Strike == atmStrike).OrderByDescending(x => x.Expiry).First();
MarketOrder(selectedContract.Symbol, 1);
}
}
}
public override void OnOrderEvent(OrderEvent orderEvent)
{
Debug($"{Time} {orderEvent.ToString()}");
}
}
}
@@ -0,0 +1,226 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
using System.Collections.Generic;
using QuantConnect.Data;
using QuantConnect.Interfaces;
using QuantConnect.Indicators;
using QuantConnect.Securities;
using QuantConnect.Securities.Future;
namespace QuantConnect.Algorithm.CSharp
{
/// <summary>
/// Example algorithm for trading continuous future
/// </summary>
public class BasicTemplateFutureRolloverAlgorithm : QCAlgorithm, IRegressionAlgorithmDefinition
{
private Dictionary<Symbol, SymbolData> _symbolDataBySymbol = new();
/// <summary>
/// Initialise the data and resolution required, as well as the cash and start-end dates for your algorithm. All algorithms must initialized.
/// </summary>
public override void Initialize()
{
SetStartDate(2013, 10, 8);
SetEndDate(2013, 12, 10);
SetCash(1000000);
var futures = new List<string> {
Futures.Indices.SP500EMini
};
foreach (var future in futures)
{
// Requesting data
var continuousContract = AddFuture(future,
resolution: Resolution.Daily,
extendedMarketHours: true,
dataNormalizationMode: DataNormalizationMode.BackwardsRatio,
dataMappingMode: DataMappingMode.OpenInterest,
contractDepthOffset: 0
);
var symbolData = new SymbolData(this, continuousContract);
_symbolDataBySymbol.Add(continuousContract.Symbol, symbolData);
}
}
/// <summary>
/// OnData event is the primary entry point for your algorithm. Each new data point will be pumped in here.
/// </summary>
/// <param name="slice">Slice object keyed by symbol containing the stock data</param>
public override void OnData(Slice slice)
{
foreach (var kvp in _symbolDataBySymbol)
{
var symbol = kvp.Key;
var symbolData = kvp.Value;
// Call SymbolData.Update() method to handle new data slice received
symbolData.Update(slice);
// Check if information in SymbolData class and new slice data are ready for trading
if (!symbolData.IsReady || !slice.Bars.ContainsKey(symbol))
{
return;
}
var emaCurrentValue = symbolData.EMA.Current.Value;
if (emaCurrentValue < symbolData.Price && !symbolData.IsLong)
{
MarketOrder(symbolData.Mapped, 1);
}
else if (emaCurrentValue > symbolData.Price && !symbolData.IsShort)
{
MarketOrder(symbolData.Mapped, -1);
}
}
}
/// <summary>
/// Abstracted class object to hold information (state, indicators, methods, etc.) from a Symbol/Security in a multi-security algorithm
/// </summary>
public class SymbolData
{
private QCAlgorithm _algorithm;
private Future _future;
public ExponentialMovingAverage EMA { get; set; }
public decimal Price { get; set; }
public bool IsLong { get; set; }
public bool IsShort { get; set; }
public Symbol Symbol => _future.Symbol;
public Symbol Mapped => _future.Mapped;
/// <summary>
/// Check if symbolData class object are ready for trading
/// </summary>
public bool IsReady => Mapped != null && EMA.IsReady;
/// <summary>
/// Constructor to instantiate the information needed to be hold
/// </summary>
public SymbolData(QCAlgorithm algorithm, Future future)
{
_algorithm = algorithm;
_future = future;
EMA = algorithm.EMA(future.Symbol, 20, Resolution.Daily);
Reset();
}
/// <summary>
/// Handler of new slice of data received
/// </summary>
public void Update(Slice slice)
{
if (slice.SymbolChangedEvents.TryGetValue(Symbol, out var changedEvent))
{
var oldSymbol = changedEvent.OldSymbol;
var newSymbol = changedEvent.NewSymbol;
var tag = $"Rollover - Symbol changed at {_algorithm.Time}: {oldSymbol} -> {newSymbol}";
var quantity = _algorithm.Portfolio[oldSymbol].Quantity;
// Rolling over: to liquidate any position of the old mapped contract and switch to the newly mapped contract
_algorithm.Liquidate(oldSymbol, tag: tag);
_algorithm.MarketOrder(newSymbol, quantity, tag: tag);
Reset();
}
Price = slice.Bars.ContainsKey(Symbol) ? slice.Bars[Symbol].Price : Price;
IsLong = _algorithm.Portfolio[Mapped].IsLong;
IsShort = _algorithm.Portfolio[Mapped].IsShort;
}
/// <summary>
/// Reset RollingWindow/indicator to adapt to newly mapped contract, then warm up the RollingWindow/indicator
/// </summary>
private void Reset()
{
EMA.Reset();
_algorithm.WarmUpIndicator(Symbol, EMA, Resolution.Daily);
}
/// <summary>
/// Disposal method to remove consolidator/update method handler, and reset RollingWindow/indicator to free up memory and speed
/// </summary>
public void Dispose()
{
EMA.Reset();
}
}
/// <summary>
/// This is used by the regression test system to indicate if the open source Lean repository has the required data to run this algorithm.
/// </summary>
public bool CanRunLocally { get; } = true;
/// <summary>
/// This is used by the regression test system to indicate which languages this algorithm is written in.
/// </summary>
public List<Language> Languages { get; } = new() { Language.CSharp, Language.Python };
/// <summary>
/// Data Points count of all timeslices of algorithm
/// </summary>
public long DataPoints => 727;
/// <summary>
/// Data Points count of the algorithm history
/// </summary>
public int AlgorithmHistoryDataPoints => 2;
/// <summary>
/// Final status of the algorithm
/// </summary>
public AlgorithmStatus AlgorithmStatus => AlgorithmStatus.Completed;
/// <summary>
/// This is used by the regression test system to indicate what the expected statistics are from running the algorithm
/// </summary>
public Dictionary<string, string> ExpectedStatistics => new Dictionary<string, string>
{
{"Total Orders", "3"},
{"Average Win", "0.14%"},
{"Average Loss", "0%"},
{"Compounding Annual Return", "0.770%"},
{"Drawdown", "0.100%"},
{"Expectancy", "0"},
{"Start Equity", "1000000"},
{"End Equity", "1001341.4"},
{"Net Profit", "0.134%"},
{"Sharpe Ratio", "-0.494"},
{"Sortino Ratio", "-0.544"},
{"Probabilistic Sharpe Ratio", "23.043%"},
{"Loss Rate", "0%"},
{"Win Rate", "100%"},
{"Profit-Loss Ratio", "0"},
{"Alpha", "-0.015"},
{"Beta", "0.03"},
{"Annual Standard Deviation", "0.004"},
{"Annual Variance", "0"},
{"Information Ratio", "-5.235"},
{"Tracking Error", "0.081"},
{"Treynor Ratio", "-0.069"},
{"Total Fees", "$6.45"},
{"Estimated Strategy Capacity", "$780000000000.00"},
{"Lowest Capacity Asset", "ES VMKLFZIH2MTD"},
{"Portfolio Turnover", "0.42%"},
{"Drawdown Recovery", "3"},
{"OrderListHash", "d17bbe62c86730e5178528a3153df0e6"}
};
}
}
@@ -0,0 +1,199 @@
/*
* 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.Data.UniverseSelection;
using QuantConnect.Interfaces;
using QuantConnect.Securities;
using QuantConnect.Securities.Future;
namespace QuantConnect.Algorithm.CSharp
{
/// <summary>
/// This example demonstrates how to add futures for a given underlying asset.
/// It also shows how you can prefilter contracts easily based on expirations, and how you
/// can inspect the futures chain to pick a specific contract to trade.
/// </summary>
/// <meta name="tag" content="using data" />
/// <meta name="tag" content="benchmarks" />
/// <meta name="tag" content="futures" />
public class BasicTemplateFuturesAlgorithm : QCAlgorithm, IRegressionAlgorithmDefinition
{
private Symbol _contractSymbol;
// S&P 500 EMini futures
private const string RootSP500 = Futures.Indices.SP500EMini;
// Gold futures
private const string RootGold = Futures.Metals.Gold;
/// <summary>
/// Initialize your algorithm and add desired assets.
/// </summary>
public override void Initialize()
{
SetStartDate(2013, 10, 08);
SetEndDate(2013, 10, 10);
SetCash(1000000);
var futureSP500 = AddFuture(RootSP500);
var futureGold = AddFuture(RootGold);
// set our expiry filter for this futures chain
// SetFilter method accepts TimeSpan objects or integer for days.
// The following statements yield the same filtering criteria
futureSP500.SetFilter(TimeSpan.Zero, TimeSpan.FromDays(182));
futureGold.SetFilter(0, 182);
var benchmark = AddEquity("SPY");
SetBenchmark(benchmark.Symbol);
var seeder = new FuncSecuritySeeder(GetLastKnownPrices);
SetSecurityInitializer(security => seeder.SeedSecurity(security));
}
/// <summary>
/// Event - v3.0 DATA EVENT HANDLER: (Pattern) Basic template for user to override for receiving all subscription data in a single event
/// </summary>
/// <param name="slice">The current slice of data keyed by symbol string</param>
public override void OnData(Slice slice)
{
foreach (var changedEvent in slice.SymbolChangedEvents.Values)
{
Debug($"{Time} - SymbolChanged event: {changedEvent}");
if (Time.TimeOfDay != TimeSpan.Zero)
{
throw new RegressionTestException($"{Time} unexpected symbol changed event {changedEvent}!");
}
}
if (!Portfolio.Invested)
{
foreach(var chain in slice.FutureChains)
{
// find the front contract expiring no earlier than in 90 days
var contract = (
from futuresContract in chain.Value.OrderBy(x => x.Expiry)
where futuresContract.Expiry > Time.Date.AddDays(90)
select futuresContract
).FirstOrDefault();
// if found, trade it
if (contract != null)
{
_contractSymbol = contract.Symbol;
MarketOrder(_contractSymbol, 1);
}
}
}
else
{
Liquidate();
}
}
public override void OnEndOfAlgorithm()
{
// Get the margin requirements
var buyingPowerModel = Securities[_contractSymbol].BuyingPowerModel;
var futureMarginModel = buyingPowerModel as FutureMarginModel;
if (buyingPowerModel == null)
{
throw new RegressionTestException($"Invalid buying power model. Found: {buyingPowerModel.GetType().Name}. Expected: {nameof(FutureMarginModel)}");
}
var initialOvernight = futureMarginModel.InitialOvernightMarginRequirement;
var maintenanceOvernight = futureMarginModel.MaintenanceOvernightMarginRequirement;
var initialIntraday = futureMarginModel.InitialIntradayMarginRequirement;
var maintenanceIntraday = futureMarginModel.MaintenanceIntradayMarginRequirement;
}
public override void OnSecuritiesChanged(SecurityChanges changes)
{
foreach (var addedSecurity in changes.AddedSecurities)
{
if (addedSecurity.Symbol.SecurityType == SecurityType.Future
&& !addedSecurity.Symbol.IsCanonical()
&& !addedSecurity.HasData)
{
throw new RegressionTestException($"Future contracts did not work up as expected: {addedSecurity.Symbol}");
}
}
}
/// <summary>
/// This is used by the regression test system to indicate if the open source Lean repository has the required data to run this algorithm.
/// </summary>
public bool CanRunLocally { get; } = true;
/// <summary>
/// This is used by the regression test system to indicate which languages this algorithm is written in.
/// </summary>
public List<Language> Languages { get; } = new() { Language.CSharp, Language.Python };
/// <summary>
/// Data Points count of all timeslices of algorithm
/// </summary>
public long DataPoints => 40308;
/// <summary>
/// Data Points count of the algorithm history
/// </summary>
public int AlgorithmHistoryDataPoints => 354;
/// <summary>
/// Final status of the algorithm
/// </summary>
public AlgorithmStatus AlgorithmStatus => AlgorithmStatus.Completed;
/// <summary>
/// This is used by the regression test system to indicate what the expected statistics are from running the algorithm
/// </summary>
public Dictionary<string, string> ExpectedStatistics => new Dictionary<string, string>
{
{"Total Orders", "2700"},
{"Average Win", "0.00%"},
{"Average Loss", "0.00%"},
{"Compounding Annual Return", "-99.597%"},
{"Drawdown", "4.400%"},
{"Expectancy", "-0.724"},
{"Start Equity", "1000000"},
{"End Equity", "955700.5"},
{"Net Profit", "-4.430%"},
{"Sharpe Ratio", "-31.63"},
{"Sortino Ratio", "-31.63"},
{"Probabilistic Sharpe Ratio", "0%"},
{"Loss Rate", "83%"},
{"Win Rate", "17%"},
{"Profit-Loss Ratio", "0.65"},
{"Alpha", "-3.065"},
{"Beta", "0.128"},
{"Annual Standard Deviation", "0.031"},
{"Annual Variance", "0.001"},
{"Information Ratio", "-81.232"},
{"Tracking Error", "0.212"},
{"Treynor Ratio", "-7.677"},
{"Total Fees", "$6237.00"},
{"Estimated Strategy Capacity", "$14000.00"},
{"Lowest Capacity Asset", "GC VOFJUCDY9XNH"},
{"Portfolio Turnover", "9912.69%"},
{"Drawdown Recovery", "0"},
{"OrderListHash", "6e0f767a46a54365287801295cf7bb75"}
};
}
}
@@ -0,0 +1,80 @@
/*
* 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 QuantConnect.Data.Market;
using QuantConnect.Securities;
using System.Collections.Generic;
using QuantConnect.Data.Consolidators;
namespace QuantConnect.Algorithm.CSharp
{
/// <summary>
/// A demonstration of consolidating futures data into larger bars for your algorithm.
/// </summary>
/// <meta name="tag" content="using data" />
/// <meta name="tag" content="benchmarks" />
/// <meta name="tag" content="consolidating data" />
/// <meta name="tag" content="futures" />
public class BasicTemplateFuturesConsolidationAlgorithm : QCAlgorithm
{
private const string RootSP500 = Futures.Indices.SP500EMini;
private HashSet<Symbol> _futureContracts = new HashSet<Symbol>();
public override void Initialize()
{
SetStartDate(2013, 10, 8);
SetEndDate(2013, 10, 11);
SetCash(1000000);
var futureSP500 = AddFuture(RootSP500);
// set our expiry filter for this future chain
// SetFilter method accepts TimeSpan objects or integer for days.
// The following statements yield the same filtering criteria
futureSP500.SetFilter(0, 182);
// futureSP500.SetFilter(TimeSpan.Zero, TimeSpan.FromDays(182));
SetBenchmark(x => 0);
}
public override void OnData(Slice slice)
{
foreach (var chain in slice.FutureChains)
{
foreach (var contract in chain.Value)
{
if (!_futureContracts.Contains(contract.Symbol))
{
_futureContracts.Add(contract.Symbol);
var consolidator = new QuoteBarConsolidator(TimeSpan.FromMinutes(5));
consolidator.DataConsolidated += OnDataConsolidated;
SubscriptionManager.AddConsolidator(contract.Symbol, consolidator);
Log("Added new consolidator for " + contract.Symbol.Value);
}
}
}
}
public void OnDataConsolidated(object sender, QuoteBar quoteBar)
{
Log("OnDataConsolidated called");
Log(quoteBar.ToString());
}
}
}
@@ -0,0 +1,177 @@
/*
* 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.Data.UniverseSelection;
using QuantConnect.Interfaces;
using QuantConnect.Securities;
using QuantConnect.Securities.Future;
namespace QuantConnect.Algorithm.CSharp
{
/// <summary>
/// This example demonstrates how to add futures with daily resolution.
/// </summary>
/// <meta name="tag" content="using data" />
/// <meta name="tag" content="benchmarks" />
/// <meta name="tag" content="futures" />
public class BasicTemplateFuturesDailyAlgorithm : QCAlgorithm, IRegressionAlgorithmDefinition
{
protected virtual Resolution Resolution => Resolution.Daily;
protected virtual bool ExtendedMarketHours => false;
// S&P 500 EMini futures
private const string RootSP500 = Futures.Indices.SP500EMini;
// Gold futures
private const string RootGold = Futures.Metals.Gold;
private Future _futureSP500;
private Future _futureGold;
/// <summary>
/// Initialize your algorithm and add desired assets.
/// </summary>
public override void Initialize()
{
SetStartDate(2013, 10, 08);
SetEndDate(2014, 10, 10);
SetCash(1000000);
_futureSP500 = AddFuture(RootSP500, Resolution, extendedMarketHours: ExtendedMarketHours);
_futureGold = AddFuture(RootGold, Resolution, extendedMarketHours: ExtendedMarketHours);
// set our expiry filter for this futures chain
// SetFilter method accepts TimeSpan objects or integer for days.
// The following statements yield the same filtering criteria
_futureSP500.SetFilter(TimeSpan.Zero, TimeSpan.FromDays(182));
_futureGold.SetFilter(0, 182);
}
/// <summary>
/// Event - v3.0 DATA EVENT HANDLER: (Pattern) Basic template for user to override for receiving all subscription data in a single event
/// </summary>
/// <param name="slice">The current slice of data keyed by symbol string</param>
public override void OnData(Slice slice)
{
if (!Portfolio.Invested)
{
foreach(var chain in slice.FutureChains)
{
// find the front contract expiring no earlier than in 90 days
var contract = (
from futuresContract in chain.Value.OrderBy(x => x.Expiry)
where futuresContract.Expiry > Time.Date.AddDays(90)
select futuresContract
).FirstOrDefault();
// if found, trade it.
// Also check if exchange is open for regular or extended hours. Since daily data comes at 8PM, this allows us prevent the
// algorithm from trading on friday when there is not after-market.
if (contract != null)
{
MarketOrder(contract.Symbol, 1);
}
}
}
// Same as above, check for cases like trading on a friday night.
else if (Securities.Values.Where(x => x.Invested).All(x => x.Exchange.Hours.IsOpen(Time, true)))
{
Liquidate();
}
foreach (var changedEvent in slice.SymbolChangedEvents.Values)
{
if (Time.TimeOfDay != TimeSpan.Zero)
{
throw new RegressionTestException($"{Time} unexpected symbol changed event {changedEvent}!");
}
}
}
public override void OnSecuritiesChanged(SecurityChanges changes)
{
if (changes.RemovedSecurities.Count > 0 &&
Portfolio.Invested &&
Securities.Values.Where(x => x.Invested).All(x => x.Exchange.Hours.IsOpen(Time, true)))
{
Liquidate();
}
}
/// <summary>
/// This is used by the regression test system to indicate if the open source Lean repository has the required data to run this algorithm.
/// </summary>
public virtual bool CanRunLocally { get; } = true;
/// <summary>
/// This is used by the regression test system to indicate which languages this algorithm is written in.
/// </summary>
public virtual List<Language> Languages { get; } = new() { Language.CSharp, Language.Python };
/// <summary>
/// Data Points count of all timeslices of algorithm
/// </summary>
public virtual long DataPoints => 5876;
/// <summary>
/// Data Points count of the algorithm history
/// </summary>
public virtual int AlgorithmHistoryDataPoints => 0;
/// <summary>
/// Final status of the algorithm
/// </summary>
public AlgorithmStatus AlgorithmStatus => AlgorithmStatus.Completed;
/// <summary>
/// This is used by the regression test system to indicate what the expected statistics are from running the algorithm
/// </summary>
public virtual Dictionary<string, string> ExpectedStatistics => new Dictionary<string, string>
{
{"Total Orders", "22"},
{"Average Win", "0.24%"},
{"Average Loss", "-0.49%"},
{"Compounding Annual Return", "-0.252%"},
{"Drawdown", "0.300%"},
{"Expectancy", "-0.258"},
{"Start Equity", "1000000"},
{"End Equity", "997465.73"},
{"Net Profit", "-0.253%"},
{"Sharpe Ratio", "-5.753"},
{"Sortino Ratio", "-1.032"},
{"Probabilistic Sharpe Ratio", "0.000%"},
{"Loss Rate", "50%"},
{"Win Rate", "50%"},
{"Profit-Loss Ratio", "0.48"},
{"Alpha", "-0.009"},
{"Beta", "0"},
{"Annual Standard Deviation", "0.002"},
{"Annual Variance", "0"},
{"Information Ratio", "-1.381"},
{"Tracking Error", "0.089"},
{"Treynor Ratio", "-19.581"},
{"Total Fees", "$6.77"},
{"Estimated Strategy Capacity", "$290000000.00"},
{"Lowest Capacity Asset", "GC VOFJUCDY9XNH"},
{"Portfolio Turnover", "0.12%"},
{"Drawdown Recovery", "0"},
{"OrderListHash", "140ff4560d532192be3041846667deca"}
};
}
}
@@ -0,0 +1,186 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.Collections.Generic;
using QuantConnect.Algorithm.Framework.Alphas;
using QuantConnect.Algorithm.Framework.Execution;
using QuantConnect.Algorithm.Framework.Portfolio;
using QuantConnect.Algorithm.Framework.Risk;
using QuantConnect.Algorithm.Framework.Selection;
using QuantConnect.Interfaces;
using QuantConnect.Securities;
namespace QuantConnect.Algorithm.CSharp
{
/// <summary>
/// Basic template futures framework algorithm uses framework components to define an algorithm
/// that trades futures.
/// </summary>
public class BasicTemplateFuturesFrameworkAlgorithm : QCAlgorithm, IRegressionAlgorithmDefinition
{
protected virtual bool ExtendedMarketHours => false;
public override void Initialize()
{
UniverseSettings.Resolution = Resolution.Minute;
UniverseSettings.ExtendedMarketHours = ExtendedMarketHours;
SetStartDate(2013, 10, 07);
SetEndDate(2013, 10, 11);
SetCash(100000);
// set framework models
SetUniverseSelection(new FrontMonthFutureUniverseSelectionModel(SelectFutureChainSymbols));
SetAlpha(new ConstantFutureContractAlphaModel(InsightType.Price, InsightDirection.Up, TimeSpan.FromDays(1)));
SetPortfolioConstruction(new SingleSharePortfolioConstructionModel());
SetExecution(new ImmediateExecutionModel());
SetRiskManagement(new NullRiskManagementModel());
}
// future symbol universe selection function
private static IEnumerable<Symbol> SelectFutureChainSymbols(DateTime utcTime)
{
var newYorkTime = utcTime.ConvertFromUtc(TimeZones.NewYork);
if (newYorkTime.Date < new DateTime(2013, 10, 09))
{
yield return QuantConnect.Symbol.Create(Futures.Indices.SP500EMini, SecurityType.Future, Market.CME);
}
if (newYorkTime.Date >= new DateTime(2013, 10, 09))
{
yield return QuantConnect.Symbol.Create(Futures.Metals.Gold, SecurityType.Future, Market.COMEX);
}
}
/// <summary>
/// Creates futures chain universes that select the front month contract and runs a user
/// defined futureChainSymbolSelector every day to enable choosing different futures chains
/// </summary>
class FrontMonthFutureUniverseSelectionModel : FutureUniverseSelectionModel
{
public FrontMonthFutureUniverseSelectionModel(Func<DateTime, IEnumerable<Symbol>> futureChainSymbolSelector)
: base(TimeSpan.FromDays(1), futureChainSymbolSelector)
{
}
/// <summary>
/// Defines the future chain universe filter
/// </summary>
protected override FutureFilterUniverse Filter(FutureFilterUniverse filter)
{
return filter
.FrontMonth()
.OnlyApplyFilterAtMarketOpen();
}
}
/// <summary>
/// Implementation of a constant alpha model that only emits insights for future symbols
/// </summary>
class ConstantFutureContractAlphaModel : ConstantAlphaModel
{
public ConstantFutureContractAlphaModel(InsightType type, InsightDirection direction, TimeSpan period)
: base(type, direction, period)
{
}
protected override bool ShouldEmitInsight(DateTime utcTime, Symbol symbol)
{
// only emit alpha for future symbols and not underlying equity symbols
if (symbol.SecurityType != SecurityType.Future)
{
return false;
}
return base.ShouldEmitInsight(utcTime, symbol);
}
}
/// <summary>
/// Portfolio construction model that sets target quantities to 1 for up insights and -1 for down insights
/// </summary>
class SingleSharePortfolioConstructionModel : PortfolioConstructionModel
{
public override IEnumerable<IPortfolioTarget> CreateTargets(QCAlgorithm algorithm, Insight[] insights)
{
foreach (var insight in insights)
{
yield return new PortfolioTarget(insight.Symbol, (int) insight.Direction);
}
}
}
/// <summary>
/// This is used by the regression test system to indicate if the open source Lean repository has the required data to run this algorithm.
/// </summary>
public virtual bool CanRunLocally { get; } = true;
/// <summary>
/// This is used by the regression test system to indicate which languages this algorithm is written in.
/// </summary>
public virtual List<Language> Languages { get; } = new() { Language.CSharp, Language.Python };
/// <summary>
/// Data Points count of all timeslices of algorithm
/// </summary>
public virtual long DataPoints => 24883;
/// <summary>
/// Data Points count of the algorithm history
/// </summary>
public virtual int AlgorithmHistoryDataPoints => 0;
/// <summary>
/// Final status of the algorithm
/// </summary>
public AlgorithmStatus AlgorithmStatus => AlgorithmStatus.Completed;
/// <summary>
/// This is used by the regression test system to indicate what the expected statistics are from running the algorithm
/// </summary>
public virtual Dictionary<string, string> ExpectedStatistics => new Dictionary<string, string>
{
{"Total Orders", "2"},
{"Average Win", "0%"},
{"Average Loss", "0%"},
{"Compounding Annual Return", "-81.734%"},
{"Drawdown", "4.100%"},
{"Expectancy", "0"},
{"Start Equity", "100000"},
{"End Equity", "97830.76"},
{"Net Profit", "-2.169%"},
{"Sharpe Ratio", "-10.299"},
{"Sortino Ratio", "-10.299"},
{"Probabilistic Sharpe Ratio", "0%"},
{"Loss Rate", "0%"},
{"Win Rate", "0%"},
{"Profit-Loss Ratio", "0"},
{"Alpha", "-1.212"},
{"Beta", "0.238"},
{"Annual Standard Deviation", "0.072"},
{"Annual Variance", "0.005"},
{"Information Ratio", "-15.404"},
{"Tracking Error", "0.176"},
{"Treynor Ratio", "-3.109"},
{"Total Fees", "$4.62"},
{"Estimated Strategy Capacity", "$17000000.00"},
{"Lowest Capacity Asset", "GC VL5E74HP3EE5"},
{"Portfolio Turnover", "43.23%"},
{"Drawdown Recovery", "0"},
{"OrderListHash", "c0fc1bcdc3008a8d263521bbc9d7cdbd"}
};
}
}
@@ -0,0 +1,81 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.Collections.Generic;
using QuantConnect.Algorithm.Framework.Alphas;
using QuantConnect.Algorithm.Framework.Execution;
using QuantConnect.Algorithm.Framework.Portfolio;
using QuantConnect.Algorithm.Framework.Risk;
using QuantConnect.Algorithm.Framework.Selection;
using QuantConnect.Interfaces;
using QuantConnect.Securities;
namespace QuantConnect.Algorithm.CSharp
{
/// <summary>
/// Basic template futures framework algorithm uses framework components to define an algorithm
/// that trades futures.
/// </summary>
public class BasicTemplateFuturesFrameworkWithExtendedMarketAlgorithm : BasicTemplateFuturesFrameworkAlgorithm
{
protected override bool ExtendedMarketHours => true;
/// <summary>
/// This is used by the regression test system to indicate which languages this algorithm is written in.
/// </summary>
public override List<Language> Languages { get; } = new() { Language.CSharp, Language.Python };
/// <summary>
/// Data Points count of all timeslices of algorithm
/// </summary>
public override long DataPoints => 70262;
/// <summary>
/// This is used by the regression test system to indicate what the expected statistics are from running the algorithm
/// </summary>
public override Dictionary<string, string> ExpectedStatistics => new Dictionary<string, string>
{
{"Total Orders", "2"},
{"Average Win", "0%"},
{"Average Loss", "0%"},
{"Compounding Annual Return", "-92.667%"},
{"Drawdown", "5.000%"},
{"Expectancy", "0"},
{"Start Equity", "100000"},
{"End Equity", "96685.76"},
{"Net Profit", "-3.314%"},
{"Sharpe Ratio", "-6.359"},
{"Sortino Ratio", "-11.237"},
{"Probabilistic Sharpe Ratio", "9.257%"},
{"Loss Rate", "0%"},
{"Win Rate", "0%"},
{"Profit-Loss Ratio", "0"},
{"Alpha", "-1.47"},
{"Beta", "0.312"},
{"Annual Standard Deviation", "0.134"},
{"Annual Variance", "0.018"},
{"Information Ratio", "-14.77"},
{"Tracking Error", "0.192"},
{"Treynor Ratio", "-2.742"},
{"Total Fees", "$4.62"},
{"Estimated Strategy Capacity", "$52000000.00"},
{"Lowest Capacity Asset", "GC VL5E74HP3EE5"},
{"Portfolio Turnover", "43.77%"},
{"Drawdown Recovery", "0"},
{"OrderListHash", "dcdaafcefa47465962ace2759ed99c91"}
};
}
}
@@ -0,0 +1,190 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
using System;
using System.Linq;
using QuantConnect.Data;
using QuantConnect.Orders;
using QuantConnect.Securities;
using QuantConnect.Data.UniverseSelection;
using QuantConnect.Interfaces;
using System.Collections.Generic;
namespace QuantConnect.Algorithm.CSharp
{
/// <summary>
/// This example demonstrates how to get access to futures history for a given root symbol.
/// It also shows how you can prefilter contracts easily based on expirations, and inspect the futures
/// chain to pick a specific contract to trade.
/// </summary>
/// <meta name="tag" content="using data" />
/// <meta name="tag" content="history and warm up" />
/// <meta name="tag" content="history" />
/// <meta name="tag" content="futures" />
public class BasicTemplateFuturesHistoryAlgorithm : QCAlgorithm, IRegressionAlgorithmDefinition
{
protected virtual bool ExtendedMarketHours => false;
protected virtual int ExpectedHistoryCallCount => 42;
// S&P 500 EMini futures
private string [] roots = new []
{
Futures.Indices.SP500EMini,
Futures.Metals.Gold,
};
private int _successCount = 0;
public override void Initialize()
{
SetStartDate(2013, 10, 8);
SetEndDate(2013, 10, 9);
SetCash(1000000);
foreach (var root in roots)
{
// set our expiry filter for this futures chain
AddFuture(root, Resolution.Minute, extendedMarketHours: ExtendedMarketHours).SetFilter(TimeSpan.Zero, TimeSpan.FromDays(182));
}
SetBenchmark(d => 1000000);
Schedule.On(DateRules.EveryDay(), TimeRules.Every(TimeSpan.FromHours(1)), MakeHistoryCall);
}
private void MakeHistoryCall()
{
var history = History(10, Resolution.Minute);
if (history.Count() < 10)
{
throw new RegressionTestException($"Empty history at {Time}");
}
_successCount++;
}
public override void OnEndOfAlgorithm()
{
if (_successCount < ExpectedHistoryCallCount)
{
throw new RegressionTestException($"Scheduled Event did not assert history call as many times as expected: {_successCount}/49");
}
}
/// <summary>
/// Event - v3.0 DATA EVENT HANDLER: (Pattern) Basic template for user to override for receiving all subscription data in a single event
/// </summary>
/// <param name="slice">The current slice of data keyed by symbol string</param>
public override void OnData(Slice slice)
{
if (!Portfolio.Invested)
{
foreach (var chain in slice.FutureChains)
{
foreach (var contract in chain.Value)
{
Log($"{contract.Symbol.Value}," +
$"Bid={contract.BidPrice.ToStringInvariant()} " +
$"Ask={contract.AskPrice.ToStringInvariant()} " +
$"Last={contract.LastPrice.ToStringInvariant()} " +
$"OI={contract.OpenInterest.ToStringInvariant()}"
);
}
}
}
}
public override void OnSecuritiesChanged(SecurityChanges changes)
{
foreach (var change in changes.AddedSecurities)
{
var history = History(change.Symbol, 10, Resolution.Minute);
foreach (var data in history.OrderByDescending(x => x.Time).Take(3))
{
Log("History: " + data.Symbol.Value + ": " + data.Time + " > " + data.Close);
}
}
}
/// <summary>
/// Order fill event handler. On an order fill update the resulting information is passed to this method.
/// </summary>
/// <param name="orderEvent">Order event details containing details of the events</param>
/// <remarks>This method can be called asynchronously and so should only be used by seasoned C# experts. Ensure you use proper locks on thread-unsafe objects</remarks>
public override void OnOrderEvent(OrderEvent orderEvent)
{
Log(orderEvent.ToString());
}
/// <summary>
/// This is used by the regression test system to indicate if the open source Lean repository has the required data to run this algorithm.
/// </summary>
public virtual bool CanRunLocally { get; } = true;
/// <summary>
/// This is used by the regression test system to indicate which languages this algorithm is written in.
/// </summary>
public virtual List<Language> Languages { get; } = new() { Language.CSharp, Language.Python };
/// <summary>
/// Data Points count of all timeslices of algorithm
/// </summary>
public virtual long DataPoints => 25316;
/// <summary>
/// Data Points count of the algorithm history
/// </summary>
public virtual int AlgorithmHistoryDataPoints => 6075;
/// <summary>
/// Final status of the algorithm
/// </summary>
public AlgorithmStatus AlgorithmStatus => AlgorithmStatus.Completed;
/// <summary>
/// This is used by the regression test system to indicate what the expected statistics are from running the algorithm
/// </summary>
public virtual Dictionary<string, string> ExpectedStatistics => new Dictionary<string, string>
{
{"Total Orders", "0"},
{"Average Win", "0%"},
{"Average Loss", "0%"},
{"Compounding Annual Return", "0%"},
{"Drawdown", "0%"},
{"Expectancy", "0"},
{"Start Equity", "1000000"},
{"End Equity", "1000000"},
{"Net Profit", "0%"},
{"Sharpe Ratio", "0"},
{"Sortino Ratio", "0"},
{"Probabilistic Sharpe Ratio", "0%"},
{"Loss Rate", "0%"},
{"Win Rate", "0%"},
{"Profit-Loss Ratio", "0"},
{"Alpha", "0"},
{"Beta", "0"},
{"Annual Standard Deviation", "0"},
{"Annual Variance", "0"},
{"Information Ratio", "0"},
{"Tracking Error", "0"},
{"Treynor Ratio", "0"},
{"Total Fees", "$0.00"},
{"Estimated Strategy Capacity", "$0"},
{"Lowest Capacity Asset", ""},
{"Portfolio Turnover", "0%"},
{"Drawdown Recovery", "0"},
{"OrderListHash", "d41d8cd98f00b204e9800998ecf8427e"}
};
}
}

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