Skip to content

Commit 4243b7b

Browse files
committed
Implement Dataset
1 parent 1dee596 commit 4243b7b

File tree

94 files changed

+3381
-1295
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

94 files changed

+3381
-1295
lines changed

.github/actions/setup/action.yml

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
name: Setup
2+
description: Liberate disk space, checkout Lean, pull foundation image, define docker helper
3+
4+
runs:
5+
using: composite
6+
steps:
7+
- name: Liberate disk space
8+
uses: jlumbroso/free-disk-space@main
9+
with:
10+
tool-cache: true
11+
large-packages: false
12+
docker-images: false
13+
swap-storage: false
14+
15+
- name: Check if Lean has same branch
16+
id: lean-branch-check
17+
run: |
18+
branch="${{ github.head_ref || github.ref_name }}"
19+
if git ls-remote --exit-code --heads https://github.com/QuantConnect/Lean.git "$branch" > /dev/null 2>&1; then
20+
echo "exists=true" >> $GITHUB_OUTPUT
21+
echo "branch=$branch" >> $GITHUB_OUTPUT
22+
else
23+
echo "exists=false" >> $GITHUB_OUTPUT
24+
fi
25+
shell: bash
26+
27+
- name: Checkout Lean Same Branch
28+
if: steps.lean-branch-check.outputs.exists == 'true'
29+
uses: actions/checkout@v5
30+
with:
31+
ref: ${{ steps.lean-branch-check.outputs.branch }}
32+
repository: QuantConnect/Lean
33+
path: Lean
34+
35+
- name: Checkout Lean Master
36+
if: steps.lean-branch-check.outputs.exists != 'true'
37+
uses: actions/checkout@v5
38+
with:
39+
repository: QuantConnect/Lean
40+
path: Lean
41+
42+
- name: Move Lean
43+
run: mv Lean ../Lean
44+
shell: bash
45+
46+
- name: Pull foundation image
47+
run: docker pull quantconnect/lean:foundation
48+
shell: bash
49+
50+
- name: Define docker helper
51+
run: |
52+
echo 'runInContainer() { docker exec test-container "$@"; }' > $HOME/ci_functions.sh
53+
echo "BASH_ENV=$HOME/ci_functions.sh" >> $GITHUB_ENV
54+
shell: bash

.github/workflows/build.yml

Lines changed: 45 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -8,36 +8,56 @@ on:
88

99
jobs:
1010
build:
11-
runs-on: ubuntu-20.04
12-
container:
13-
image: quantconnect/lean:foundation
11+
runs-on: ubuntu-24.04
1412
steps:
15-
- uses: actions/checkout@v2
13+
- name: Checkout
14+
uses: actions/checkout@v5
1615

17-
- name: Checkout Lean Same Branch
18-
id: lean-same-branch
19-
uses: actions/checkout@v2
20-
continue-on-error: true
21-
with:
22-
ref: ${{ github.ref }}
23-
repository: QuantConnect/Lean
24-
path: Lean
16+
- name: Setup
17+
uses: ./.github/actions/setup
2518

