A Linux-first C++17 foundation for an event-driven crypto trading research and
paper-trading platform. Development follows the milestones in codex.md; live-money
execution is disabled and is not part of the current implementation.
Iteration 12 adds an interchangeable Binance Spot Testnet execution adapter after the monitored paper workflow and restart recovery baseline:
- modular CMake targets
- command-line help, version, and historical backtest execution
- structured UTC console logging
- validated strategy configuration
- core
CandleandTradeSignaltypes - historical candle-loader abstraction and CSV implementation
- incremental EMA and Wilder RSI implementations
- shared EMA/RSI strategy engine using closed candles
- long-only portfolio simulation with fees and adverse slippage
- return, trade, drawdown, expectancy, duration, and cost metrics
- normalized
TradeTickevents behind an exchange-neutral feed interface - Binance Spot market-data-only TLS WebSocket adapter
- malformed-message isolation and capped exponential reconnect backoff
- UTC-aligned OHLCV candle construction from normalized trade ticks
- explicit duplicate, out-of-order, late-tick, gap, and flush behavior
- live feed-to-candle-to-indicator-to-strategy orchestration
- auditable signal events with explicit
execution=DISABLED - graceful
SIGINTandSIGTERMhandling - transactional, idempotent SQLite storage for closed candles and signals
- fail-closed risk checks with explicit rejection reasons
- stop-distance position sizing with exposure, cash, minimum, and step constraints
- simulated market fills with fees and adverse slippage
- virtual cash, position, realized/unrealized P&L, stop-loss, and take-profit state
- runnable live-data paper mode with configurable simulated spread, costs, and exits
- transactional SQLite order, fill, and account-snapshot persistence
- session health, event counters, drawdown, trade outcomes, and final statistics
- append-only CSV fill reporting at
data/paper_trades.csv - complete virtual cash, P&L, fee, and open-position recovery from SQLite
- historical closed-candle warm-up without replaying historical orders
- signed Spot Testnet market-order and cancellation requests behind
IExecutionAdapter - TLS certificate and hostname verification with a hard testnet-only endpoint guard
- dependency-free unit-test setup integrated with CTest
Requirements: CMake 3.16+, a C++17 compiler, Boost 1.74+ (system and Beast
headers), OpenSSL 1.1.1+, and a SQLite 3 runtime library. The SQLite development
header is preferred when installed; a minimal stable-ABI compatibility declaration
is used when only the runtime library is available.
cmake -S . -B build -DCMAKE_BUILD_TYPE=Debug
cmake --build build
ctest --test-dir build --output-on-failureSee Running Crypto Trader for the complete command guide.
./build/crypto_trader --help
./build/crypto_trader --version
./build/crypto_trader --mode backtest --config config/strategy.yaml \
--input data/historical/BTCUSDT_5m.csv
./build/crypto_trader --mode signal --config config/live.yaml
./build/crypto_trader --mode paper --config config/paper.yamlThe tracked data/historical/BTCUSDT_5m.csv file is a small synthetic smoke-test
fixture, not real market history and not evidence of strategy profitability.
Historical candle CSV files use this header and column order:
open_time_ms,close_time_ms,open,high,low,close,volume
Timestamps are UTC Unix milliseconds. Each data row represents one closed candle.
BinanceMarketDataFeed normalizes the documented raw <symbol>@trade stream into
internal TradeTick values. It connects only to Binance's public market-data host,
uses TLS peer and hostname verification, relies on Beast's control-frame handling
for server ping/pong frames, and reconnects after errors with a capped 1/2/4/8/16
second delay. Signal mode connects this adapter to the candle and strategy pipeline.
Signal mode prints one structured SIGNAL record for every closed candle. During
indicator warm-up, values are shown as WARMING_UP and the decision is
NO_TRADE. With the default 5-minute timeframe and EMA50, full warm-up takes 50
closed candles. Every record ends with execution=DISABLED; this mode contains no
order creation or execution adapter.
Before a signal is logged, its closed candle and decision are committed together
to the configured SQLite database. The default path is data/trading.db. Repeated
writes for the same symbol/timeframe/timestamp update the existing audit record
instead of creating duplicates. Indicator values are SQL NULL during warm-up.
RiskManager turns an eligible BUY or SELL opinion into an order candidate only
after checking market freshness, signal age, spread, account state, daily loss,
loss streak, open-position count, post-loss cooldown, and protective-price
geometry. Quantity is derived from stop distance and clamped to configured
exposure, available buy-side cash, provider minimum, and quantity step.
The risk manager is not connected to signal mode and no component submits its
candidate orders. risk.trading_enabled remains false in config/live.yaml.
PaperExecutionAdapter accepts in-memory order candidates and immediately
simulates market fills. It supports one long position, partial and full exits,
cash enforcement, proportional fee allocation, marked equity, cumulative realized
P&L, and intratick stop-loss/take-profit triggers. Stop gaps use the observed price
and then apply adverse slippage rather than assuming a perfect stop fill.
Paper mode connects this adapter to public Binance trade data through the same
closed-candle strategy pipeline used by signal mode. BUY signals are risk checked;
SELL signals can only reduce the existing long position. Approved candidates fill
only inside the local simulator; orders, fills, and portfolio snapshots are
committed to data/paper_trading.db.
Paper mode preloads the CSV configured by paper_execution.warmup_csv into the
indicators without emitting signals or orders. Supply enough recent closed candles
for the longest indicator period. On restart, the latest complete virtual portfolio,
including any open position and its protection prices, is restored from SQLite.
The adapter cannot contact an exchange or broker and paper mode rejects any config that enables real execution.
BinanceTestnetExecutionAdapter implements the shared execution interface for the
official Binance Spot Test Network. It signs market-order and cancellation requests
with HMAC-SHA256 and includes a synchronous TLS transport. Both the adapter and
transport reject every base URL except https://testnet.binance.vision.
The adapter is intentionally not connected to the strategy CLI yet. Integration requires explicit testnet credentials, exchange-filter validation, reconciliation, and operational approval. Credentials must be supplied at runtime and never stored in repository configuration.
Stop the process with Ctrl+C. The Asio loop handles both SIGINT and SIGTERM
and cancels the market feed before exiting.
CandleBuilder consumes one symbol on one event-loop thread. Buckets align to UTC
Unix epoch boundaries. A tick in a newer bucket emits exactly one closed candle;
missing intervals do not create synthetic candles. Binance trade IDs suppress
duplicates within the active bucket. Out-of-order ticks in that bucket still
contribute to high, low, and volume, while open and close follow exchange event
ordering. Ticks belonging to a previously closed bucket are ignored. flush()
closes the active candle once during a controlled shutdown or replay completion.
Do not commit API credentials or secrets. Signal and paper modes use public market data and require no credentials. Paper fills are simulations, not evidence that an order could fill at the modeled price. Automated testnet operation is not connected to the CLI, and live execution remains outside the project. The testnet adapter cannot target a production Binance host; Olymp Trade integration is not implemented.