backtestchat 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.
Files changed (47) hide show
  1. backtestchat-0.1.0/.github/workflows/publish.yml +35 -0
  2. backtestchat-0.1.0/.gitignore +35 -0
  3. backtestchat-0.1.0/AGENTS.md +42 -0
  4. backtestchat-0.1.0/CLAUDE.md +107 -0
  5. backtestchat-0.1.0/LICENSE +21 -0
  6. backtestchat-0.1.0/PKG-INFO +198 -0
  7. backtestchat-0.1.0/README.md +163 -0
  8. backtestchat-0.1.0/pyproject.toml +61 -0
  9. backtestchat-0.1.0/src/backtestchat/__init__.py +8 -0
  10. backtestchat-0.1.0/src/backtestchat/__main__.py +6 -0
  11. backtestchat-0.1.0/src/backtestchat/agent/__init__.py +11 -0
  12. backtestchat-0.1.0/src/backtestchat/agent/chat.py +222 -0
  13. backtestchat-0.1.0/src/backtestchat/agent/context.py +72 -0
  14. backtestchat-0.1.0/src/backtestchat/agent/graph.py +103 -0
  15. backtestchat-0.1.0/src/backtestchat/agent/prompt.py +62 -0
  16. backtestchat-0.1.0/src/backtestchat/agent/tools.py +378 -0
  17. backtestchat-0.1.0/src/backtestchat/artifacts.py +57 -0
  18. backtestchat-0.1.0/src/backtestchat/broker/__init__.py +41 -0
  19. backtestchat-0.1.0/src/backtestchat/broker/base.py +247 -0
  20. backtestchat-0.1.0/src/backtestchat/broker/binance.py +290 -0
  21. backtestchat-0.1.0/src/backtestchat/cli.py +204 -0
  22. backtestchat-0.1.0/src/backtestchat/config.py +89 -0
  23. backtestchat-0.1.0/src/backtestchat/paper/__init__.py +22 -0
  24. backtestchat-0.1.0/src/backtestchat/paper/runner.py +231 -0
  25. backtestchat-0.1.0/src/backtestchat/paper/store.py +209 -0
  26. backtestchat-0.1.0/src/backtestchat/render/__init__.py +26 -0
  27. backtestchat-0.1.0/src/backtestchat/render/plotly_render.py +204 -0
  28. backtestchat-0.1.0/src/backtestchat/render/widgets.py +95 -0
  29. backtestchat-0.1.0/src/backtestchat/strategy/__init__.py +26 -0
  30. backtestchat-0.1.0/src/backtestchat/strategy/engine.py +181 -0
  31. backtestchat-0.1.0/src/backtestchat/strategy/indicators.py +186 -0
  32. backtestchat-0.1.0/src/backtestchat/strategy/registry.py +272 -0
  33. backtestchat-0.1.0/src/backtestchat/strategy/signals.py +303 -0
  34. backtestchat-0.1.0/tests/__init__.py +0 -0
  35. backtestchat-0.1.0/tests/conftest.py +95 -0
  36. backtestchat-0.1.0/tests/fixtures/.gitkeep +0 -0
  37. backtestchat-0.1.0/tests/fixtures/closes_sample.json +2 -0
  38. backtestchat-0.1.0/tests/test_agent_graph.py +147 -0
  39. backtestchat-0.1.0/tests/test_agent_tools.py +149 -0
  40. backtestchat-0.1.0/tests/test_broker.py +169 -0
  41. backtestchat-0.1.0/tests/test_cli.py +66 -0
  42. backtestchat-0.1.0/tests/test_engine.py +111 -0
  43. backtestchat-0.1.0/tests/test_paper_runner.py +211 -0
  44. backtestchat-0.1.0/tests/test_registry.py +79 -0
  45. backtestchat-0.1.0/tests/test_render.py +124 -0
  46. backtestchat-0.1.0/tests/test_time_windows.py +133 -0
  47. backtestchat-0.1.0/uv.lock +1449 -0