26-
- name: Checkout Lean Master
27-
if: steps.lean-same-branch.outcome != 'success'
28-
uses: actions/checkout@v2
29-
with:
30-
repository: QuantConnect/Lean
31-
path: Lean
19+
- name: Copy sample data to LEAN Data folder
20+
run: cp -r ../Lean.DataSource.BLS/output/* ../Lean/Data/
3221

33-
- name: Move Lean
34-
run: mv Lean ../Lean
22+
- name: Start container
23+
run: |
24+
docker run -d \
25+
--workdir /__w/Lean.DataSource.BLS/Lean.DataSource.BLS \
26+
-v /home/runner/work:/__w \
27+
--name test-container \
28+
quantconnect/lean:foundation \
29+
tail -f /dev/null
3530
36-
- name: BuildDataSource
37-
run: dotnet build ./QuantConnect.DataSource.csproj /p:Configuration=Release /v:quiet /p:WarningLevel=1
31+
- name: Build DataSource
32+
run: runInContainer dotnet build ./QuantConnect.DataSource.csproj /p:Configuration=Release /v:quiet /p:WarningLevel=1
3833

39-
- name: BuildTests
40-
run: dotnet build ./tests/Tests.csproj /p:Configuration=Release /v:quiet /p:WarningLevel=1
34+
- name: Build Tests
35+
run: runInContainer dotnet build ./tests/Tests.csproj /p:Configuration=Release /v:quiet /p:WarningLevel=1
4136

4237
- name: Run Tests
43-
run: dotnet test ./tests/bin/Release/net6.0/Tests.dll
38+
run: runInContainer dotnet test ./tests/bin/Release/net10.0/Tests.dll
39+
40+
- name: Build LEAN Launcher
41+
run: runInContainer dotnet build ../Lean/Launcher/QuantConnect.Lean.Launcher.csproj /p:Configuration=Release /p:OutputPath=bin/Release /v:quiet /p:WarningLevel=1
42+
43+
- name: Copy DataSource to LEAN Launcher
44+
run: runInContainer cp ./tests/bin/Release/net10.0/QuantConnect.DataSource.BLS.dll ../Lean/Launcher/bin/Release/
45+
46+
- name: Run C# Demo Algorithm
47+
run: |
48+
output=$(runInContainer bash -c "cd ../Lean/Launcher/bin/Release && dotnet ./QuantConnect.Lean.Launcher.dll --data-folder /__w/Lean.DataSource.BLS/Lean/Data/ --algorithm-language CSharp --algorithm-type-name BLSEconomicSurveysAlgorithm --algorithm-location /__w/Lean.DataSource.BLS/Lean.DataSource.BLS/tests/bin/Release/net10.0/Tests.dll --close-automatically true" 2>&1)
49+
echo "$output"
50+
echo "$output" | grep -q "STATISTICS:: Total Orders [^0]" || { echo "Algorithm placed no trades"; exit 1; }
51+
52+
- name: Run Python Demo Algorithm
53+
run: |
54+
output=$(runInContainer bash -c 'cd ../Lean/Launcher/bin/Release && dotnet ./QuantConnect.Lean.Launcher.dll --data-folder /__w/Lean.DataSource.BLS/Lean/Data/ --algorithm-language Python --algorithm-type-name BLSEconomicSurveysAlgorithm --algorithm-location /__w/Lean.DataSource.BLS/Lean.DataSource.BLS/BLSEconomicSurveysAlgorithm.py --close-automatically true' 2>&1) || true
55+
echo "$output"
56+
echo "$output" | grep -q "STATISTICS:: Total Orders [^0]" || { echo "Algorithm placed no trades"; exit 1; }
57+
58+
- name: Stop container
59+
run: docker rm -f test-container
60+
61+
rename:
62+
needs: build
63+
uses: ./.github/workflows/rename-build.yml

.github/workflows/rename-build.yml

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
name: Rename & Test
2+
3+
on:
4+
workflow_call:
5+
6+
jobs:
7+
rename-build:
8+
if: github.repository == 'QuantConnect/Lean.DataSource.SDK'
9+
runs-on: ubuntu-24.04
10+
steps:
11+
- name: Checkout
12+
uses: actions/checkout@v5
13+
14+
- name: Setup
15+
uses: ./.github/actions/setup
16+
17+
- name: Rename Dataset
18+
run: |
19+
cp -r . ../Lean.DataSource.RenameDataset
20+
cd ../Lean.DataSource.RenameDataset
21+
python renameDataset.py Rename Dataset
22+
23+
- name: Start container (renamed)
24+
run: |
25+
docker run -d \
26+
--workdir /__w/Lean.DataSource.SDK/Lean.DataSource.RenameDataset \
27+
-v /home/runner/work:/__w \
28+
--name test-container \
29+
quantconnect/lean:foundation \
30+
tail -f /dev/null
31+
32+
- name: Build Renamed DataSource
33+
run: runInContainer dotnet build ./QuantConnect.DataSource.csproj /p:Configuration=Release /v:quiet /p:WarningLevel=1
34+
35+
- name: Build Renamed Tests
36+
run: runInContainer dotnet build ./tests/Tests.csproj /p:Configuration=Release /v:quiet /p:WarningLevel=1
37+
38+
- name: Run Renamed Tests
39+
run: runInContainer dotnet test ./tests/bin/Release/net10.0/Tests.dll

.vscode/settings.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"files.autoSave": "afterDelay"
3+
}

BLSEconomicSurveysAlgorithm.cs

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
/*
2+
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
3+
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software
10+
* distributed under the License is distributed on an "AS IS" BASIS,
11+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
* See the License for the specific language governing permissions and
13+
* limitations under the License.
14+
*/
15+
16+
using QuantConnect.Data;
17+
using QuantConnect.DataSource;
18+
19+
namespace QuantConnect.Algorithm.CSharp
20+
{
21+
/// <summary>
22+
/// Demonstration algorithm showing how to use BLS Economic Surveys custom datasets
23+
/// (CPI, CES, PPI, JOLTS) for signal generation and trading.
24+
/// </summary>
25+
public class BLSEconomicSurveysAlgorithm : QCAlgorithm
26+
{
27+
private Symbol _cpiSymbol;
28+
private Symbol _cesSymbol;
29+
private Symbol _ppiSymbol;
30+
private Symbol _spySymbol;
31+
32+
/// <summary>
33+
/// Initializes the algorithm with custom data subscriptions.
34+
/// </summary>
35+
public override void Initialize()
36+
{
37+
SetStartDate(2000, 1, 1);
38+
SetEndDate(2002, 6, 1);
39+
SetCash(100000);
40+
41+
// Add a tradeable equity for order execution
42+
_spySymbol = AddEquity("SPY", Resolution.Daily).Symbol;
43+
44+
// Subscribe to BLS economic surveys (unlinked custom data)
45+
_cpiSymbol = AddData<BLSEconomicSurveysCpi>("CPI", Resolution.Daily).Symbol;
46+
_cesSymbol = AddData<BLSEconomicSurveysCes>("CES", Resolution.Daily).Symbol;
47+
_ppiSymbol = AddData<BLSEconomicSurveysPpi>("PPI", Resolution.Daily).Symbol;
48+
}
49+
50+
/// <summary>
51+
/// Handles data events. Uses CPI and employment data to generate trading signals.
52+
/// </summary>
53+
/// <param name="slice">The current data slice</param>
54+
public override void OnData(Slice slice)
55+
{
56+
// Check for CPI data
57+
if (slice.ContainsKey(_cpiSymbol))
58+
{
59+
var cpi = slice.Get<BLSEconomicSurveysCpi>(_cpiSymbol);
60+
Log($"{Time} - CPI AllItems: {cpi.AllItems}, CoreCpi: {cpi.CoreCpi}, Energy: {cpi.Energy}");
61+
62+
// Simple signal: if energy CPI is rising faster than core, reduce equity exposure
63+
if (cpi.Energy.HasValue && cpi.CoreCpi.HasValue && cpi.Energy > cpi.CoreCpi * 1.5m)
64+
{
65+
if (Portfolio[_spySymbol].Invested)
66+
{
67+
SetHoldings(_spySymbol, 0.5);
68+
}
69+
}
70+
}
71+
72+
// Check for employment data
73+
if (slice.ContainsKey(_cesSymbol))
74+
{
75+
var ces = slice.Get<BLSEconomicSurveysCes>(_cesSymbol);
76+
Log($"{Time} - CES TotalNonfarm: {ces.TotalNonfarm}, AvgHourlyEarnings: {ces.AverageHourlyEarnings}");
77+
78+
// Simple signal: go long when nonfarm payrolls are strong
79+
if (ces.TotalNonfarm.HasValue && ces.TotalNonfarm > 130000m && !Portfolio[_spySymbol].Invested)
80+
{
81+
SetHoldings(_spySymbol, 1);
82+
}
83+
}
84+
85+
// Check for PPI data
86+
if (slice.ContainsKey(_ppiSymbol))
87+
{
88+
var ppi = slice.Get<BLSEconomicSurveysPpi>(_ppiSymbol);
89+
Log($"{Time} - PPI AllCommodities: {ppi.AllCommodities}, FarmProducts: {ppi.FarmProducts}");
90+
}
91+
}
92+
}
93+
}

