Skip to content

Commit c1e4f57

Browse files
committed
Initial open strategy plugins
0 parents  commit c1e4f57

25 files changed

Lines changed: 9714 additions & 0 deletions

.github/workflows/ci.yml

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
name: CI
2+
3+
on:
4+
pull_request:
5+
push:
6+
branches: [main]
7+
8+
jobs:
9+
test:
10+
runs-on: ubuntu-latest
11+
steps:
12+
- uses: actions/checkout@v6
13+
- uses: actions/setup-python@v6
14+
with:
15+
python-version: "3.12"
16+
- name: Install dependencies
17+
run: |
18+
python -m pip install --upgrade pip
19+
python -m pip install -e '.[test]'
20+
- name: Run tests
21+
run: python -m pytest -q
22+
- name: Ruff
23+
run: ruff check .

.gitignore

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
.venv/
2+
__pycache__/
3+
.pytest_cache/
4+
.ruff_cache/
5+
build/
6+
dist/
7+
*.egg-info/
8+
data/output/
9+
*.pyc

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2026 QuantStrategyLab
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

README.md

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
# QuantStrategyPlugins
2+
3+
Open sidecar strategy plugins for QuantStrategyLab runtimes.
4+
5+
The repository emits JSON signal artifacts that are consumed through
6+
`quant_platform_kit.common.strategy_plugins`. Platform repositories such as
7+
Interactive Brokers, Schwab, LongBridge, and Firstrade only load artifacts and
8+
send notifications; plugin research and signal generation live here.
9+
10+
## What Is Public
11+
12+
- Plugin source code and synthetic tests.
13+
- The artifact schema used by platform runtimes.
14+
- Example local TOML config with placeholder paths.
15+
16+
## What Stays Out
17+
18+
- Broker credentials, tokens, account IDs, and SMTP settings.
19+
- GCS bucket names, Cloud Run service names, and production deploy workflows.
20+
- Generated `data/output` artifacts and proprietary runtime configuration.
21+
- Non-public datasets. Tests use synthetic price histories.
22+
23+
## Plugins
24+
25+
- `crisis_response_shadow`: black-swan defense observer for leveraged US equity
26+
strategies. It writes shadow-mode artifacts and never calls brokers.
27+
- `taco_rebound_shadow`: research-only rebound-budget observer. The generic
28+
runner keeps it gated until promotion criteria are met.
29+
30+
## Usage
31+
32+
Run a plugin config:
33+
34+
```bash
35+
qsp-run-strategy-plugins --config docs/examples/strategy_plugins.example.toml
36+
```
37+
38+
Build a crisis response artifact directly from a local price-history CSV:
39+
40+
```bash
41+
qsp-build-crisis-response-shadow-signal \
42+
--prices data/input/price_history.csv \
43+
--as-of 2026-05-22 \
44+
--output-dir data/output/tqqq_growth_income/plugins/crisis_response_shadow
45+
```
46+
47+
Generated artifacts include `latest_signal.json`, dated JSON, dated CSV, and
48+
an evidence CSV. `latest_signal.json` is the file platform runtimes mount via
49+
`*_STRATEGY_PLUGIN_MOUNTS_JSON`.
50+
51+
## Local Checks
52+
53+
```bash
54+
python -m pip install -e '.[test]'
55+
python -m pytest -q
56+
ruff check .
57+
```
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
output_dir = "data/output/strategy_plugins"
2+
default_mode = "shadow"
3+
4+
[[strategy_plugins]]
5+
strategy = "tqqq_growth_income"
6+
plugin = "crisis_response_shadow"
7+
enabled = true
8+
# The runner enforces plugin/strategy compatibility. This plugin is scoped to
9+
# TQQQ/SOXL leveraged equity black-swan defense strategies.
10+
# mode is optional when it matches default_mode; only shadow notification mode is supported.
11+
12+
[strategy_plugins.inputs]
13+
prices = "data/output/crisis_response_shadow/input/price_history.csv"
14+
external_context = "data/output/crisis_response_shadow/input/external_context.csv"
15+
event_set = "full"
16+
financial_symbols = ["XLF", "KRE"]
17+
credit_pairs = ["HYG:IEF", "LQD:IEF"]
18+
rate_symbols = ["IEF", "TLT"]
19+
20+
[strategy_plugins.outputs]
21+
output_dir = "data/output/tqqq_growth_income/plugins/crisis_response_shadow"

