state.json / journal.jsonl / breaker.json are per-process runtime state and
journal.jsonl can carry account data — never commit them. research/data,
research/models and research/reports are regenerable pipeline outputs.
Co-Authored-By: Claude Code <noreply@anthropic.com>
Root README now points at the auto-trading shell and research pipeline;
AGENTS.md gains a keep-docs-in-sync rule; trading/README.md maps every method
from the two research docs to trading/risk and documents manage_position;
research/README.md documents the backtest hook and --backtest CLI.
Co-Authored-By: Claude Code <noreply@anthropic.com>
research/ now runs end-to-end (fetch -> features/labels -> walk-forward ->
train -> OOS evaluate -> save), and backtest_strategy() replays the same
signal(ctx) strategy over a historical frame with the same manage_position
hook the live loop calls, simulating SL/TP, trailing, partial closes and cost
per bar. --backtest wires it into the CLI.
Co-Authored-By: Claude Code <noreply@anthropic.com>
The loop sizes entry volume by risk percent when a strategy leaves volume None
(returning to TRADING_MAX_LOTS when the broker spec or stop geometry is
missing), and gains a position-management pass that runs the strategy's
manage_position(ctx, position) hook before any new entry — executing modify /
close / partial_close through the dry-run-layered Executor. PositionAction is
the shared contract.
Co-Authored-By: Claude Code <noreply@anthropic.com>
A Strategy subclass in trading/strategies/ with params_spec + signal(ctx) is now
auto-discovered by the registry (name or module path), parameterized via
TRADING_STRATEGY_PARAMS, and loadable without touching the loop or CLI. Ships
ma_cross and model_threshold; legacy bare signal(ctx) modules keep working via
FunctionStrategy.
Co-Authored-By: Claude Code <noreply@anthropic.com>
Moves the stop-loss and position-sizing research docs into a reusable
trading.risk package (broker / sizing / exits / guards / indicators), keeping
the docs' invariants: R frozen at entry, monotonic tightening, broker-precision
rounding, and all entry gates default-OFF behind TRADING_GUARD_*.
Co-Authored-By: Claude Code <noreply@anthropic.com>
Operator-facing pre-flight gate before real orders: MTDATA_TRADE_*
guardrail inventory with defaults, idempotency, dry-run rehearsal
(verified CLI tokens only), first-size orders and incident response.
Indexed in the README trading table.
Co-Authored-By: Claude Code <noreply@anthropic.com>
Polling signal loop with a state machine, circuit breaker, layered
dry-run execution (subprocess mtdata-cli trade_*) and a JSONL journal.
The default strategy emits no signal, so the loop is safe to run as-is;
orders never reach the broker until a strategy and the live tier are
explicitly wired up.
Co-Authored-By: Claude Code <noreply@anthropic.com>
Recreate the missing root README.md (pyproject.toml declares
readme = "README.md", so packaging failed without it) as an English
landing page linking to docs/, README_CN.md, and 指标列表.md. All CLI
examples were verified against the runtime tool catalog and pass
tests/core/cli/test_cli_docs.py.
Also fix a 194 -> 193 typo in README_CN.md so the indicator count
matches the runtime pandas-ta-classic catalog and 指标列表.md.
Co-Authored-By: Claude Code <noreply@anthropic.com>
Map stale position quotes to tickets, warn on null tick spreads, and surface scan skip reasons plus bar-vs-live direction divergence so compact output can be acted on without a second full-detail call.
Only match position_opened from DEAL_ENTRY_IN when the ticket is still open and was not already in the wait baseline, so closed fills cannot wake the watcher.
llama.cpp drops unanchored pattern constraints and PCRE shorthands such
as \S, which produced incomplete grammar conversion warnings. Use
anchored, hex-escaped whitespace classes instead.
Wait-event market watchers now keep tick history for the window and attach the executable quote when the archive lags, using a spread/tick/relative agreement band that works for FX, crypto, and stocks.
Pattern detection had two recurring defects: a fallback that quietly
substituted different data than the caller asked for, and metadata that
asserted a point-in-time or guarantee the computation could not support.
Data substitution:
- Denoising on the classic/harmonic/elliott/fractal path smoothed only
`close`, so the smoothed close routinely fell outside its own raw candle
and ~68% of rows were reverted to raw -- preferentially at the local
extremes pivot detection keys on. Require the full OHLC set, matching the
candlestick path, and reject an explicitly partial column list.
- A failed denoise still echoed the requested spec with
`preprocessing_causality: "causal"`. Report `denoise_applied: false`,
`denoise_error` and `preprocessing_causality: "raw_prices"` instead.
- One non-finite OHLC value makes the aggregate candlestick dispatcher
throw, leaving only the few directly-attached detectors. The failure was
unrecorded because `dispatch_names` is the string "all", not a list. Add a
`detector_coverage` block plus a warning, and surface names the installed
backend does not provide (`outside` is absent from pandas-ta-classic).
Untrue claims:
- Elliott `available_at_index` was 67% irreproducible when re-running over a
window truncated at that index, because pivot spacing and (under the
default `scale_mode="auto"`) the swing scale are whole-window statistics.
Report the right edge as the guarantee and demote the confirmation-derived
figure to `earliest_possible_index_estimate` with a caveat, matching the
harmonic contract. Also track when a min-distance choice was settled so a
pivot surviving a later challenge is not claimed knowable at its own bar.
- The "no patterns detected in N bars" note omitted `observed_bars` outside
candlestick mode, asserting absence over bars never fetched.
- `df.attrs["pattern_ohlc_fallback"]` was written for the API layer to
disclose and never read, and was written after a slice so it could not
reach the caller. Wire it into warnings and report `analyzed_bars` when a
detector caps its own input window.
- `data_freshness` emitted the literal string "None", which is truthy and
then broke the year parse that would have raised a staleness warning.
Silent no-ops and misattribution:
- The documented `mode="all"` namespacing (`{"harmonic": {...}}`) reported
the section name as an invalid key and failed the fractal and harmonic
sections. Validate a section's contents against that detector, and
attribute an unknown top-level key to every detector that could own it
rather than only fractal and harmonic.
- `detail="summary"` dropped `warnings`, `data_quality`, `candles` and
`effective_window` -- exactly the fields that say not to trust a result.
- `min_strength`, `min_gap` and `robust_only` were accepted and ignored
outside candlestick mode; reject a non-default value like the adjacent
`engine` and `whitelist` guards do.
- Fractal `include_stale_levels` was discarded by the visibility allowlist
unless `include_completed` was also set, and stale rows were hidden
without being counted.
- Six Elliott config knobs were unread: the four rule/classifier blend
weights (no blend exists; an existing test pinned that) and two additive
unconfirmed-pattern penalties superseded by the confidence cap. Remove
them so they become explicit unknown-key errors.
Scoring correctness:
- Candlestick geometry keyed its body-size expectation off the deprioritize
set, so hammers, shooting stars and harami were scored as if a large body
confirmed them, while marubozu was scored as if a small one did. Classify
the expectation per pattern.
- A zero-range bar scored `body_ratio = 0.5` ("unknown"), making a perfect
doji rank below an imperfect one; it has a zero body by construction.
- `min_gap` spaced candidates selected at threshold 0.0, so a weak hit could
consume the slot and erase a qualifying signal one bar away. Space among
rows that meet `min_strength`.
- `inside` was signed by candle colour, contradicting the harami detected on
the identical bars and defeating the dedupe that exists to replace it.
Report it as non-directional and let the specific form suppress it.
- A hikkake confirmation bar (magnitude 200) was given the three-bar setup
span, putting `start_index` inside the setup.
- Candlestick `recency` used the reported bar count while `end_index` indexes
the warmup-inclusive frame, clamping `bars_ago` to 0 for every pattern in
the warmup span and biasing the cross-detector ranking.
- Volume-confirmation warmup ignored pattern span, so a multi-bar pattern on
the first visible bar had a short baseline.
Verified: ruff clean, 10115 backend tests pass, schemas 83/83.
Co-authored-by: Cursor <cursoragent@cursor.com>
TP/SL distances are measured from the entry quote while simulated paths are
scored from the exit quote, so a barrier inside the spread was already crossed
before the first simulated bar. Neither close comparisons nor the Brownian
bridge could observe it, and both tools reported ordinary-looking probabilities
for a position that would resolve instantly.
The minimum barrier distance used the payoff deduction, which excludes spread
when live quotes embed it in path geometry, so the round-trip cost floor
silently dropped spread exactly when it mattered most.
Antithetic paths are mirrored pairs, so p(1-p)/n misstated sampling error in
both directions: too narrow for prob_no_hit, too wide for monotone first-hit
probabilities. Each Wilson interval is now sized by its own design effect.
Independent-seed and walk-forward evidence can close the trade gate instead of
only reporting optimism, and cross-seed stability now separates estimator noise
from selection churn rather than blaming simulation size for a missing edge.
Also disclose the implicit min_prob_resolve floor and the realized-payoff
profit_factor basis, reject mode-mismatched min_barrier_* keys instead of
ignoring them, and fix the labeling history guard, the silent high_low fallback
to close-only detection, and the inert same_bar_policy in close-only mode.
Co-authored-by: Cursor <cursoragent@cursor.com>
Add unit=pips via forex_pip_size while keeping ticks as broker tick/point. Rename labels_triple_barrier --barriers to --barrier with no alias, and default forecast_barrier_optimize to mc_gbm_bb to match forecast_barrier_prob.
Keep compact unit on volatility_term_structure and explain that 0.0465 decimal times 100 is percent-points for labels_triple_barrier and forecast_barrier_prob.
When forecast_task_status finds model_store_status other than present, rewrite the completion message and set model_reusable false so expired or deleted artifacts are not advertised as reusable.
Key option_chain_quality on missing quote timestamps even when last-trade contract_as_of exists, point remediation at Tradier configuration, and name MTDATA_OPTIONS_PROVIDER/MTDATA_OPTIONS_API_KEY in Heston rejection copy. Anonymous Yahoo status stays ready_degraded.
Close-only pre-TI denoise was feeding smoothed close into RSI while leaving the column named rsi_14. Rename those columns whenever the indicator input was denoised, emit indicator_column_suffix only after a rename, and keep indicator_input on compact output.
Document compact options_expirations default of 12 and has_more, map barrier risk_free_rate/dividend_yield to r/q (FX q as foreign/base), and say top-markets time follows data_source.
Emit execution_not_ready or optimizer_non_viable instead of quote_not_live when the quote is live, and skip freshness_unverified when stress-test marks are not_applicable.
Pass compacted quote_context, sl_tp_error, and validation_error through compact TOON, keep lookback_bars on support_resistance, and label candidate risk_currency as account_currency.