BLSEconomicSurveysAlgorithm.py

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
# region imports
2+
from AlgorithmImports import *
3+
from QuantConnect.DataSource import *
4+
# endregion
5+
6+
7+
class BLSEconomicSurveysAlgorithm(QCAlgorithm):
8+
"""
9+
Demonstration algorithm showing how to use BLS Economic Surveys custom datasets
10+
(CPI, CES, PPI, JOLTS) for signal generation and trading.
11+
"""
12+
13+
def initialize(self):
14+
self.set_start_date(2000, 1, 1)
15+
self.set_end_date(2002, 6, 1)
16+
self.set_cash(100000)
17+
18+
# Add a tradeable equity for order execution
19+
self._spy_symbol = self.add_equity("SPY", Resolution.DAILY).symbol
20+
21+
# Subscribe to BLS economic surveys (unlinked custom data)
22+
self._cpi_symbol = self.add_data(BLSEconomicSurveysCpi, "CPI", Resolution.DAILY).symbol
23+
self._ces_symbol = self.add_data(BLSEconomicSurveysCes, "CES", Resolution.DAILY).symbol
24+
self._ppi_symbol = self.add_data(BLSEconomicSurveysPpi, "PPI", Resolution.DAILY).symbol
25+
26+
def on_data(self, slice: Slice):
27+
# Check for CPI data
28+
if slice.contains_key(self._cpi_symbol):
29+
cpi = slice.get(BLSEconomicSurveysCpi, self._cpi_symbol)
30+
self.log(f"{self.time} - CPI AllItems: {cpi.all_items}, CoreCpi: {cpi.core_cpi}, Energy: {cpi.energy}")
31+
32+
# Simple signal: if energy CPI is rising faster than core, reduce equity exposure
33+
if cpi.energy is not None and cpi.core_cpi is not None and cpi.energy > cpi.core_cpi * 1.5:
34+
if self.portfolio[self._spy_symbol].invested:
35+
self.set_holdings(self._spy_symbol, 0.5)
36+
37+
# Check for employment data
38+
if slice.contains_key(self._ces_symbol):
39+
ces = slice.get(BLSEconomicSurveysCes, self._ces_symbol)
40+
self.log(f"{self.time} - CES TotalNonfarm: {ces.total_nonfarm}, AvgHourlyEarnings: {ces.average_hourly_earnings}")
41+
42+
# Simple signal: go long when nonfarm payrolls are strong
43+
if ces.total_nonfarm is not None and ces.total_nonfarm > 130000 and not self.portfolio[self._spy_symbol].invested:
44+
self.set_holdings(self._spy_symbol, 1)
45+
46+
# Check for PPI data
47+
if slice.contains_key(self._ppi_symbol):
48+
ppi = slice.get(BLSEconomicSurveysPpi, self._ppi_symbol)
49+
self.log(f"{self.time} - PPI AllCommodities: {ppi.all_commodities}, FarmProducts: {ppi.farm_products}")

0 commit comments

Comments
 (0)