Files
Pratik Bhadane 71b6343e92 feat: refresh benchmark coverage and harden CI tooling
Refresh the benchmark and performance surface across the repo. This updates the benchmark wrappers and helper scripts, regenerates the checked-in benchmark and perf-contract artifacts, and folds in the related roadmap, compatibility, and example notebook changes that belong with this performance-focused pass.

Harden the Python CI and local pre-push flow so the same checks pass reliably in both places. The workflow and pre-push script now use module-safe uv typecheck invocations, the Python test environment installs the optional MCP dependency needed by the MCP server tests, and one-off root benchmark outputs are ignored to keep the repo clean.

Align local tooling with the current project configuration by updating the Ruff pre-commit hook, tightening the API typing and MCP server helpers, and refreshing the lockfile to pick up the audited PyJWT fix while preserving the rest of the staged source changes.
2026-03-24 14:52:20 +05:30

207 lines
5.1 KiB
Plaintext

{
"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",
"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
}