pyproject.toml

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
[build-system]
2+
requires = ["setuptools>=69", "wheel"]
3+
build-backend = "setuptools.build_meta"
4+
5+
[project]
6+
name = "quant-strategy-plugins"
7+
version = "0.1.0"
8+
description = "Open sidecar strategy plugins that emit QuantPlatformKit-compatible signal artifacts."
9+
readme = "README.md"
10+
requires-python = ">=3.11"
11+
license = { text = "MIT" }
12+
authors = [
13+
{ name = "QuantStrategyLab" }
14+
]
15+
dependencies = [
16+
"pandas>=2.0",
17+
"yfinance>=0.2.40",
18+
]
19+
20+
[project.optional-dependencies]
21+
test = ["pytest>=8", "ruff>=0.8"]
22+
23+
[project.scripts]
24+
qsp-build-crisis-response-shadow-signal = "quant_strategy_plugins.crisis_response_shadow_plugin:main"
25+
qsp-build-taco-rebound-shadow-signal = "quant_strategy_plugins.taco_rebound_shadow_plugin:main"
26+
qsp-run-strategy-plugins = "quant_strategy_plugins.strategy_plugin_runner:main"
27+
28+
[tool.setuptools]
29+
package-dir = {"" = "src"}
30+
31+
[tool.setuptools.packages.find]
32+
where = ["src"]
33+
34+
[tool.pytest.ini_options]
35+
testpaths = ["tests"]
36+
37+
[tool.ruff]
38+
target-version = "py311"
39+
line-length = 120
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
from __future__ import annotations
2+
3+
from quant_strategy_plugins.crisis_response_shadow_plugin import main
4+
5+
if __name__ == "__main__":
6+
raise SystemExit(main())

scripts/run_strategy_plugins.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
from __future__ import annotations
2+
3+
from quant_strategy_plugins.strategy_plugin_runner import main
4+
5+
if __name__ == "__main__":
6+
raise SystemExit(main())
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
"""Open strategy plugin implementations for QuantStrategyLab runtimes."""
2+
3+
from .crisis_response_shadow_plugin import (
4+
SCHEMA_VERSION as CRISIS_RESPONSE_SHADOW_SCHEMA_VERSION,
5+
SHADOW_PROFILE as CRISIS_RESPONSE_SHADOW_PROFILE,
6+
build_crisis_response_shadow_signal,
7+
write_crisis_response_shadow_outputs,
8+
)
9+
from .strategy_plugin_runner import run_configured_plugins
10+
from .taco_rebound_shadow_plugin import (
11+
SCHEMA_VERSION as TACO_REBOUND_SHADOW_SCHEMA_VERSION,
12+
TACO_REBOUND_PROFILE,
13+
build_taco_rebound_shadow_signal,
14+
write_taco_rebound_shadow_outputs,
15+
)
16+
17+
__all__ = [
18+
"CRISIS_RESPONSE_SHADOW_PROFILE",
19+
"CRISIS_RESPONSE_SHADOW_SCHEMA_VERSION",
20+
"TACO_REBOUND_PROFILE",
21+
"TACO_REBOUND_SHADOW_SCHEMA_VERSION",
22+
"build_crisis_response_shadow_signal",
23+
"build_taco_rebound_shadow_signal",
24+
"run_configured_plugins",
25+
"write_crisis_response_shadow_outputs",
26+
"write_taco_rebound_shadow_outputs",
27+
]
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
from __future__ import annotations
2+
3+
import hashlib
4+
import json
5+
from pathlib import Path
6+
from typing import Any, Mapping
7+
8+
9+
def sha256_file(path: str | Path) -> str:
10+
hasher = hashlib.sha256()
11+
with Path(path).open("rb") as fh:
12+
while True:
13+
chunk = fh.read(1024 * 1024)
14+
if not chunk:
15+
break
16+
hasher.update(chunk)
17+
return hasher.hexdigest()
18+
19+
20+
def write_json(path: str | Path, payload: Mapping[str, Any]) -> Path:
21+
resolved = Path(path)
22+
resolved.parent.mkdir(parents=True, exist_ok=True)
23+
resolved.write_text(
24+
json.dumps(payload, ensure_ascii=False, indent=2, sort_keys=True),
25+
encoding="utf-8",
26+
)
27+
return resolved

0 commit comments

Comments
 (0)