@@ -0,0 +1,35 @@
1
+ name: Publish to PyPI
2
+
3
+ # Publishes backtestchat to PyPI when you cut a GitHub Release.
4
+ # Auth is PyPI Trusted Publishing (OIDC) - no API tokens stored anywhere.
5
+ # The publish is gated on the test suite passing.
6
+
7
+ on:
8
+ release:
9
+ types: [published]
10
+
11
+ jobs:
12
+ publish:
13
+ runs-on: ubuntu-latest
14
+ environment:
15
+ name: pypi
16
+ url: https://pypi.org/p/backtestchat
17
+ permissions:
18
+ id-token: write # required for OIDC trusted publishing
19
+ contents: read
20
+ steps:
21
+ - uses: actions/checkout@v4
22
+
23
+ - name: Install uv
24
+ uses: astral-sh/setup-uv@v5
25
+
26
+ - name: Run tests (gate the publish)
27
+ run: |
28
+ uv sync --group dev
29
+ uv run pytest -q
30
+
31
+ - name: Build sdist + wheel
32
+ run: uv build
33
+
34
+ - name: Publish to PyPI (trusted publishing)
35
+ uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,35 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *.egg-info/
5
+ .eggs/
6
+ build/
7
+ dist/
8
+
9
+ # Virtual environments
10
+ .venv/
11
+ venv/
12
+ env/
13
+
14
+ # Environment / secrets
15
+ .env
16
+ .env.*
17
+
18
+ # Runtime data (created on startup)
19
+ data/
20
+ artifacts/
21
+ *.sqlite3
22
+ *.sqlite3-journal
23
+ *.sqlite3-wal
24
+ *.sqlite3-shm
25
+
26
+ # Throwaway manual smoke scripts (not part of the package)
27
+ scripts/
28
+
29
+ # Tooling
30
+ .pytest_cache/
31
+ .ruff_cache/
32
+ .mypy_cache/
33
+ .vscode/
34
+
35
+ # uv.lock is committed on purpose - do not ignore it.
@@ -0,0 +1,42 @@
1
+ # AGENTS.md
2
+
3
+ Guidance for coding agents and contributors working in this repository. This
4
+ mirrors the key rules in CLAUDE.md; see CLAUDE.md for stack, domain decisions,
5
+ and layout.
6
+
7
+ ## What this project is
8
+
9
+ backtestchat: an open-source, local-first agentic strategy lab CLI. A LangGraph
10
+ tool-calling agent fetches keyless Binance public market data, backtests
11
+ long/flat strategies, and runs simulated paper trades. Paper-only by design -
12
+ no exchange keys, no real orders.
13
+
14
+ ## House rules (non-negotiable)
15
+
16
+ - Plain ASCII everywhere (copy, comments, docs). No em/en dashes, curly quotes,
17
+ or ellipsis characters. Use `-` and `...` instead.
18
+ - Loud, structured, self-repairing tool errors:
19
+ `{"error": code, "message": ..., "valid_options": [...]}`. No fuzzy parsing
20
+ inside tools; canonical encodings only.
21
+ - Data tools never render; the LLM never writes HTML. Rendering is a
22
+ deterministic function of widget dicts.
23
+ - Pure logic stays pure (engine/signals: bars in, results out; no I/O, globals).
24
+ - Idempotence over scheduling: the processed-bar-ts guard is the cadence
25
+ control; any command may safely trigger a sync at any time.
26
+
27
+ ## Scope
28
+
29
+ Paper-only, keyless data, no daemon, and exactly 10 agent tools. See the "Scope
30
+ and roadmap" section of CLAUDE.md for what is intentionally out of scope and
31
+ should be proposed as an addition rather than assumed to belong in the core.
32
+
33
+ ## Build and test
34
+
35
+ ```
36
+ uv sync
37
+ uv run pytest -q # deterministic, no network, no model key
38
+ ```
39
+
40
+ Package manager is uv; never edit uv.lock by hand (let `uv` resolve it). Tests
41
+ must stay offline: mock HTTP for the market layer and use a scripted fake model
42
+ for the agent graph.
@@ -0,0 +1,107 @@
1
+ # backtestchat - contributor and coding-agent guide
2
+
3
+ backtestchat is an open-source, local-first agentic strategy lab CLI: a LangGraph
4
+ tool-calling agent for fetching keyless Binance public market data, backtesting
5
+ long/flat strategies, and running simulated paper trades. Paper-only by design.
6
+
7
+ This file captures the house rules and design decisions so changes stay
8
+ consistent. If a rule here conflicts with a maintainer's instruction, follow the
9
+ maintainer.
10
+
11
+ ## Design principles (house rules, apply everywhere)
12
+
13
+ - Fix tool surfaces: canonical encodings, alias tables where needed, loud
14
+ structured errors that teach the model the valid options
15
+ (`{"error": code, "message": ..., "valid_options": [...]}`). Never add
16
+ inference layers, fuzzy parsing, or special-cased conditions inside tools; the
17
+ model maps user language to canonical values.
18
+ - Data tools do not render. Rendering is a deterministic function of widget
19
+ dicts. The LLM never writes HTML or markup.
20
+ - Pure logic stays pure: engine and signals take bars in, return results out -
21
+ no I/O, no globals. This is what makes them testable and portable.
22
+ - Idempotence over scheduling: the processed-bar-ts guard is the cadence
23
+ control; any command may safely trigger a sync at any time.
24
+ - Plain ASCII in all copy, comments, and docs. No em/en dashes, no curly quotes,
25
+ no ellipsis characters. Use `-` and `...` instead.
26
+
27
+ ## Stack
28
+
29
+ - Python >= 3.12, uv + pyproject.toml, src/ layout, console script `backtestchat`.
30
+ - langgraph (agent graph + SqliteSaver checkpointer). langchain-core (@tool,
31
+ messages) + init_chat_model for BYOK. No legacy LangChain chains/agents.
32
+ - typer + rich (CLI + streaming output). httpx (Binance client; no
33
+ python-binance). plotly (chart HTML via fig.write_html).
34
+ - sqlite3 via a thin hand-rolled store (no SQLAlchemy, no migrations;
35
+ CREATE TABLE IF NOT EXISTS on startup). LangGraph checkpoints live in their
36
+ own sqlite file via SqliteSaver.
37
+ - pytest; engine and paper-run logic tested with fixture bars, deterministic,
38
+ no network.
39
+
40
+ No Celery, Redis, MySQL, FastAPI, or frontend framework. Single process, single
41
+ user, local files.
42
+
43
+ ## Domain decisions
44
+
45
+ - Symbols: Binance spot (BTCUSDT, ETHUSDT, SOLUSDT, ...). Validated against a
46
+ cached GET /api/v3/exchangeInfo symbol set; unknown symbols fail loudly with
47
+ suggestions.
48
+ - Intervals (Binance strings, canonical): 15m, 1h, 4h, 1d. bars_per_year:
49
+ 15m=35040, 1h=8760, 4h=2190, 1d=365 (crypto trades 24/7/365).
50
+ - The still-forming bar is always dropped: only closed bars enter the engine,
51
+ paper runner, or charts.
52
+ - Bar contract everywhere: `{ts, open, high, low, close, volume}` with ts an ISO
53
+ UTC string.
54
+ - Binance client: public keyless, base https://api.binance.com. klines
55
+ (limit 1000, paginate by startTime), ticker for quotes, exchangeInfo for
56
+ validation (cached 24h). In-process TTL caches (quote 30s, klines 60s). Retry
57
+ twice with backoff; HTTP errors surfaced verbatim.
58
+ - Engine: long/flat only, next-bar fill, cost_bps wired but default 0. Metrics:
59
+ CAGR, Sharpe, max drawdown, win rate, trade count.
60
+ - Paper runs: the first fill is on the first bar that CLOSES after creation (no
61
+ backdated fills). Advancing replays all closed bars since the last processed
62
+ bar, one signal eval per bar; the already-processed-ts guard is the only
63
+ cadence control. Fills are fractional and fully allocated. Default starting
64
+ cash 10000 USDT.
65
+
66
+ ## Layout
67
+
68
+ ```
69
+ src/backtestchat/
70
+ cli.py typer app: chat, runs, show, config
71
+ config.py env > ./backtestchat.toml > defaults
72
+ artifacts.py rendered-artifact resolution (last/newest/path)
73
+ agent/ graph.py, tools.py, prompt.py, context.py, chat.py
74
+ broker/ base.py (interface, window logic), binance.py (httpx client)
75
+ strategy/ registry.py, signals.py, indicators.py, engine.py
76
+ paper/ runner.py (replay), store.py (sqlite)
77
+ render/ widgets.py (dict builders), plotly_render.py (HTML)
78
+ tests/ fixtures/, test_engine.py, test_registry.py, ...
79
+ ```
80
+
81
+ `./data` (sqlite store + LangGraph checkpoints) and `./artifacts` (chart HTML)
82
+ are created at runtime and gitignored.
83
+
84
+ ## Scope and roadmap
85
+
86
+ Intentionally in scope: paper-only simulation, keyless data, the 10 agent tools
87
+ (get_quote, get_price_series, list_strategies, run_backtest, compare_strategies,
88
+ save_strategy, list_saved_strategies, start_paper_run, list_paper_runs,
89
+ stop_paper_run), and the ported strategy catalog.
90
+
91
+ Deliberately out of scope (a clean adapter/extension, not yet built): Binance
92
+ testnet order routing (the Broker interface is designed to make this an adapter
93
+ add), a news-signal tool, web/FastAPI/TUI charts, live streaming / alerts /
94
+ daemons, portfolio / multi-asset / shorting / position sizing / leverage, and
95
+ new strategies beyond the catalog. Propose these as additions rather than
96
+ assuming they belong in the core.
97
+
98
+ ## Build and test
99
+
100
+ ```
101
+ uv sync
102
+ uv run pytest -q # deterministic, no network, no model key
103
+ ```
104
+
105
+ The engine, signals, broker window logic, and paper runner are pure and tested
106
+ against fixture bars; the market-data and agent layers use mocked HTTP and a
107
+ scripted fake model, so the whole suite runs offline.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Baris Arat
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.
@@ -0,0 +1,198 @@
1
+ Metadata-Version: 2.4
2
+ Name: backtestchat
3
+ Version: 0.1.0
4
+ Summary: Local-first agentic strategy lab CLI: chat, backtest, and paper-trade long/flat strategies on keyless Binance public data.
5
+ Project-URL: Homepage, https://github.com/barisarat/backtestchat
6
+ Project-URL: Repository, https://github.com/barisarat/backtestchat
7
+ Project-URL: Issues, https://github.com/barisarat/backtestchat/issues
8
+ Author: Baris Arat
9
+ License: MIT
10
+ License-File: LICENSE
11
+ Keywords: agent,backtest,binance,cli,langgraph,paper-trading,trading
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Environment :: Console
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: License :: OSI Approved :: MIT License
16
+ Classifier: Programming Language :: Python :: 3.12
17
+ Classifier: Topic :: Office/Business :: Financial :: Investment
18
+ Classifier: Topic :: Scientific/Engineering
19
+ Requires-Python: >=3.12
20
+ Requires-Dist: httpx>=0.27.0
21
+ Requires-Dist: langchain-core>=0.3.0
22
+ Requires-Dist: langchain>=0.3.0
23
+ Requires-Dist: langgraph-checkpoint-sqlite>=2.0.0
24
+ Requires-Dist: langgraph>=0.2.60
25
+ Requires-Dist: plotly>=5.22.0
26
+ Requires-Dist: rich>=13.7.0
27
+ Requires-Dist: typer>=0.12.0
28
+ Provides-Extra: anthropic
29
+ Requires-Dist: langchain-anthropic>=0.2.0; extra == 'anthropic'
30
+ Provides-Extra: ollama
31
+ Requires-Dist: langchain-ollama>=0.2.0; extra == 'ollama'
32
+ Provides-Extra: openai
33
+ Requires-Dist: langchain-openai>=0.2.0; extra == 'openai'
34
+ Description-Content-Type: text/markdown
35
+
36
+ # backtestchat
37
+
38
+ An open-source, local-first agentic strategy lab in your terminal. Chat with a
39
+ LangGraph agent to fetch keyless Binance public market data, design and backtest
40
+ long/flat crypto strategies, and run simulated paper trades. Charts render to
41
+ self-contained plotly HTML that opens in your browser.
42
+
43
+ **Paper-only by design.** backtestchat simulates fills from closed bars. It never
44
+ places real orders and never needs exchange API keys. Market data comes from the
45
+ public, keyless Binance REST API. The only key you supply is your own model
46
+ (BYOK) key, or a local Ollama endpoint.
47
+
48
+ > backtestchat is a research and simulation tool and a portfolio/learning project.
49
+ > It is not financial advice and not a trading product. Do not use it to make
50
+ > investment decisions.
51
+
52
+ <!-- TODO: asciinema GIF of a chat session (quote -> backtest -> chart). -->
53
+ <!-- TODO: screenshot of a backtestReport chart. -->
54
+
55
+ ## Quickstart
56
+
57
+ Requires Python 3.12+ and [uv](https://docs.astral.sh/uv/).
58
+
59
+ ```bash
60
+ git clone https://github.com/barisarat/backtestchat
61
+ cd backtestchat
62
+ uv sync --extra openai # deps + the OpenAI model provider
63
+
64
+ export BACKTESTCHAT_MODEL=openai:gpt-5.4-nano
65
+ export OPENAI_API_KEY=sk-...
66
+
67
+ uv run backtestchat chat # talk to the agent
68
+ uv run backtestchat runs sync # advance paper runs to the latest closed bar
69
+ uv run backtestchat runs list # check paper run status
70
+ ```
71
+
72
+ Two things to know:
73
+
74
+ - The `backtestchat` command lives in the project venv, so either prefix every
75
+ command with `uv run`, or activate the venv once with
76
+ `source .venv/bin/activate` and call `backtestchat` directly.
77
+ - Always sync with the extra for the provider you use. A plain `uv sync`
78
+ removes extras, and `backtestchat chat` will fail until you
79
+ `uv sync --extra openai` again.
80
+
81
+ Market data works with **zero keys**; only the chat agent needs a model key.
82
+ Other providers (Anthropic, Ollama, ...) are covered under
83
+ [Model setup](#model-setup-byok).
84
+
85
+ ## What it does
86
+
87
+ - **Chat** with a tool-calling agent (LangGraph) that maps your plain-English
88
+ requests onto market-data, backtest, and paper-trade actions.
89
+ - **Backtest** ~11 single-signal long/flat strategies (SMA/EMA crossover, MACD,
90
+ RSI, Bollinger, Donchian, ROC, stochastic, ATR channel, price-vs-SMA,
91
+ buy & hold) with CAGR, Sharpe, max drawdown, win rate, and trade count.
92
+ - **Compare** several strategies at once, ranked, on one chart.
93
+ - **Paper-trade** a strategy with simulated fills. Runs advance by replaying
94
+ closed bars - no daemon, no scheduler. Any command can trigger a cheap sync.
95
+ - **Charts** are deterministic plotly HTML written to `./artifacts`. The model
96
+ never writes HTML; it only triggers the tools that build the charts.
97
+
98
+ Supported intervals: **15m, 1h, 4h, 1d**. Symbols: any Binance spot pair
99
+ (BTCUSDT, ETHUSDT, SOLUSDT, XRPUSDT, DOGEUSDT, ...).
100
+
101
+ ## Model setup (BYOK)
102
+
103
+ backtestchat talks to any provider via LangChain's `init_chat_model`, configured with
104
+ a `provider:model` string in `BACKTESTCHAT_MODEL` (or `model = "..."` in
105
+ `./backtestchat.toml`). The default setup uses OpenAI:
106
+
107
+ ```bash
108
+ uv sync --extra openai
109
+ export BACKTESTCHAT_MODEL=openai:gpt-5.4-nano
110
+ export OPENAI_API_KEY=sk-...
111
+ ```
112
+
113
+ Any provider `init_chat_model` supports works the same way: install the matching
114
+ extra (`--extra anthropic`, `--extra ollama`, ...) and set `BACKTESTCHAT_MODEL` to
115
+ that provider's `provider:model` string plus its API key (Ollama runs locally
116
+ and needs no key).
117
+
118
+ If no model is configured, `backtestchat chat` prints these instructions and exits.
119
+ Check what is resolved with `backtestchat config`.
120
+
121
+ ## Usage
122
+
123
+ ```bash
124
+ uv run backtestchat chat
125
+ ```
126
+
127
+ Then talk to it naturally:
128
+
129
+ ```
130
+ you > what's BTC trading at?
131
+ you > backtest an ma crossover 20/50 on BTCUSDT 1h over the last 3 months
132
+ you > compare that against buy and hold and rsi
133
+ you > save that strategy # asks you to confirm in the terminal
134
+ you > start a paper run with 5000 usdt # asks you to confirm
135
+ you > list my paper runs
136
+ ```
137
+
138
+ Charts open automatically in your browser and are saved under `./artifacts`.
139
+ Saving a strategy and starting a paper run pause for a y/n confirmation
140
+ (human-in-the-loop, implemented with LangGraph interrupts).
141
+
142
+ ### Commands
143
+
144
+ ```bash
145
+ backtestchat chat [--new] [--thread ID] # agent REPL (resumes the last thread by default)
146
+ backtestchat runs list [--status active] # list paper runs (stored state)
147
+ backtestchat runs sync # advance all active runs to the latest closed bar
148
+ backtestchat show [last|FILE] # open a rendered chart artifact
149
+ backtestchat config # print resolved configuration
150
+ ```
151
+
152
+ ### How paper runs work
153
+
154
+ A paper run does not backdate: the first simulated fill happens on the first bar
155
+ that **closes after** you create the run, so a fresh run shows
156
+ "waiting for first tick" until then. Advancing a run replays every closed bar
157
+ since its last processed bar, one signal evaluation per bar. Because the
158
+ already-processed-bar guard is the only cadence control, `backtestchat runs sync` is
159
+ safe to run anytime and is idempotent.
160
+
161
+ ## LangSmith tracing (optional)
162
+
163
+ Set the standard env vars and traces appear in your LangSmith project - no code
164
+ or flags required:
165
+
166
+ ```bash
167
+ export LANGSMITH_TRACING=true
168
+ export LANGSMITH_API_KEY=...
169
+ ```
170
+
171
+ ## Configuration
172
+
173
+ Resolved in order: environment variables > `./backtestchat.toml` > defaults.
174
+
175
+ | Key | Env var | Default |
176
+ |---|---|---|
177
+ | model | `BACKTESTCHAT_MODEL` | (unset; required for chat) |
178
+ | data dir | `BACKTESTCHAT_DATA_DIR` | `./data` |
179
+ | artifacts dir | `BACKTESTCHAT_ARTIFACTS_DIR` | `./artifacts` |
180
+
181
+ `./data` holds the sqlite store (strategies, paper runs, trades) and the
182
+ LangGraph checkpoint database. `./artifacts` holds rendered chart HTML. Both are
183
+ gitignored.
184
+
185
+ ## Development
186
+
187
+ ```bash
188
+ uv sync --extra openai # dev dependencies included; keep your provider extra
189
+ uv run pytest -q # deterministic, no network, no model key
190
+ ```
191
+
192
+ The engine, signals, broker window logic, and paper runner are pure and tested
193
+ against fixture bars. Market-data and agent layers are tested with mocked HTTP
194
+ and a scripted fake model, so the whole suite runs offline.
195
+
196
+ ## License
197
+
198
+ MIT - see [LICENSE](LICENSE).
@@ -0,0 +1,163 @@
1
+ # backtestchat
2
+
3
+ An open-source, local-first agentic strategy lab in your terminal. Chat with a
4
+ LangGraph agent to fetch keyless Binance public market data, design and backtest
5
+ long/flat crypto strategies, and run simulated paper trades. Charts render to
6
+ self-contained plotly HTML that opens in your browser.
7
+
8
+ **Paper-only by design.** backtestchat simulates fills from closed bars. It never
9
+ places real orders and never needs exchange API keys. Market data comes from the
10
+ public, keyless Binance REST API. The only key you supply is your own model
11
+ (BYOK) key, or a local Ollama endpoint.
12
+
13
+ > backtestchat is a research and simulation tool and a portfolio/learning project.
14
+ > It is not financial advice and not a trading product. Do not use it to make
15
+ > investment decisions.
16
+
17
+ <!-- TODO: asciinema GIF of a chat session (quote -> backtest -> chart). -->
18
+ <!-- TODO: screenshot of a backtestReport chart. -->
19
+
20
+ ## Quickstart
21
+
22
+ Requires Python 3.12+ and [uv](https://docs.astral.sh/uv/).
23
+
24
+ ```bash
25
+ git clone https://github.com/barisarat/backtestchat
26
+ cd backtestchat
27
+ uv sync --extra openai # deps + the OpenAI model provider
28
+
29
+ export BACKTESTCHAT_MODEL=openai:gpt-5.4-nano
30
+ export OPENAI_API_KEY=sk-...
31
+
32
+ uv run backtestchat chat # talk to the agent
33
+ uv run backtestchat runs sync # advance paper runs to the latest closed bar
34
+ uv run backtestchat runs list # check paper run status
35
+ ```
36
+
37
+ Two things to know:
38
+
39
+ - The `backtestchat` command lives in the project venv, so either prefix every
40
+ command with `uv run`, or activate the venv once with
41
+ `source .venv/bin/activate` and call `backtestchat` directly.
42
+ - Always sync with the extra for the provider you use. A plain `uv sync`
43
+ removes extras, and `backtestchat chat` will fail until you
44
+ `uv sync --extra openai` again.
45
+
46
+ Market data works with **zero keys**; only the chat agent needs a model key.
47
+ Other providers (Anthropic, Ollama, ...) are covered under
48
+ [Model setup](#model-setup-byok).
49
+
50
+ ## What it does
51
+
52
+ - **Chat** with a tool-calling agent (LangGraph) that maps your plain-English
53
+ requests onto market-data, backtest, and paper-trade actions.
54
+ - **Backtest** ~11 single-signal long/flat strategies (SMA/EMA crossover, MACD,
55
+ RSI, Bollinger, Donchian, ROC, stochastic, ATR channel, price-vs-SMA,
56
+ buy & hold) with CAGR, Sharpe, max drawdown, win rate, and trade count.
57
+ - **Compare** several strategies at once, ranked, on one chart.
58
+ - **Paper-trade** a strategy with simulated fills. Runs advance by replaying
59
+ closed bars - no daemon, no scheduler. Any command can trigger a cheap sync.
60
+ - **Charts** are deterministic plotly HTML written to `./artifacts`. The model
61
+ never writes HTML; it only triggers the tools that build the charts.
62
+
63
+ Supported intervals: **15m, 1h, 4h, 1d**. Symbols: any Binance spot pair
64
+ (BTCUSDT, ETHUSDT, SOLUSDT, XRPUSDT, DOGEUSDT, ...).
65
+
66
+ ## Model setup (BYOK)
67
+
68
+ backtestchat talks to any provider via LangChain's `init_chat_model`, configured with
69
+ a `provider:model` string in `BACKTESTCHAT_MODEL` (or `model = "..."` in
70
+ `./backtestchat.toml`). The default setup uses OpenAI:
71
+
72
+ ```bash
73
+ uv sync --extra openai
74
+ export BACKTESTCHAT_MODEL=openai:gpt-5.4-nano
75
+ export OPENAI_API_KEY=sk-...
76
+ ```
77
+
78
+ Any provider `init_chat_model` supports works the same way: install the matching
79
+ extra (`--extra anthropic`, `--extra ollama`, ...) and set `BACKTESTCHAT_MODEL` to
80
+ that provider's `provider:model` string plus its API key (Ollama runs locally
81
+ and needs no key).
82
+
83
+ If no model is configured, `backtestchat chat` prints these instructions and exits.
84
+ Check what is resolved with `backtestchat config`.
85
+
86
+ ## Usage
87
+
88
+ ```bash
89
+ uv run backtestchat chat
90
+ ```
91
+
92
+ Then talk to it naturally:
93
+
94
+ ```
95
+ you > what's BTC trading at?
96
+ you > backtest an ma crossover 20/50 on BTCUSDT 1h over the last 3 months
97
+ you > compare that against buy and hold and rsi
98
+ you > save that strategy # asks you to confirm in the terminal
99
+ you > start a paper run with 5000 usdt # asks you to confirm
100
+ you > list my paper runs
101
+ ```
102
+
103
+ Charts open automatically in your browser and are saved under `./artifacts`.
104
+ Saving a strategy and starting a paper run pause for a y/n confirmation
105
+ (human-in-the-loop, implemented with LangGraph interrupts).
106
+
107
+ ### Commands
108
+
109
+ ```bash
110
+ backtestchat chat [--new] [--thread ID] # agent REPL (resumes the last thread by default)
111
+ backtestchat runs list [--status active] # list paper runs (stored state)
112
+ backtestchat runs sync # advance all active runs to the latest closed bar
113
+ backtestchat show [last|FILE] # open a rendered chart artifact
114
+ backtestchat config # print resolved configuration
115
+ ```
116
+
117
+ ### How paper runs work
118
+
119
+ A paper run does not backdate: the first simulated fill happens on the first bar
120
+ that **closes after** you create the run, so a fresh run shows
121
+ "waiting for first tick" until then. Advancing a run replays every closed bar
122
+ since its last processed bar, one signal evaluation per bar. Because the
123
+ already-processed-bar guard is the only cadence control, `backtestchat runs sync` is
124
+ safe to run anytime and is idempotent.
125
+
126
+ ## LangSmith tracing (optional)
127
+
128
+ Set the standard env vars and traces appear in your LangSmith project - no code
129
+ or flags required:
130
+
131
+ ```bash
132
+ export LANGSMITH_TRACING=true
133
+ export LANGSMITH_API_KEY=...
134
+ ```
135
+
136
+ ## Configuration
137
+
138
+ Resolved in order: environment variables > `./backtestchat.toml` > defaults.
139
+
140
+ | Key | Env var | Default |
141
+ |---|---|---|
142
+ | model | `BACKTESTCHAT_MODEL` | (unset; required for chat) |
143
+ | data dir | `BACKTESTCHAT_DATA_DIR` | `./data` |
144
+ | artifacts dir | `BACKTESTCHAT_ARTIFACTS_DIR` | `./artifacts` |
145
+
146
+ `./data` holds the sqlite store (strategies, paper runs, trades) and the
147
+ LangGraph checkpoint database. `./artifacts` holds rendered chart HTML. Both are
148
+ gitignored.
149
+
150
+ ## Development
151
+
152
+ ```bash
153
+ uv sync --extra openai # dev dependencies included; keep your provider extra
154
+ uv run pytest -q # deterministic, no network, no model key
155
+ ```
156
+
157
+ The engine, signals, broker window logic, and paper runner are pure and tested
158
+ against fixture bars. Market-data and agent layers are tested with mocked HTTP
159
+ and a scripted fake model, so the whole suite runs offline.
160
+
161
+ ## License
162
+
163
+ MIT - see [LICENSE](LICENSE).
@@ -0,0 +1,61 @@
1
+ [project]
2
+ name = "backtestchat"
3
+ version = "0.1.0"
4
+ description = "Local-first agentic strategy lab CLI: chat, backtest, and paper-trade long/flat strategies on keyless Binance public data."
5
+ readme = "README.md"
6
+ requires-python = ">=3.12"
7
+ license = { text = "MIT" }
8
+ license-files = ["LICENSE"]
9
+ authors = [{ name = "Baris Arat" }]
10
+ keywords = ["langgraph", "trading", "backtest", "paper-trading", "binance", "agent", "cli"]
11
+ classifiers = [
12
+ "Development Status :: 4 - Beta",
13
+ "Environment :: Console",
14
+ "Intended Audience :: Developers",
15
+ "License :: OSI Approved :: MIT License",
16
+ "Programming Language :: Python :: 3.12",
17
+ "Topic :: Office/Business :: Financial :: Investment",
18
+ "Topic :: Scientific/Engineering",
19
+ ]
20
+
21
+ dependencies = [
22
+ "langgraph>=0.2.60",
23
+ "langgraph-checkpoint-sqlite>=2.0.0",
24
+ "langchain>=0.3.0",
25
+ "langchain-core>=0.3.0",
26
+ "typer>=0.12.0",
27
+ "rich>=13.7.0",
28
+ "httpx>=0.27.0",
29
+ "plotly>=5.22.0",
30
+ ]
31
+
32
+ [project.optional-dependencies]
33
+ openai = ["langchain-openai>=0.2.0"]
34
+ anthropic = ["langchain-anthropic>=0.2.0"]
35
+ ollama = ["langchain-ollama>=0.2.0"]
36
+
37
+ [project.scripts]
38
+ backtestchat = "backtestchat.cli:app"
39
+ btchat = "backtestchat.cli:app"
40
+
41
+ [project.urls]
42
+ Homepage = "https://github.com/barisarat/backtestchat"
43
+ Repository = "https://github.com/barisarat/backtestchat"
44
+ Issues = "https://github.com/barisarat/backtestchat/issues"
45
+
46
+ [dependency-groups]
47
+ dev = [
48
+ "pytest>=8.2.0",
49
+ "respx>=0.21.0",
50
+ ]
51
+
52
+ [build-system]
53
+ requires = ["hatchling"]
54
+ build-backend = "hatchling.build"
55
+
56
+ [tool.hatch.build.targets.wheel]
57
+ packages = ["src/backtestchat"]
58
+
59
+ [tool.pytest.ini_options]
60
+ testpaths = ["tests"]
61
+ addopts = "-q"
@@ -0,0 +1,8 @@
1
+ """backtestchat: a local-first agentic strategy lab CLI.
2
+
3
+ Chat with a LangGraph agent to fetch keyless Binance public market data,
4
+ backtest long/flat strategies, and run simulated paper trades. Paper-only by
5
+ design: no exchange keys, no real orders.
6
+ """
7
+
8
+ __version__ = "0.1.0"
@@ -0,0 +1,6 @@
1
+ """Enable `python -m backtestchat`."""
2
+
3
+ from backtestchat.cli import app
4
+
5
+ if __name__ == "__main__":
6
+ app()