feat: init the repo
This commit is contained in:
@@ -0,0 +1,31 @@
|
||||
# ferro-ta Examples
|
||||
|
||||
Jupyter notebooks demonstrating key ferro-ta features.
|
||||
|
||||
## Notebooks
|
||||
|
||||
| Notebook | Description |
|
||||
|---|---|
|
||||
| [`quickstart.ipynb`](quickstart.ipynb) | Core API: moving averages, RSI, MACD, Bollinger Bands, batch API, pipeline, pandas integration |
|
||||
| [`streaming.ipynb`](streaming.ipynb) | Streaming bar-by-bar API: StreamingSMA, StreamingRSI, StreamingBBands, StreamingMACD, StreamingATR |
|
||||
| [`backtesting.ipynb`](backtesting.ipynb) | Backtesting harness, indicator pipeline for feature engineering, config defaults |
|
||||
| [`features_21_30.ipynb`](features_21_30.ipynb) | Multi-timeframe, resampling, portfolio analytics, strategy DSL, feature matrix, viz, adapters |
|
||||
|
||||
## Running the Notebooks
|
||||
|
||||
```bash
|
||||
# Install dependencies
|
||||
pip install ferro-ta jupyter numpy
|
||||
|
||||
# Optional: pandas and polars integration
|
||||
pip install "ferro-ta[pandas]" "ferro_ta[polars]"
|
||||
|
||||
# Start Jupyter
|
||||
jupyter notebook examples/
|
||||
```
|
||||
|
||||
## Links
|
||||
|
||||
- [ferro-ta README](../README.md)
|
||||
- [API documentation](../docs/)
|
||||
- [CONTRIBUTING.md](../CONTRIBUTING.md)
|
||||
@@ -0,0 +1,200 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Backtesting with ferro-ta\n",
|
||||
"\n",
|
||||
"This notebook demonstrates the minimal backtesting harness and the\n",
|
||||
"indicator pipeline, together with the configuration defaults API.\n",
|
||||
"\n",
|
||||
"Install:\n",
|
||||
"```bash\n",
|
||||
"pip install ferro-ta\n",
|
||||
"```"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import numpy as np\n",
|
||||
"\n",
|
||||
"import ferro_ta.config as config\n",
|
||||
"from ferro_ta import BBANDS, EMA, RSI, SMA\n",
|
||||
"from ferro_ta.backtest import backtest\n",
|
||||
"from ferro_ta.pipeline import Pipeline\n",
|
||||
"\n",
|
||||
"# Synthetic data\n",
|
||||
"np.random.seed(42)\n",
|
||||
"n = 300\n",
|
||||
"close = np.cumprod(1 + np.random.randn(n) * 0.01) * 100\n",
|
||||
"volume = np.random.randint(1000, 10000, n).astype(float)\n",
|
||||
"print(f\"Generated {n} bars, final price: {close[-1]:.2f}\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## RSI 30/70 Strategy"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"result = backtest(close, strategy=\"rsi_30_70\", timeperiod=14)\n",
|
||||
"print(\"Strategy: RSI 30/70\")\n",
|
||||
"print(f\"Final equity: {result.final_equity:.4f}\")\n",
|
||||
"print(f\"Number of trades: {result.n_trades}\")\n",
|
||||
"print(f\"Return: {(result.final_equity - 1.0) * 100:.2f}%\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## SMA Crossover Strategy"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"result2 = backtest(close, strategy=\"sma_crossover\", fast=10, slow=30)\n",
|
||||
"print(\"Strategy: SMA Crossover (10/30)\")\n",
|
||||
"print(f\"Final equity: {result2.final_equity:.4f}\")\n",
|
||||
"print(f\"Number of trades: {result2.n_trades}\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Configuration Defaults\n",
|
||||
"\n",
|
||||
"Set global defaults for indicator parameters to avoid repeating them."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Set global defaults\n",
|
||||
"config.set_default(\"timeperiod\", 20) # global default for all indicators\n",
|
||||
"config.set_default(\"RSI.timeperiod\", 14) # RSI-specific override\n",
|
||||
"\n",
|
||||
"print(\"Current defaults:\", config.list_defaults())\n",
|
||||
"print(\"RSI defaults:\", config.get_defaults_for(\"RSI\"))\n",
|
||||
"print(\"SMA defaults:\", config.get_defaults_for(\"SMA\"))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Context manager for temporary overrides\n",
|
||||
"with config.Config(timeperiod=5):\n",
|
||||
" temp_default = config.get_default(\"timeperiod\")\n",
|
||||
" print(f\"Inside context: timeperiod={temp_default}\")\n",
|
||||
"\n",
|
||||
"print(f\"After context: timeperiod={config.get_default('timeperiod')}\") # back to 20\n",
|
||||
"\n",
|
||||
"# Clean up\n",
|
||||
"config.reset()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Multi-indicator Pipeline for Feature Engineering"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"pipe = (\n",
|
||||
" Pipeline()\n",
|
||||
" .add(\"sma_10\", SMA, timeperiod=10)\n",
|
||||
" .add(\"sma_30\", SMA, timeperiod=30)\n",
|
||||
" .add(\"ema_10\", EMA, timeperiod=10)\n",
|
||||
" .add(\"rsi_14\", RSI, timeperiod=14)\n",
|
||||
" .add(\n",
|
||||
" \"bb\",\n",
|
||||
" BBANDS,\n",
|
||||
" output_keys=[\"bb_upper\", \"bb_mid\", \"bb_lower\"],\n",
|
||||
" timeperiod=20,\n",
|
||||
" nbdevup=2.0,\n",
|
||||
" nbdevdn=2.0,\n",
|
||||
" )\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"features = pipe.run(close)\n",
|
||||
"print(\"Feature columns:\", list(features.keys()))\n",
|
||||
"\n",
|
||||
"# Build a simple feature matrix (last 5 complete rows)\n",
|
||||
"valid_start = 30 # warmup\n",
|
||||
"feature_matrix = np.column_stack([v[valid_start:] for v in features.values()])\n",
|
||||
"print(f\"Feature matrix shape: {feature_matrix.shape}\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Simple Manual Backtest Using the Pipeline"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Signal: long when RSI < 40 AND close > SMA_30; flat otherwise\n",
|
||||
"rsi_vals = features[\"rsi_14\"]\n",
|
||||
"sma30_vals = features[\"sma_30\"]\n",
|
||||
"\n",
|
||||
"signal = np.where((rsi_vals < 40) & (close > sma30_vals), 1.0, 0.0)\n",
|
||||
"position = np.roll(signal, 1) # trade on next bar open\n",
|
||||
"position[0] = 0.0\n",
|
||||
"\n",
|
||||
"returns = np.diff(close) / close[:-1]\n",
|
||||
"strategy_returns = returns * position[1:]\n",
|
||||
"\n",
|
||||
"equity = np.cumprod(1 + strategy_returns)\n",
|
||||
"print(f\"Final equity: {equity[-1]:.4f}\")\n",
|
||||
"print(f\"Number of signal bars: {int(signal.sum())}\")"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"name": "python",
|
||||
"version": "3.11.0"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 4
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
"""
|
||||
Example plugin: smoothed RSI (SMA of RSI).
|
||||
|
||||
Run this file to verify the plugin contract:
|
||||
python examples/custom_indicator.py
|
||||
|
||||
Registers "SMOOTH_RSI" and runs it on sample data.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import numpy as np
|
||||
|
||||
from ferro_ta import RSI, SMA
|
||||
from ferro_ta.core.registry import list_indicators, register, run
|
||||
|
||||
|
||||
def smooth_rsi(close, timeperiod=14, smooth=3):
|
||||
"""Smoothed RSI: RSI then SMA of the RSI series.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
close : array-like
|
||||
Close prices.
|
||||
timeperiod : int
|
||||
RSI period (default 14).
|
||||
smooth : int
|
||||
SMA period applied to RSI (default 3).
|
||||
|
||||
Returns
|
||||
-------
|
||||
numpy.ndarray
|
||||
Smoothed RSI values; same length as close.
|
||||
"""
|
||||
rsi = RSI(close, timeperiod=timeperiod)
|
||||
return SMA(rsi, timeperiod=smooth)
|
||||
|
||||
|
||||
def main():
|
||||
register("SMOOTH_RSI", smooth_rsi)
|
||||
close = np.array(
|
||||
[44.34, 44.09, 44.15, 43.61, 44.33, 44.83, 45.10, 45.15, 44.61, 44.33]
|
||||
)
|
||||
out = run("SMOOTH_RSI", close, timeperiod=5, smooth=2)
|
||||
print("SMOOTH_RSI:", out)
|
||||
assert "SMOOTH_RSI" in list_indicators(), (
|
||||
"SMOOTH_RSI should be in list_indicators()"
|
||||
)
|
||||
print("OK: plugin registered and run successfully.")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,233 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# ferro-ta Quick Start\n",
|
||||
"\n",
|
||||
"This notebook demonstrates the core ferro-ta API.\n",
|
||||
"\n",
|
||||
"Install:\n",
|
||||
"```bash\n",
|
||||
"pip install ferro-ta\n",
|
||||
"```"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import numpy as np\n",
|
||||
"\n",
|
||||
"from ferro_ta import BBANDS, EMA, MACD, RSI, SMA\n",
|
||||
"\n",
|
||||
"# Synthetic OHLCV data\n",
|
||||
"np.random.seed(42)\n",
|
||||
"n = 200\n",
|
||||
"close = np.cumprod(1 + np.random.randn(n) * 0.01) * 100\n",
|
||||
"high = close * (1 + np.abs(np.random.randn(n)) * 0.005)\n",
|
||||
"low = close * (1 - np.abs(np.random.randn(n)) * 0.005)\n",
|
||||
"volume = np.random.randint(1_000, 10_000, n).astype(float)\n",
|
||||
"\n",
|
||||
"print(f\"Generated {n} bars\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Moving Averages"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"sma_20 = SMA(close, timeperiod=20)\n",
|
||||
"ema_20 = EMA(close, timeperiod=20)\n",
|
||||
"\n",
|
||||
"print(\"SMA(20):\", sma_20[-5:])\n",
|
||||
"print(\"EMA(20):\", ema_20[-5:])"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## RSI"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"rsi = RSI(close, timeperiod=14)\n",
|
||||
"print(\"RSI(14):\", rsi[-5:])\n",
|
||||
"print(f\"RSI range: [{np.nanmin(rsi):.2f}, {np.nanmax(rsi):.2f}]\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## MACD"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"macd_line, signal, hist = MACD(close, fastperiod=12, slowperiod=26, signalperiod=9)\n",
|
||||
"print(\"MACD line: \", macd_line[-5:])\n",
|
||||
"print(\"Signal: \", signal[-5:])\n",
|
||||
"print(\"Histogram: \", hist[-5:])"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Bollinger Bands"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"upper, middle, lower = BBANDS(close, timeperiod=20, nbdevup=2.0, nbdevdn=2.0)\n",
|
||||
"print(\"Upper band: \", upper[-5:])\n",
|
||||
"print(\"Middle band:\", middle[-5:])\n",
|
||||
"print(\"Lower band: \", lower[-5:])"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Batch API — multiple symbols at once"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from ferro_ta.batch import batch_rsi, batch_sma\n",
|
||||
"\n",
|
||||
"# Simulate 5 symbols\n",
|
||||
"data = np.random.default_rng(0).random((200, 5)) * 100 + 50\n",
|
||||
"sma_result = batch_sma(data, timeperiod=20)\n",
|
||||
"rsi_result = batch_rsi(data, timeperiod=14)\n",
|
||||
"\n",
|
||||
"print(\"Batch SMA shape:\", sma_result.shape) # (200, 5)\n",
|
||||
"print(\"Batch RSI shape:\", rsi_result.shape) # (200, 5)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Pipeline API — compose multiple indicators"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from ferro_ta.pipeline import Pipeline\n",
|
||||
"\n",
|
||||
"pipe = (\n",
|
||||
" Pipeline()\n",
|
||||
" .add(\"sma_20\", SMA, timeperiod=20)\n",
|
||||
" .add(\"ema_20\", EMA, timeperiod=20)\n",
|
||||
" .add(\"rsi_14\", RSI, timeperiod=14)\n",
|
||||
" .add(\n",
|
||||
" \"bb\",\n",
|
||||
" BBANDS,\n",
|
||||
" output_keys=[\"bb_upper\", \"bb_mid\", \"bb_lower\"],\n",
|
||||
" timeperiod=20,\n",
|
||||
" nbdevup=2.0,\n",
|
||||
" nbdevdn=2.0,\n",
|
||||
" )\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"results = pipe.run(close)\n",
|
||||
"print(\"Pipeline outputs:\", list(results.keys()))\n",
|
||||
"print(\"SMA last 3:\", results[\"sma_20\"][-3:])"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Pandas Integration"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"try:\n",
|
||||
" import pandas as pd\n",
|
||||
"\n",
|
||||
" s = pd.Series(close, name=\"close\")\n",
|
||||
" sma_pd = SMA(s, timeperiod=20)\n",
|
||||
" print(\"Result type:\", type(sma_pd)) # pandas.Series\n",
|
||||
" print(\"Index preserved:\", list(sma_pd.index[:3]))\n",
|
||||
"except ImportError:\n",
|
||||
" print(\"pandas not installed\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Error Handling"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from ferro_ta import FerroTAValueError\n",
|
||||
"from ferro_ta.exceptions import check_timeperiod\n",
|
||||
"\n",
|
||||
"try:\n",
|
||||
" check_timeperiod(0)\n",
|
||||
"except FerroTAValueError as e:\n",
|
||||
" print(\"Caught:\", e)"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"name": "python",
|
||||
"version": "3.11.0"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 4
|
||||
}
|
||||
@@ -0,0 +1,207 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Streaming API — bar-by-bar live trading\n",
|
||||
"\n",
|
||||
"The `ferro_ta.streaming` module provides stateful classes that process\n",
|
||||
"data bar-by-bar, suitable for real-time feeds and live trading.\n",
|
||||
"\n",
|
||||
"Install:\n",
|
||||
"```bash\n",
|
||||
"pip install ferro-ta\n",
|
||||
"```"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import numpy as np\n",
|
||||
"\n",
|
||||
"from ferro_ta.streaming import (\n",
|
||||
" StreamingATR,\n",
|
||||
" StreamingBBands,\n",
|
||||
" StreamingEMA,\n",
|
||||
" StreamingMACD,\n",
|
||||
" StreamingRSI,\n",
|
||||
" StreamingSMA,\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"# Simulate incoming bars\n",
|
||||
"np.random.seed(42)\n",
|
||||
"n = 50\n",
|
||||
"closes = np.cumprod(1 + np.random.randn(n) * 0.01) * 100\n",
|
||||
"highs = closes * 1.005\n",
|
||||
"lows = closes * 0.995\n",
|
||||
"\n",
|
||||
"print(f\"Simulated {n} bars\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## StreamingSMA and StreamingEMA"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"sma = StreamingSMA(period=5)\n",
|
||||
"ema = StreamingEMA(period=5)\n",
|
||||
"\n",
|
||||
"sma_values = [sma.update(c) for c in closes]\n",
|
||||
"ema_values = [ema.update(c) for c in closes]\n",
|
||||
"\n",
|
||||
"print(\n",
|
||||
" \"SMA last 5:\", [f\"{v:.4f}\" if not np.isnan(v) else \"NaN\" for v in sma_values[-5:]]\n",
|
||||
")\n",
|
||||
"print(\n",
|
||||
" \"EMA last 5:\", [f\"{v:.4f}\" if not np.isnan(v) else \"NaN\" for v in ema_values[-5:]]\n",
|
||||
")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## StreamingRSI"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"rsi_stream = StreamingRSI(period=14)\n",
|
||||
"\n",
|
||||
"rsi_values = [rsi_stream.update(c) for c in closes]\n",
|
||||
"finite = [(i, v) for i, v in enumerate(rsi_values) if not np.isnan(v)]\n",
|
||||
"print(f\"First valid RSI at bar {finite[0][0]}: {finite[0][1]:.2f}\")\n",
|
||||
"print(\"RSI last 3:\", [f\"{v:.2f}\" for _, v in finite[-3:]])"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## StreamingBBands"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"bbands = StreamingBBands(period=20)\n",
|
||||
"\n",
|
||||
"bb_results = [bbands.update(c) for c in closes]\n",
|
||||
"# Each result is (upper, middle, lower) or (nan, nan, nan) during warmup\n",
|
||||
"valid_bb = [\n",
|
||||
" (i, u, m, lower) for i, (u, m, lower) in enumerate(bb_results) if not np.isnan(m)\n",
|
||||
"]\n",
|
||||
"if valid_bb:\n",
|
||||
" i, u, m, lower = valid_bb[-1]\n",
|
||||
" print(f\"Latest Bollinger Bands at bar {i}:\")\n",
|
||||
" print(f\" Upper: {u:.4f}\")\n",
|
||||
" print(f\" Middle: {m:.4f}\")\n",
|
||||
" print(f\" Lower: {lower:.4f}\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## StreamingMACD"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"macd_stream = StreamingMACD(fastperiod=12, slowperiod=26, signalperiod=9)\n",
|
||||
"\n",
|
||||
"macd_results = [macd_stream.update(c) for c in closes]\n",
|
||||
"# Each result is (macd_line, signal, histogram)\n",
|
||||
"valid_macd = [\n",
|
||||
" (i, m, s, h) for i, (m, s, h) in enumerate(macd_results) if not np.isnan(m)\n",
|
||||
"]\n",
|
||||
"if valid_macd:\n",
|
||||
" i, m, s, h = valid_macd[-1]\n",
|
||||
" print(f\"Latest MACD at bar {i}:\")\n",
|
||||
" print(f\" MACD line: {m:.6f}\")\n",
|
||||
" print(f\" Signal: {s:.6f}\")\n",
|
||||
" print(f\" Histogram: {h:.6f}\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## StreamingATR"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"atr_stream = StreamingATR(period=14)\n",
|
||||
"\n",
|
||||
"atr_values = [atr_stream.update(h, low, c) for h, low, c in zip(highs, lows, closes)]\n",
|
||||
"finite_atr = [v for v in atr_values if not np.isnan(v)]\n",
|
||||
"if finite_atr:\n",
|
||||
" print(f\"Latest ATR: {finite_atr[-1]:.4f}\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Reset and reuse\n",
|
||||
"\n",
|
||||
"All streaming classes support `reset()` to clear internal state and start fresh."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"sma.reset()\n",
|
||||
"print(\"After reset, SMA(5.0):\", sma.update(5.0)) # NaN — warm-up restarted\n",
|
||||
"sma.update(6.0)\n",
|
||||
"sma.update(7.0)\n",
|
||||
"sma.update(8.0)\n",
|
||||
"print(\"SMA after 4 bars:\", sma.update(9.0)) # 7.0 = mean of [5,6,7,8,9]"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"name": "python",
|
||||
"version": "3.11.0"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 4
|
||||
}
|
||||
Reference in New Issue
Block a user