This project is paper-only.
- Paper-only execution only.
- Correct Bitfinex paper symbol is
tTESTBTC:TESTUSD. - Do not use
tBTCUSDfor paper execution. - Do not commit
.env. - Do not expose your
SUPABASE_SERVICE_ROLE_KEYorBITFINEX_API_SECRET. - The local runner refuses to start unless
PAPER_MODE=true.
.env.example— example local environment variablesrequirements.txt— Python dependenciesmarket_data_ingester.py— fetches Bitfinex candles into Supabasesignal_generator.py— creates deterministic buy signals from recent candlesrunner.py— executes Bitfinex paper orders from queued signalsorderbook_liquidity_ingester.py— fetches Bitfinex orderbook and stores snapshot + liquidity metricsai_market_watcher.py— asks an AI for BUY/SELL/HOLD based on candles, orderbook, and liquidity
- Create
.envfrom.env.example - Install dependencies:
pip install -r requirements.txt
- terminal 1:
python market_data_ingester.py - terminal 2:
python signal_generator.py - terminal 3:
python runner.py - optional terminal 4:
python orderbook_liquidity_ingester.py - optional terminal 5:
python ai_market_watcher.py
Use scenario_probe.py when you want to see the full AI decision and reflection loop without making the live agent more aggressive.
- Default mode is audit-only:
python scenario_probe.py - Run one scenario:
python scenario_probe.py --scenario bullish_breakout_probe - Skip synthetic reflections:
python scenario_probe.py --no-reflection - Queue at most one paper signal for BUY/SELL probe decisions:
python scenario_probe.py --queue-paper-signal --max-paper-signals 1
Probe events are logged separately as ai_market_scenario_probe and ai_market_scenario_probe_reflection.
The live watcher and scenario probes share the same AI decision policy: BUY and SELL mean queue-worthy short-term directional intent, while HOLD is the active decision for mixed or trap-like setups. Heavy ask-side pressure, widening spread, or weak volume after a small price pop should be treated as a liquidity-trap HOLD unless there is clear downside continuation evidence.
Use experiment_report.py to read Supabase audit data back into a compact report.
- Markdown report for the current
.envexperiment:python experiment_report.py - JSON report:
python experiment_report.py --format json - Explicit experiment:
python experiment_report.py --experiment-id exp_2026_05_25_a - Write to a file:
python experiment_report.py --output experiment_report.md
Run these before a live paper session when changing prompts, models, or API mode:
- Contract and schema checks without API calls:
python tests/openai_contract_check.py - Retry/backoff checks without API calls:
python tests/openai_retry_check.py - Scenario regression with the default API mode:
python scenario_probe.py --no-reflection - Scenario regression with Responses API:
powershell -Command "$env:AI_API_MODE='responses'; python scenario_probe.py --scenario liquidity_trap_probe --no-reflection"
Bitfinex candles → market_candles → signal_generator → agent_signals → runner → Bitfinex paper → paper_orders + audit log
AI watcher inputs → market_candles + orderbook snapshot + liquidity metrics → ai_market_watcher.py → agent_audit_log
Orderbook flow → Bitfinex book → orderbook_liquidity_ingester.py → orderbook_snapshots + liquidity_metrics
Research and experiment tracking are intentionally separate.
- Research notes describe a small hypothesis, assumptions, and expected failure modes.
- Experiment runs describe a concrete run with a mode, config, status, and optional link to a research note.
- Runtime scripts add
RESEARCH_KEY,EXPERIMENT_ID, andEXPERIMENT_MODEto audit payloads and signal/order metadata. - Run
sql/research_experiment_tables.sqlin Supabase SQL editor before relying on the tracking tables. - Keep research lightweight; use it to frame the run, not to block iteration.
SUPABASE_URL=
SUPABASE_SERVICE_ROLE_KEY=
BITFINEX_API_KEY=
BITFINEX_API_SECRET=
PAPER_MODE=true
RESEARCH_KEY=
EXPERIMENT_ID=
EXPERIMENT_MODE=observe_only
SYMBOL=tTESTBTC:TESTUSD
TIMEFRAME=1m
RUNNER_POLL_SECONDS=5
DEFAULT_ORDER_AMOUNT=0.0001
MARKET_DATA_POLL_SECONDS=30
SIGNAL_POLL_SECONDS=30
AI_API_URL=https://api.openai.com/v1/chat/completions
AI_RESPONSES_API_URL=https://api.openai.com/v1/responses
AI_API_MODE=chat_completions
AI_API_KEY=
AI_MODEL=gpt-4o-mini
AI_DECISION_MODEL=
AI_REFLECTION_MODEL=
AI_POLL_SECONDS=30
AI_REQUEST_TIMEOUT_SECONDS=20
AI_REQUEST_MAX_ATTEMPTS=2
AI_REQUEST_BACKOFF_SECONDS=2
AI_DECISION_MAX_OUTPUT_TOKENS=900
AI_REFLECTION_MAX_OUTPUT_TOKENS=700
AI_REVIEW_DELAY_SECONDS=120
AI_REVIEW_SCAN_LIMIT=50
AI_REFLECTION_SCAN_LIMIT=20
AI_REFLECTION_MAX_PER_CYCLE=1
AI_CANDLE_LOOKBACK=10
ORDERBOOK_TABLE=orderbook_snapshots
ORDERBOOK_TIME_COLUMN=created_at
LIQUIDITY_TABLE=liquidity_metrics
LIQUIDITY_TIME_COLUMN=created_at
ORDERBOOK_POLL_SECONDS=10
ORDERBOOK_DEPTH_LIMIT=25
signal_generator.pyonly createsbuysignals for the MVP.- A signal is only generated when the latest close is above the previous close.
- Duplicate signals for the same candle pair are skipped.
- Signals are only marked
executedwhen the Bitfinex response returnsok=true. - If the Bitfinex response returns
ok=false, both the signal and order are markedfailedand an audit event is written. - Create the watcher input tables by running
sql/ai_market_watcher_tables.sqlin Supabase SQL editor. orderbook_liquidity_ingester.pystores raw top-of-book structure inorderbook_snapshotsand derived metrics inliquidity_metrics.ai_market_watcher.pylogs AI decisions toagent_audit_logwith eventai_market_decision.- Later movement is logged with event
ai_market_post_decision_reviewfor simple review of market awareness. - The AI watcher scans recent AI decisions for due post-decision reviews, so a restart does not limit review logging to only the latest decision.
- Reviewed decisions can trigger an audit-only AI self-reflection event named
ai_market_reflection; reflections are rate-limited byAI_REFLECTION_MAX_PER_CYCLEand can be paused by setting it to0. - OpenAI calls go through
openai_client.py.AI_API_MODE=chat_completionsis the default; setAI_API_MODE=responsesto test the Responses API behind the same decision/reflection contract. - Decision and reflection calls can use separate models with
AI_DECISION_MODELandAI_REFLECTION_MODEL; empty values fall back toAI_MODEL. - Decision and reflection outputs use strict structured JSON schemas with an
experimental_notesfield for audit-only observations that are not part of the stable trading contract. - OpenAI decision/reflection calls retry transient timeouts and connection errors. Retry attempts are audited as
ai_request_retrywith severitywarning; only exhausted attempts fall through asai_market_watcher_error. Successful decision/reflection audits include OpenAI request metadata when available. - The AI watcher expects latest rows in the Supabase tables named by
ORDERBOOK_TABLEandLIQUIDITY_TABLE.