stacksats 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- stacksats-0.1.0/LICENSE +21 -0
- stacksats-0.1.0/PKG-INFO +318 -0
- stacksats-0.1.0/README.md +269 -0
- stacksats-0.1.0/pyproject.toml +74 -0
- stacksats-0.1.0/setup.cfg +4 -0
- stacksats-0.1.0/stacksats/__init__.py +21 -0
- stacksats-0.1.0/stacksats/api.py +373 -0
- stacksats-0.1.0/stacksats/backtest.py +430 -0
- stacksats-0.1.0/stacksats/btc_api/__init__.py +1 -0
- stacksats-0.1.0/stacksats/btc_api/bitstamp_btc_usd.py +10 -0
- stacksats-0.1.0/stacksats/btc_api/coinbase_btc_usd.py +10 -0
- stacksats-0.1.0/stacksats/btc_api/coingecko_btc_usd.py +10 -0
- stacksats-0.1.0/stacksats/btc_api/coinmetrics_btc_csv.py +128 -0
- stacksats-0.1.0/stacksats/btc_api/kraken_xbt_usd.py +12 -0
- stacksats-0.1.0/stacksats/btc_price_fetcher.py +484 -0
- stacksats-0.1.0/stacksats/export_weights.py +748 -0
- stacksats-0.1.0/stacksats/loader.py +60 -0
- stacksats-0.1.0/stacksats/matplotlib_setup.py +54 -0
- stacksats-0.1.0/stacksats/modal_app.py +529 -0
- stacksats-0.1.0/stacksats/model_development.py +822 -0
- stacksats-0.1.0/stacksats/plot_mvrv.py +376 -0
- stacksats-0.1.0/stacksats/plot_weights.py +502 -0
- stacksats-0.1.0/stacksats/prelude.py +561 -0
- stacksats-0.1.0/stacksats/py.typed +1 -0
- stacksats-0.1.0/stacksats/strategies/__init__.py +14 -0
- stacksats-0.1.0/stacksats/strategies/base.py +37 -0
- stacksats-0.1.0/stacksats/strategies/examples.py +73 -0
- stacksats-0.1.0/stacksats/strategies/mvrv.py +20 -0
- stacksats-0.1.0/stacksats.egg-info/PKG-INFO +318 -0
- stacksats-0.1.0/stacksats.egg-info/SOURCES.txt +77 -0
- stacksats-0.1.0/stacksats.egg-info/dependency_links.txt +1 -0
- stacksats-0.1.0/stacksats.egg-info/entry_points.txt +6 -0
- stacksats-0.1.0/stacksats.egg-info/requires.txt +27 -0
- stacksats-0.1.0/stacksats.egg-info/top_level.txt +1 -0
- stacksats-0.1.0/tests/test_api_enhancements.py +226 -0
- stacksats-0.1.0/tests/test_backtest_errors.py +200 -0
- stacksats-0.1.0/tests/test_backtest_export_parity.py +690 -0
- stacksats-0.1.0/tests/test_backtest_performance.py +296 -0
- stacksats-0.1.0/tests/test_bdd_backtest.py +13 -0
- stacksats-0.1.0/tests/test_bdd_consistency.py +13 -0
- stacksats-0.1.0/tests/test_bdd_data_integrity.py +13 -0
- stacksats-0.1.0/tests/test_bdd_database_operations.py +13 -0
- stacksats-0.1.0/tests/test_bdd_date_ranges.py +13 -0
- stacksats-0.1.0/tests/test_bdd_edge_cases.py +13 -0
- stacksats-0.1.0/tests/test_bdd_export_weights.py +13 -0
- stacksats-0.1.0/tests/test_bdd_forward_looking.py +13 -0
- stacksats-0.1.0/tests/test_bdd_golden_snapshots.py +13 -0
- stacksats-0.1.0/tests/test_bdd_model_development.py +13 -0
- stacksats-0.1.0/tests/test_bdd_weight_computation.py +13 -0
- stacksats-0.1.0/tests/test_bdd_weight_constraints.py +13 -0
- stacksats-0.1.0/tests/test_bdd_weight_stability.py +14 -0
- stacksats-0.1.0/tests/test_btc_price_fetcher.py +688 -0
- stacksats-0.1.0/tests/test_btc_price_fetcher_historical.py +219 -0
- stacksats-0.1.0/tests/test_coinmetrics_btc_csv.py +155 -0
- stacksats-0.1.0/tests/test_cross_validation.py +565 -0
- stacksats-0.1.0/tests/test_debug_multiplier.py +212 -0
- stacksats-0.1.0/tests/test_debug_weights.py +164 -0
- stacksats-0.1.0/tests/test_export_weights_database.py +145 -0
- stacksats-0.1.0/tests/test_export_weights_detailed.py +183 -0
- stacksats-0.1.0/tests/test_helpers.py +24 -0
- stacksats-0.1.0/tests/test_main.py +407 -0
- stacksats-0.1.0/tests/test_market_regimes.py +701 -0
- stacksats-0.1.0/tests/test_modal_app.py +112 -0
- stacksats-0.1.0/tests/test_model_development_helpers.py +86 -0
- stacksats-0.1.0/tests/test_model_edge_cases.py +129 -0
- stacksats-0.1.0/tests/test_monte_carlo.py +647 -0
- stacksats-0.1.0/tests/test_package_api.py +68 -0
- stacksats-0.1.0/tests/test_performance_benchmarks.py +478 -0
- stacksats-0.1.0/tests/test_plotting.py +71 -0
- stacksats-0.1.0/tests/test_prelude_cache.py +72 -0
- stacksats-0.1.0/tests/test_prelude_gap_filling.py +102 -0
- stacksats-0.1.0/tests/test_prelude_mvrv_fallback.py +412 -0
- stacksats-0.1.0/tests/test_price_validation.py +44 -0
- stacksats-0.1.0/tests/test_property_based.py +339 -0
- stacksats-0.1.0/tests/test_sensitivity_analysis.py +396 -0
- stacksats-0.1.0/tests/test_simulation.py +748 -0
- stacksats-0.1.0/tests/test_statistical_validation.py +484 -0
- stacksats-0.1.0/tests/test_visualization.py +337 -0
- stacksats-0.1.0/tests/test_weight_stability.py +415 -0
stacksats-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Hypertrial
|
|
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.
|
stacksats-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,318 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: stacksats
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Bitcoin DCA model development, backtesting, and Modal deployment toolkit
|
|
5
|
+
Author: StackSats Contributors
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/stacksats/stacksats
|
|
8
|
+
Project-URL: Repository, https://github.com/stacksats/stacksats
|
|
9
|
+
Project-URL: Documentation, https://github.com/stacksats/stacksats/tree/main/docs
|
|
10
|
+
Keywords: bitcoin,dca,backtesting,quant,crypto
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: Intended Audience :: Financial and Insurance Industry
|
|
13
|
+
Classifier: Intended Audience :: Science/Research
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Topic :: Office/Business :: Financial :: Investment
|
|
19
|
+
Classifier: Topic :: Scientific/Engineering :: Information Analysis
|
|
20
|
+
Requires-Python: >=3.11
|
|
21
|
+
Description-Content-Type: text/markdown
|
|
22
|
+
License-File: LICENSE
|
|
23
|
+
Requires-Dist: pandas>=2.0.0
|
|
24
|
+
Requires-Dist: numpy>=1.24.0
|
|
25
|
+
Requires-Dist: scipy>=1.11.0
|
|
26
|
+
Requires-Dist: requests>=2.31.0
|
|
27
|
+
Requires-Dist: matplotlib>=3.7.0
|
|
28
|
+
Requires-Dist: seaborn>=0.12.0
|
|
29
|
+
Provides-Extra: deploy
|
|
30
|
+
Requires-Dist: modal>=0.52.0; extra == "deploy"
|
|
31
|
+
Requires-Dist: psycopg2-binary>=2.9.0; extra == "deploy"
|
|
32
|
+
Requires-Dist: fastapi>=0.104.0; extra == "deploy"
|
|
33
|
+
Requires-Dist: python-dotenv>=1.0.0; extra == "deploy"
|
|
34
|
+
Requires-Dist: tenacity>=8.2.0; extra == "deploy"
|
|
35
|
+
Requires-Dist: pyarrow>=13.0.0; extra == "deploy"
|
|
36
|
+
Provides-Extra: dev
|
|
37
|
+
Requires-Dist: pytest>=7.0.0; extra == "dev"
|
|
38
|
+
Requires-Dist: pytest-bdd>=7.0.0; extra == "dev"
|
|
39
|
+
Requires-Dist: pytest-cov>=4.0.0; extra == "dev"
|
|
40
|
+
Requires-Dist: pytest-mock>=3.10.0; extra == "dev"
|
|
41
|
+
Requires-Dist: pytest-benchmark>=4.0.0; extra == "dev"
|
|
42
|
+
Requires-Dist: pytest-xdist>=3.0.0; extra == "dev"
|
|
43
|
+
Requires-Dist: responses>=0.23.0; extra == "dev"
|
|
44
|
+
Requires-Dist: freezegun>=1.2.0; extra == "dev"
|
|
45
|
+
Requires-Dist: hypothesis>=6.0.0; extra == "dev"
|
|
46
|
+
Requires-Dist: ruff>=0.1.0; extra == "dev"
|
|
47
|
+
Requires-Dist: vulture; extra == "dev"
|
|
48
|
+
Dynamic: license-file
|
|
49
|
+
|
|
50
|
+
# StackSats
|
|
51
|
+
|
|
52
|
+
StackSats, developed by [Hypertrial](https://www.hypertrail.ai), is a Python package for developing and backtesting Bitcoin DCA ("stacking sats") allocation strategies.
|
|
53
|
+
|
|
54
|
+
Learn more at [www.stackingsats.org](https://www.stackingsats.org)
|
|
55
|
+
|
|
56
|
+
It provides:
|
|
57
|
+
- A clean strategy interface (`WindowStrategy`)
|
|
58
|
+
- Built-in and example strategies
|
|
59
|
+
- A rolling-window backtest engine
|
|
60
|
+
- Feature precomputation utilities
|
|
61
|
+
- Validation checks for leakage, constraints, and win-rate
|
|
62
|
+
|
|
63
|
+
## Installation
|
|
64
|
+
|
|
65
|
+
Install core package for local model development:
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
pip install stacksats
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
For local development from source:
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
pip install -e .
|
|
75
|
+
pip install -r requirements-dev.txt
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Install deployment dependencies only if needed:
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
pip install "stacksats[deploy]"
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## Quick Start (write your own strategy file)
|
|
85
|
+
|
|
86
|
+
Create `my_strategy.py`:
|
|
87
|
+
|
|
88
|
+
```python
|
|
89
|
+
import numpy as np
|
|
90
|
+
import pandas as pd
|
|
91
|
+
|
|
92
|
+
from stacksats import run_backtest, validate_strategy
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
class MyStrategy:
|
|
96
|
+
def compute_weights(
|
|
97
|
+
self,
|
|
98
|
+
features_df: pd.DataFrame,
|
|
99
|
+
start_date: pd.Timestamp,
|
|
100
|
+
end_date: pd.Timestamp,
|
|
101
|
+
current_date: pd.Timestamp,
|
|
102
|
+
) -> pd.Series:
|
|
103
|
+
del current_date
|
|
104
|
+
window = features_df.loc[start_date:end_date]
|
|
105
|
+
if window.empty:
|
|
106
|
+
return pd.Series(dtype=float)
|
|
107
|
+
|
|
108
|
+
z = window.get("mvrv_zscore", pd.Series(0.0, index=window.index)).to_numpy()
|
|
109
|
+
ma = window.get("price_vs_ma", pd.Series(0.0, index=window.index)).to_numpy()
|
|
110
|
+
raw = np.exp((-1.2 * z) + (-0.8 * ma))
|
|
111
|
+
w = raw / raw.sum()
|
|
112
|
+
return pd.Series(w, index=window.index)
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
if __name__ == "__main__":
|
|
116
|
+
strategy = MyStrategy()
|
|
117
|
+
|
|
118
|
+
validation = validate_strategy(strategy)
|
|
119
|
+
print(validation.summary())
|
|
120
|
+
|
|
121
|
+
result = run_backtest(strategy, strategy_label="my-strategy")
|
|
122
|
+
print(result.summary())
|
|
123
|
+
result.plot(output_dir="output")
|
|
124
|
+
result.to_json("output/backtest_result.json")
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
Run it directly:
|
|
128
|
+
|
|
129
|
+
```bash
|
|
130
|
+
python my_strategy.py
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
For a complete command reference using the included example file, see
|
|
134
|
+
[`docs/commands.md`](docs/commands.md).
|
|
135
|
+
|
|
136
|
+
## Public API
|
|
137
|
+
|
|
138
|
+
Top-level package exports:
|
|
139
|
+
|
|
140
|
+
- `run_backtest()`: Run a rolling-window backtest for any strategy
|
|
141
|
+
- `validate_strategy()`: Run submission-style validation checks
|
|
142
|
+
- `load_data()`: Load BTC market data (with local cache support)
|
|
143
|
+
- `precompute_features()`: Build model features from BTC data
|
|
144
|
+
- `load_strategy()`: Load a strategy from `module_or_path:ClassName`
|
|
145
|
+
- `BacktestResult`: Result object with summary/plot/serialization helpers
|
|
146
|
+
- `ValidationResult`: Structured validation output
|
|
147
|
+
- `WindowStrategy`, `CallableWindowStrategy`, `MVRVStrategy`
|
|
148
|
+
|
|
149
|
+
`load_data()` also supports cache controls via optional keyword args:
|
|
150
|
+
- `cache_dir` (default `~/.stacksats/cache`, set to `None` to disable local cache)
|
|
151
|
+
- `max_age_hours` (default `24`, refresh threshold for cached CoinMetrics CSV)
|
|
152
|
+
|
|
153
|
+
## Writing a Strategy
|
|
154
|
+
|
|
155
|
+
Implement `compute_weights()` with this interface:
|
|
156
|
+
|
|
157
|
+
```python
|
|
158
|
+
def compute_weights(
|
|
159
|
+
self,
|
|
160
|
+
features_df: pd.DataFrame,
|
|
161
|
+
start_date: pd.Timestamp,
|
|
162
|
+
end_date: pd.Timestamp,
|
|
163
|
+
current_date: pd.Timestamp,
|
|
164
|
+
) -> pd.Series:
|
|
165
|
+
...
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
Rules your strategy should satisfy:
|
|
169
|
+
|
|
170
|
+
- Return a weight series indexed by dates in the selected window
|
|
171
|
+
- Weights should be non-negative
|
|
172
|
+
- Weights should sum to `1.0`
|
|
173
|
+
- Avoid forward-looking data usage
|
|
174
|
+
|
|
175
|
+
### Available Features
|
|
176
|
+
|
|
177
|
+
Feature columns are generated by `precompute_features()` and typically include:
|
|
178
|
+
|
|
179
|
+
- `PriceUSD_coinmetrics`
|
|
180
|
+
- `price_ma`
|
|
181
|
+
- `price_vs_ma`
|
|
182
|
+
- `mvrv_zscore`
|
|
183
|
+
- `mvrv_gradient`
|
|
184
|
+
- `mvrv_percentile`
|
|
185
|
+
- `mvrv_acceleration`
|
|
186
|
+
- `mvrv_zone`
|
|
187
|
+
- `mvrv_volatility`
|
|
188
|
+
- `signal_confidence`
|
|
189
|
+
|
|
190
|
+
## Built-in and Example Strategies
|
|
191
|
+
|
|
192
|
+
### Built-in
|
|
193
|
+
|
|
194
|
+
- `MVRVStrategy`: Default strategy from the package model.
|
|
195
|
+
|
|
196
|
+
### Examples
|
|
197
|
+
|
|
198
|
+
In `stacksats.strategies.examples`:
|
|
199
|
+
|
|
200
|
+
- `UniformStrategy`
|
|
201
|
+
- `SimpleZScoreStrategy`
|
|
202
|
+
- `MomentumStrategy`
|
|
203
|
+
|
|
204
|
+
These are lightweight templates for custom model development.
|
|
205
|
+
|
|
206
|
+
## Backtesting
|
|
207
|
+
|
|
208
|
+
Run the default built-in strategy:
|
|
209
|
+
|
|
210
|
+
```bash
|
|
211
|
+
stacksats-backtest
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
Run a custom strategy class from a file:
|
|
215
|
+
|
|
216
|
+
```bash
|
|
217
|
+
stacksats-backtest --strategy my_strategy.py:MyStrategy --start-date 2020-01-01 --end-date 2025-01-01
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
Use the Python API directly:
|
|
221
|
+
|
|
222
|
+
```python
|
|
223
|
+
from stacksats import MVRVStrategy, run_backtest
|
|
224
|
+
|
|
225
|
+
result = run_backtest(MVRVStrategy(), strategy_label="default-mvrv")
|
|
226
|
+
print(result.summary())
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
## Validation
|
|
230
|
+
|
|
231
|
+
Validate built-in strategy:
|
|
232
|
+
|
|
233
|
+
```bash
|
|
234
|
+
stacksats-validate --start-date 2020-01-01 --end-date 2025-01-01
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
Validate a custom strategy class:
|
|
238
|
+
|
|
239
|
+
```bash
|
|
240
|
+
stacksats-validate --strategy my_strategy.py:MyStrategy --min-win-rate 50.0
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
## Command Line Tools
|
|
244
|
+
|
|
245
|
+
Installed scripts:
|
|
246
|
+
|
|
247
|
+
- `stacksats-backtest`
|
|
248
|
+
- `stacksats-export`
|
|
249
|
+
- `stacksats-plot-mvrv`
|
|
250
|
+
- `stacksats-plot-weights`
|
|
251
|
+
- `stacksats-validate`
|
|
252
|
+
|
|
253
|
+
Custom-strategy flags:
|
|
254
|
+
|
|
255
|
+
- `stacksats-backtest --strategy module_or_path:ClassName`
|
|
256
|
+
- `stacksats-validate --strategy module_or_path:ClassName`
|
|
257
|
+
- `stacksats-export --strategy module_or_path:ClassName`
|
|
258
|
+
|
|
259
|
+
## Advanced: Deployment
|
|
260
|
+
|
|
261
|
+
Deployment and infrastructure modules are optional:
|
|
262
|
+
|
|
263
|
+
- `stacksats.export_weights`
|
|
264
|
+
- `stacksats.modal_app`
|
|
265
|
+
|
|
266
|
+
These require deployment extras:
|
|
267
|
+
|
|
268
|
+
```bash
|
|
269
|
+
pip install "stacksats[deploy]"
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
Deploy with built-in strategy:
|
|
273
|
+
|
|
274
|
+
```bash
|
|
275
|
+
modal deploy stacksats/modal_app.py
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
Deploy with custom strategy:
|
|
279
|
+
|
|
280
|
+
```bash
|
|
281
|
+
STACKSATS_STRATEGY=my_strategy.py:MyStrategy modal deploy stacksats/modal_app.py
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
## Development
|
|
285
|
+
|
|
286
|
+
Run tests:
|
|
287
|
+
|
|
288
|
+
```bash
|
|
289
|
+
pytest tests/ -v
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
Verify documented command examples:
|
|
293
|
+
|
|
294
|
+
```bash
|
|
295
|
+
# Requires ./venv (for example: python -m venv venv && source venv/bin/activate && pip install -e .)
|
|
296
|
+
python scripts/test_example_commands.py
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
Run lint:
|
|
300
|
+
|
|
301
|
+
```bash
|
|
302
|
+
ruff check .
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
Release process: see `docs/release.md`.
|
|
306
|
+
|
|
307
|
+
## Contributors
|
|
308
|
+
|
|
309
|
+
This project has benefited from contributions by researchers from the following universities:
|
|
310
|
+
|
|
311
|
+
- Columbia University (Master of Data Science)
|
|
312
|
+
- Cornell University (Master of Engineering in Management)
|
|
313
|
+
- Georgia Institute of Technology (Master of Science in Analytics)
|
|
314
|
+
- London School of Economics (Master of Science in Data Science)
|
|
315
|
+
- University of British Columbia (Master of Data Science)
|
|
316
|
+
- University of California, Davis (Master of Science in Business Analytics)
|
|
317
|
+
- University of California, Irvine (Master of Data Science)
|
|
318
|
+
- University of California, San Diego (Master of Quantitative Finance)
|
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
# StackSats
|
|
2
|
+
|
|
3
|
+
StackSats, developed by [Hypertrial](https://www.hypertrail.ai), is a Python package for developing and backtesting Bitcoin DCA ("stacking sats") allocation strategies.
|
|
4
|
+
|
|
5
|
+
Learn more at [www.stackingsats.org](https://www.stackingsats.org)
|
|
6
|
+
|
|
7
|
+
It provides:
|
|
8
|
+
- A clean strategy interface (`WindowStrategy`)
|
|
9
|
+
- Built-in and example strategies
|
|
10
|
+
- A rolling-window backtest engine
|
|
11
|
+
- Feature precomputation utilities
|
|
12
|
+
- Validation checks for leakage, constraints, and win-rate
|
|
13
|
+
|
|
14
|
+
## Installation
|
|
15
|
+
|
|
16
|
+
Install core package for local model development:
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
pip install stacksats
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
For local development from source:
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
pip install -e .
|
|
26
|
+
pip install -r requirements-dev.txt
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Install deployment dependencies only if needed:
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
pip install "stacksats[deploy]"
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Quick Start (write your own strategy file)
|
|
36
|
+
|
|
37
|
+
Create `my_strategy.py`:
|
|
38
|
+
|
|
39
|
+
```python
|
|
40
|
+
import numpy as np
|
|
41
|
+
import pandas as pd
|
|
42
|
+
|
|
43
|
+
from stacksats import run_backtest, validate_strategy
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
class MyStrategy:
|
|
47
|
+
def compute_weights(
|
|
48
|
+
self,
|
|
49
|
+
features_df: pd.DataFrame,
|
|
50
|
+
start_date: pd.Timestamp,
|
|
51
|
+
end_date: pd.Timestamp,
|
|
52
|
+
current_date: pd.Timestamp,
|
|
53
|
+
) -> pd.Series:
|
|
54
|
+
del current_date
|
|
55
|
+
window = features_df.loc[start_date:end_date]
|
|
56
|
+
if window.empty:
|
|
57
|
+
return pd.Series(dtype=float)
|
|
58
|
+
|
|
59
|
+
z = window.get("mvrv_zscore", pd.Series(0.0, index=window.index)).to_numpy()
|
|
60
|
+
ma = window.get("price_vs_ma", pd.Series(0.0, index=window.index)).to_numpy()
|
|
61
|
+
raw = np.exp((-1.2 * z) + (-0.8 * ma))
|
|
62
|
+
w = raw / raw.sum()
|
|
63
|
+
return pd.Series(w, index=window.index)
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
if __name__ == "__main__":
|
|
67
|
+
strategy = MyStrategy()
|
|
68
|
+
|
|
69
|
+
validation = validate_strategy(strategy)
|
|
70
|
+
print(validation.summary())
|
|
71
|
+
|
|
72
|
+
result = run_backtest(strategy, strategy_label="my-strategy")
|
|
73
|
+
print(result.summary())
|
|
74
|
+
result.plot(output_dir="output")
|
|
75
|
+
result.to_json("output/backtest_result.json")
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Run it directly:
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
python my_strategy.py
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
For a complete command reference using the included example file, see
|
|
85
|
+
[`docs/commands.md`](docs/commands.md).
|
|
86
|
+
|
|
87
|
+
## Public API
|
|
88
|
+
|
|
89
|
+
Top-level package exports:
|
|
90
|
+
|
|
91
|
+
- `run_backtest()`: Run a rolling-window backtest for any strategy
|
|
92
|
+
- `validate_strategy()`: Run submission-style validation checks
|
|
93
|
+
- `load_data()`: Load BTC market data (with local cache support)
|
|
94
|
+
- `precompute_features()`: Build model features from BTC data
|
|
95
|
+
- `load_strategy()`: Load a strategy from `module_or_path:ClassName`
|
|
96
|
+
- `BacktestResult`: Result object with summary/plot/serialization helpers
|
|
97
|
+
- `ValidationResult`: Structured validation output
|
|
98
|
+
- `WindowStrategy`, `CallableWindowStrategy`, `MVRVStrategy`
|
|
99
|
+
|
|
100
|
+
`load_data()` also supports cache controls via optional keyword args:
|
|
101
|
+
- `cache_dir` (default `~/.stacksats/cache`, set to `None` to disable local cache)
|
|
102
|
+
- `max_age_hours` (default `24`, refresh threshold for cached CoinMetrics CSV)
|
|
103
|
+
|
|
104
|
+
## Writing a Strategy
|
|
105
|
+
|
|
106
|
+
Implement `compute_weights()` with this interface:
|
|
107
|
+
|
|
108
|
+
```python
|
|
109
|
+
def compute_weights(
|
|
110
|
+
self,
|
|
111
|
+
features_df: pd.DataFrame,
|
|
112
|
+
start_date: pd.Timestamp,
|
|
113
|
+
end_date: pd.Timestamp,
|
|
114
|
+
current_date: pd.Timestamp,
|
|
115
|
+
) -> pd.Series:
|
|
116
|
+
...
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
Rules your strategy should satisfy:
|
|
120
|
+
|
|
121
|
+
- Return a weight series indexed by dates in the selected window
|
|
122
|
+
- Weights should be non-negative
|
|
123
|
+
- Weights should sum to `1.0`
|
|
124
|
+
- Avoid forward-looking data usage
|
|
125
|
+
|
|
126
|
+
### Available Features
|
|
127
|
+
|
|
128
|
+
Feature columns are generated by `precompute_features()` and typically include:
|
|
129
|
+
|
|
130
|
+
- `PriceUSD_coinmetrics`
|
|
131
|
+
- `price_ma`
|
|
132
|
+
- `price_vs_ma`
|
|
133
|
+
- `mvrv_zscore`
|
|
134
|
+
- `mvrv_gradient`
|
|
135
|
+
- `mvrv_percentile`
|
|
136
|
+
- `mvrv_acceleration`
|
|
137
|
+
- `mvrv_zone`
|
|
138
|
+
- `mvrv_volatility`
|
|
139
|
+
- `signal_confidence`
|
|
140
|
+
|
|
141
|
+
## Built-in and Example Strategies
|
|
142
|
+
|
|
143
|
+
### Built-in
|
|
144
|
+
|
|
145
|
+
- `MVRVStrategy`: Default strategy from the package model.
|
|
146
|
+
|
|
147
|
+
### Examples
|
|
148
|
+
|
|
149
|
+
In `stacksats.strategies.examples`:
|
|
150
|
+
|
|
151
|
+
- `UniformStrategy`
|
|
152
|
+
- `SimpleZScoreStrategy`
|
|
153
|
+
- `MomentumStrategy`
|
|
154
|
+
|
|
155
|
+
These are lightweight templates for custom model development.
|
|
156
|
+
|
|
157
|
+
## Backtesting
|
|
158
|
+
|
|
159
|
+
Run the default built-in strategy:
|
|
160
|
+
|
|
161
|
+
```bash
|
|
162
|
+
stacksats-backtest
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
Run a custom strategy class from a file:
|
|
166
|
+
|
|
167
|
+
```bash
|
|
168
|
+
stacksats-backtest --strategy my_strategy.py:MyStrategy --start-date 2020-01-01 --end-date 2025-01-01
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
Use the Python API directly:
|
|
172
|
+
|
|
173
|
+
```python
|
|
174
|
+
from stacksats import MVRVStrategy, run_backtest
|
|
175
|
+
|
|
176
|
+
result = run_backtest(MVRVStrategy(), strategy_label="default-mvrv")
|
|
177
|
+
print(result.summary())
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
## Validation
|
|
181
|
+
|
|
182
|
+
Validate built-in strategy:
|
|
183
|
+
|
|
184
|
+
```bash
|
|
185
|
+
stacksats-validate --start-date 2020-01-01 --end-date 2025-01-01
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
Validate a custom strategy class:
|
|
189
|
+
|
|
190
|
+
```bash
|
|
191
|
+
stacksats-validate --strategy my_strategy.py:MyStrategy --min-win-rate 50.0
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
## Command Line Tools
|
|
195
|
+
|
|
196
|
+
Installed scripts:
|
|
197
|
+
|
|
198
|
+
- `stacksats-backtest`
|
|
199
|
+
- `stacksats-export`
|
|
200
|
+
- `stacksats-plot-mvrv`
|
|
201
|
+
- `stacksats-plot-weights`
|
|
202
|
+
- `stacksats-validate`
|
|
203
|
+
|
|
204
|
+
Custom-strategy flags:
|
|
205
|
+
|
|
206
|
+
- `stacksats-backtest --strategy module_or_path:ClassName`
|
|
207
|
+
- `stacksats-validate --strategy module_or_path:ClassName`
|
|
208
|
+
- `stacksats-export --strategy module_or_path:ClassName`
|
|
209
|
+
|
|
210
|
+
## Advanced: Deployment
|
|
211
|
+
|
|
212
|
+
Deployment and infrastructure modules are optional:
|
|
213
|
+
|
|
214
|
+
- `stacksats.export_weights`
|
|
215
|
+
- `stacksats.modal_app`
|
|
216
|
+
|
|
217
|
+
These require deployment extras:
|
|
218
|
+
|
|
219
|
+
```bash
|
|
220
|
+
pip install "stacksats[deploy]"
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
Deploy with built-in strategy:
|
|
224
|
+
|
|
225
|
+
```bash
|
|
226
|
+
modal deploy stacksats/modal_app.py
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
Deploy with custom strategy:
|
|
230
|
+
|
|
231
|
+
```bash
|
|
232
|
+
STACKSATS_STRATEGY=my_strategy.py:MyStrategy modal deploy stacksats/modal_app.py
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
## Development
|
|
236
|
+
|
|
237
|
+
Run tests:
|
|
238
|
+
|
|
239
|
+
```bash
|
|
240
|
+
pytest tests/ -v
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
Verify documented command examples:
|
|
244
|
+
|
|
245
|
+
```bash
|
|
246
|
+
# Requires ./venv (for example: python -m venv venv && source venv/bin/activate && pip install -e .)
|
|
247
|
+
python scripts/test_example_commands.py
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
Run lint:
|
|
251
|
+
|
|
252
|
+
```bash
|
|
253
|
+
ruff check .
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
Release process: see `docs/release.md`.
|
|
257
|
+
|
|
258
|
+
## Contributors
|
|
259
|
+
|
|
260
|
+
This project has benefited from contributions by researchers from the following universities:
|
|
261
|
+
|
|
262
|
+
- Columbia University (Master of Data Science)
|
|
263
|
+
- Cornell University (Master of Engineering in Management)
|
|
264
|
+
- Georgia Institute of Technology (Master of Science in Analytics)
|
|
265
|
+
- London School of Economics (Master of Science in Data Science)
|
|
266
|
+
- University of British Columbia (Master of Data Science)
|
|
267
|
+
- University of California, Davis (Master of Science in Business Analytics)
|
|
268
|
+
- University of California, Irvine (Master of Data Science)
|
|
269
|
+
- University of California, San Diego (Master of Quantitative Finance)
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=69", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "stacksats"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Bitcoin DCA model development, backtesting, and Modal deployment toolkit"
|
|
9
|
+
readme = { file = "README.md", content-type = "text/markdown" }
|
|
10
|
+
requires-python = ">=3.11"
|
|
11
|
+
license = { text = "MIT" }
|
|
12
|
+
authors = [{ name = "StackSats Contributors" }]
|
|
13
|
+
keywords = ["bitcoin", "dca", "backtesting", "quant", "crypto"]
|
|
14
|
+
classifiers = [
|
|
15
|
+
"Development Status :: 3 - Alpha",
|
|
16
|
+
"Intended Audience :: Financial and Insurance Industry",
|
|
17
|
+
"Intended Audience :: Science/Research",
|
|
18
|
+
"License :: OSI Approved :: MIT License",
|
|
19
|
+
"Programming Language :: Python :: 3",
|
|
20
|
+
"Programming Language :: Python :: 3.11",
|
|
21
|
+
"Programming Language :: Python :: 3.12",
|
|
22
|
+
"Topic :: Office/Business :: Financial :: Investment",
|
|
23
|
+
"Topic :: Scientific/Engineering :: Information Analysis",
|
|
24
|
+
]
|
|
25
|
+
dependencies = [
|
|
26
|
+
"pandas>=2.0.0",
|
|
27
|
+
"numpy>=1.24.0",
|
|
28
|
+
"scipy>=1.11.0",
|
|
29
|
+
"requests>=2.31.0",
|
|
30
|
+
"matplotlib>=3.7.0",
|
|
31
|
+
"seaborn>=0.12.0",
|
|
32
|
+
]
|
|
33
|
+
|
|
34
|
+
[project.urls]
|
|
35
|
+
Homepage = "https://github.com/stacksats/stacksats"
|
|
36
|
+
Repository = "https://github.com/stacksats/stacksats"
|
|
37
|
+
Documentation = "https://github.com/stacksats/stacksats/tree/main/docs"
|
|
38
|
+
|
|
39
|
+
[project.optional-dependencies]
|
|
40
|
+
deploy = [
|
|
41
|
+
"modal>=0.52.0",
|
|
42
|
+
"psycopg2-binary>=2.9.0",
|
|
43
|
+
"fastapi>=0.104.0",
|
|
44
|
+
"python-dotenv>=1.0.0",
|
|
45
|
+
"tenacity>=8.2.0",
|
|
46
|
+
"pyarrow>=13.0.0",
|
|
47
|
+
]
|
|
48
|
+
dev = [
|
|
49
|
+
"pytest>=7.0.0",
|
|
50
|
+
"pytest-bdd>=7.0.0",
|
|
51
|
+
"pytest-cov>=4.0.0",
|
|
52
|
+
"pytest-mock>=3.10.0",
|
|
53
|
+
"pytest-benchmark>=4.0.0",
|
|
54
|
+
"pytest-xdist>=3.0.0",
|
|
55
|
+
"responses>=0.23.0",
|
|
56
|
+
"freezegun>=1.2.0",
|
|
57
|
+
"hypothesis>=6.0.0",
|
|
58
|
+
"ruff>=0.1.0",
|
|
59
|
+
"vulture",
|
|
60
|
+
]
|
|
61
|
+
|
|
62
|
+
[project.scripts]
|
|
63
|
+
stacksats-backtest = "stacksats.backtest:main"
|
|
64
|
+
stacksats-export = "stacksats.export_weights:main"
|
|
65
|
+
stacksats-plot-mvrv = "stacksats.plot_mvrv:main"
|
|
66
|
+
stacksats-plot-weights = "stacksats.plot_weights:main"
|
|
67
|
+
stacksats-validate = "stacksats.api:validate_strategy_cli"
|
|
68
|
+
|
|
69
|
+
[tool.setuptools.packages.find]
|
|
70
|
+
where = ["."]
|
|
71
|
+
include = ["stacksats", "stacksats.*"]
|
|
72
|
+
|
|
73
|
+
[tool.setuptools.package-data]
|
|
74
|
+
stacksats = ["py.typed"]
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"""StackSats package public API."""
|
|
2
|
+
|
|
3
|
+
from .api import BacktestResult, ValidationResult, run_backtest, validate_strategy
|
|
4
|
+
from .loader import load_strategy
|
|
5
|
+
from .model_development import precompute_features
|
|
6
|
+
from .prelude import load_data
|
|
7
|
+
from .strategies.base import CallableWindowStrategy, WindowStrategy
|
|
8
|
+
from .strategies.mvrv import MVRVStrategy
|
|
9
|
+
|
|
10
|
+
__all__ = [
|
|
11
|
+
"BacktestResult",
|
|
12
|
+
"CallableWindowStrategy",
|
|
13
|
+
"MVRVStrategy",
|
|
14
|
+
"ValidationResult",
|
|
15
|
+
"WindowStrategy",
|
|
16
|
+
"load_strategy",
|
|
17
|
+
"load_data",
|
|
18
|
+
"precompute_features",
|
|
19
|
+
"run_backtest",
|
|
20
|
+
"validate_strategy",
|
|
21
|
+
]
|