TheOddCollective.io
Trading System
A GPU-accelerated ensemble of deep learning and gradient-boosted models for automated cryptocurrency trading via Alpaca Markets.
1. Dashboard Overview
The application uses a fixed two-panel layout: a 530-pixel sidebar on the left for controls and status, and a multi-tab chart panel on the right. A branded title bar spans the full width at the top. The chart panel hosts a ttk.Notebook tab strip above the charts — up to five crypto tabs can be open simultaneously, each trading a different symbol with its own chart, confidence panel, P/L display, and independent trader loop.
Each tab has a top bar with a symbol selector dropdown, a real-time P/L label, a trade-count label, and a close button. The active tab drives the sidebar — switching tabs saves the previous tab's sidebar settings and restores the new tab's saved configuration, so each symbol maintains its own parameter state.
1.1 Sidebar
The top portion of the sidebar is a signal display canvas showing the current price, market regime label (BULL · BEAR · NEUTRAL), a four-bar confidence meter for each class (BUY / SELL / HOLD_UP / HOLD_DOWN), and a live trade status indicator. Below that, three collapsible cards organize all user-configurable inputs:
| Field | What it controls |
|---|---|
| LR | Optimizer learning rate (default 0.000484) |
| SEQ | Sequence length — bars fed per inference window |
| VAL | Validation split fraction (e.g. 0.2 = 20% held for val loss) |
| BARS | Historical bars to load from Alpaca (default 45,000) |
| REG WT | Regime weight boost — amplifies loss on regime-matching bars |
| MIN ACC | Minimum validation accuracy required before Full Auto proceeds |
| Multi-Sym On | Enables multi-symbol training using the tab's aux symbol list |
| Aux 1–3 | Three dropdown slots — select up to 3 auxiliary training symbols per tab. Settings are saved and restored per tab on every switch. |
| Field | What it controls |
|---|---|
| BUY CONF / SELL CONF | Minimum class confidence required to generate a signal |
| DELTA | Minimum predicted price move required to trade |
| CONSEC | Consecutive bars that must agree before entry fires |
| STOP% | Hard stop-loss as a percentage below entry price |
| EXPO | Maximum fraction of capital allocated per position |
| BARS | Number of bars used in the backtest window |
| Field | What it controls |
|---|---|
| Auto-Retrain | Toggles scheduled background retraining |
| Retrain Days | Days since last retrain before a symbol becomes eligible. Each open tab tracks its own retrain date independently — if more than one tab is overdue at the same time, only the most-overdue symbol retrains that cycle, so a large multi-tab setup spreads its retraining load across several days instead of triggering every symbol at once. |
| Dynamic Position Sizing | Scales position size by model confidence at entry |
| Bear Filter | Blocks BUY signals when HTF regime is in downtrend |
| Bear Lookback | Window for the HTF bear/bull regime determination |
The action row beneath the cards holds the primary workflow buttons: API Keys (encrypted Alpaca credentials), Opt Model (standalone model optimizer), Apply & Train (apply UI values and retrain immediately), Opt Params (execution parameter optimizer), and Backtest (run backtest with current model, no retraining). A second row provides Stop BG, Shutdown, Save Defaults, and Load Defaults.
1.2 Chart Panel
Each chart tab contains two stacked matplotlib charts sharing a common x-axis (bar index at the configured timeframe). The active tab's chart responds to sidebar controls; inactive tabs preserve their last backtest state and reload it when re-selected. The Optimizer Status panel below the charts is scoped to the training tab — other tabs show a dim indicator naming the symbol being trained without overwriting the chart view.
- Price chart (top) — Candlestick or line plot of close price. Overlays include the dashed ZigZag pivot line, green valley markers (trained BUY labels), orange peak markers (trained SELL labels), green upward triangles (model BUY entries), red downward triangles (model SELL exits), and orange × markers (stop-loss exits).
- Confidence chart (bottom) — Per-bar softmax probabilities for all four classes: BUY % (green), SELL % (red), HOLD_UP % (blue), HOLD_DOWN % (pink). A horizontal dashed line marks the active confidence threshold floor.
An Optimizer Status panel below the charts displays the current trial number, best score so far, and the parameter values of the current best trial. The chart updates live whenever a new best trial is found during Stage 2 or Stage 5 of Full Auto.
1.3 Trade History Panel
A fixed 215-pixel panel on the far right edge of the window displays the last 20 completed trades in reverse-chronological order (most recent at the top). Each row shows entry price, exit price, and P/L percentage (green for profit, red for loss). A dot indicator marks each row's source: orange ● for live executed trades, muted · for backtest trades. The panel populates immediately after any backtest run, so it is always filled with data even before the bot goes live. As real trades execute, they push backtest rows out from the bottom up.
Below the 20 rows, a summary strip shows:
- 20-TRADE P/L — cumulative P/L across all 20 displayed trades
- SOURCE — breakdown of live vs. backtest trade counts
- LIVE PROFIT — cumulative P/L from real executed trades only (hidden until at least one live trade completes)
2. Model Input Features
The model receives a sliding window of SEQUENCE_LENGTH consecutive bars (range 48–192, default 112), each bar described by 59 engineered features. The input tensor shape is (batch, seq_len, 59). All features are standardized with a fitted StandardScaler before being passed to the network, and clipped to ±3σ to suppress outlier bars.
| Feature | Description |
|---|---|
| price_change | Bar-over-bar return of close price |
| momentum | N-bar cumulative price change |
| close_zscore | Z-score of close relative to a rolling window |
| Feature | Description |
|---|---|
| long_term_trend | Direction of the long-period moving average |
| long_ma_slope | Rate of change of the long MA |
| long_ma_deviation | Price distance from the long MA, normalised |
| bull_probability | Smoothed probability score that current regime is bullish |
| Feature | Description |
|---|---|
| swing_length | Bar count of the most recent swing |
| swing_size_atr | Size of the most recent swing in ATR units |
| last3_swing_avg | Average size of the last three swings |
| hh_count / hl_count | Recent higher-high and higher-low counts (bullish structure) |
| lh_count / ll_count | Recent lower-high and lower-low counts (bearish structure) |
| bull_structure | Binary flag: HH+HL sequence active |
| swing_retracement | Current bar's retracement depth into the last swing |
| Feature | Description |
|---|---|
| rsi | Relative Strength Index (14-period) |
| macd_hist | MACD histogram (signal line divergence) |
| stoch_k | Stochastic %K |
| mfi | Money Flow Index — volume-weighted RSI variant |
| Feature | Description |
|---|---|
| atr | Average True Range — normalised volatility measure |
| bb_percent | Price position within Bollinger Bands (0–1) |
| bb_squeeze | Band width as fraction of midline — detects volatility compression |
| adx | Average Directional Index — trend strength magnitude |
| adx_trend | ADX trend direction (+1 / −1) |
| obv | On-Balance Volume — cumulative volume direction |
| volume_ratio | Current bar volume relative to recent average |
| buying_pressure | Fraction of volume on up-ticks |
| price_vwap_ratio | Price relative to VWAP — above=bullish bias |
| vwap_slope | Rate of change of VWAP |
| vwap_crossover | Recent price–VWAP crossover signal |
| Feature | Description |
|---|---|
| btc_price_change | BTC bar-over-bar return (same timeframe) |
| btc_momentum | BTC N-bar momentum |
| btc_price_vwap_ratio | BTC price relative to its VWAP |
| btc_vwap_slope | Rate of change of BTC VWAP |
| btc_vwap_lead | BTC VWAP deviation 1 bar ahead (lead indicator) |
| btc_phase_markup / btc_phase_markdown | BTC 4-phase regime flags |
| btc_lag1 / btc_lag2 / btc_lag3 | BTC return lagged 1–3 bars — captures the typical 1–3 bar lead BTC has over altcoins |
| Feature | Description |
|---|---|
| m5_price_change | 5-minute bar return (finer resolution momentum) |
| m5_momentum | 5-minute N-bar momentum |
| m5_volatility | 5-minute ATR-normalised volatility |
| m5_rsi | RSI computed on the 5-minute series |
| htf_trend | 1-hour timeframe trend direction |
| htf_rsi | 1-hour RSI |
| htf_momentum | 1-hour momentum |
| htf_phase_markup / htf_phase_distribution / htf_phase_markdown | 1-hour 4-phase market regime flags |
| htf_vwap_dev | Price deviation from 1-hour VWAP |
| Feature | Description |
|---|---|
| hour_sin / hour_cos | Sine and cosine encoding of hour-of-day (captures intraday seasonality) |
| dow_sin / dow_cos | Sine and cosine encoding of day-of-week |
| phase_markup | 15-minute Wyckoff markup phase flag |
| phase_distribution | 15-minute distribution phase flag |
| phase_markdown | 15-minute markdown phase flag |
Abstract
This document describes the architecture, training pipeline, optimization methodology, and risk management framework of TheOddCollective.io trading system. The system employs a hybrid ensemble of a HybridTransformerBiLSTM neural network and an XGBoost gradient-boosted classifier, trained on 4-class ZigZag pivot labels derived from ATR-normalized price action. Bayesian hyperparameter optimization via Optuna TPE searches across six dimensions simultaneously. Walk-forward validation with a withheld holdout set provides out-of-sample performance estimates uncorrupted by in-sample overfitting.
Version 10.38 introduces a multi-tab trading architecture: up to five simultaneous crypto trading tabs can be open at once, each with its own symbol, up to three aux training symbols (configurable via dropdown), independent trader loop, and per-tab settings persistence. A single trained model is broadcast to all tabs after training; each tab then applies continuous per-symbol online fine-tuning every 50 new bars. Execution is broadcast simultaneously to all selected exchanges — Alpaca, Coinbase Advanced Trade, Robinhood, and Binance — with per-exchange cash balances displayed in the status bar. API key storage uses Fernet encryption with machine-bound hardware IDs.
1. Model Architecture
1.1 HybridTransformerBiLSTM
The primary model is a hybrid architecture that combines the global attention mechanism of Transformer encoders with the sequential state-tracking capability of a bidirectional LSTM. The input projection maps raw features to a 320-dimensional embedding. Six Transformer blocks (each with multi-head self-attention and a feed-forward sublayer) process the full sequence in parallel. The output is then passed through a BiLSTM with hidden size 160, producing a 320-dimensional bidirectional representation. Layer normalization stabilizes gradients before the classification heads.
| Input projection | → 320 dims |
| Transformer blocks | 6 layers, multi-head attention |
| BiLSTM | hidden=160, bidirectional → 320 out |
| Layer Norm | pre-classification |
| FC1 | 320 → 128 + ReLU + Dropout |
| Classification head (fc2) | 128 → 4 classes |
| Magnitude head (mag_head) | 128 → 1 (scalar) |
| Leg head (leg_head) | 128 → 2 (bull/bear logits) |
1.2 XGBoost Ensemble Component
An XGBoost gradient-boosted tree classifier runs in parallel with the neural network. Both models emit class probability vectors. Their outputs are fused via a weighted average (tunable via the optimizer), and the final signal is determined by the argmax of the fused distribution. When the two models disagree significantly, the ensemble falls back to HOLD, reducing false signal frequency in ambiguous market conditions.
1.3 Regime Filter
A regime weight boost (REGIME_WEIGHT_BOOST) up-weights BUY and SELL class probabilities when a high-timeframe bullish regime is detected. This helps the model distinguish trending from ranging markets and reduces whipsaw trades during lateral price action. The regime filter is applied post-inference and does not affect the model weights.
2. ZigZag Label Engine
Training labels are derived from a ZigZag pivot detection algorithm scaled by the Average True Range (ATR). Rather than fixed percentage thresholds, the pivot size adapts to current volatility via an ATR multiplier (ATR_LABEL_MULTIPLIER). This produces labels that are meaningful across different volatility regimes.
Each bar in the training set is assigned one of four classes:
| Class | Label | Meaning |
|---|---|---|
| 0 | SELL | Bar is at or near a confirmed ZigZag peak |
| 1 | HOLD_DOWN | Bar is in a bear leg between peak and trough |
| 2 | HOLD_UP | Bar is in a bull leg between trough and peak |
| 3 | BUY | Bar is at or near a confirmed ZigZag trough |
Labels are computed using a forward-looking window (ZIGZAG_LABEL_WINDOW) during training. This look-ahead is appropriate for label generation only and is never applied during live inference.
3. Bayesian Hyperparameter Optimization
3.1 Model Optimizer (Stage 2)
The model optimizer uses Optuna's Tree-structured Parzen Estimator (TPE) to search the training hyperparameter space. TPE is a form of Bayesian optimization that builds probabilistic models of the parameter regions associated with high and low scores, then proposes new candidates from the high-scoring region. This is substantially more efficient than grid search across multi-dimensional spaces.
A MedianPruner monitors validation loss at each epoch. Trials that fall below the median of completed trials at the same epoch step are stopped early, saving compute time on clearly suboptimal configurations.
| Parameter | Range |
|---|---|
| Learning rate | 1e-5 – 1e-3 (log scale) |
| ATR label multiplier | 0.5 – 3.0 |
| Regime weight boost | 1.0 – 3.0 |
| Predict horizon | 1 – 10 |
| Sequence length | 48 – 192 |
| ZigZag window (if enabled) | 3 – 15 |
3.2 Execution Parameter Optimizer (Stage 5)
After the model is trained, a second optimizer searches over execution parameters — the thresholds and filters that govern when the trained model actually triggers a trade. These are optimized via backtest score (profit factor × Sharpe ratio) rather than training loss, which more directly targets live profitability.
| Parameter | Description |
|---|---|
| MIN_DELTA | Minimum predicted price move required to trade |
| CONSECUTIVE_SIGNAL_REQUIRED | How many consecutive bars must agree before entry |
| LSTM_ENSEMBLE_WEIGHT | Neural net weight in the fused signal |
| XGB_ENSEMBLE_WEIGHT | XGBoost weight in the fused signal |
| BULL_FILTER_LOOKBACK | High-timeframe trend filter window |
| ZIGZAG_ARGMAX_FLOOR | Minimum confidence threshold for BUY/SELL signals |
4. Full Auto Pipeline
The Full Auto pipeline executes all optimization, training, and validation stages in a single unattended run. It is designed to run overnight and save the best discovered configuration as the default for paper trading.
- Pause auto-trader & disable UI buttons
- Set _FULL_AUTO_ACTIVE = True (prevents data trimming to live window)
- Flush entry boxes → globals (sync all signal params)
- Create timestamped .log + _summary.json run files
- Write header: symbol, GPU, LR, epochs, conf gates, filters
- Prune old logs — keep 10 most recent runs per symbol
- Pull up to 85,000 bars of OHLCV from Alpaca
- Full dataset kept in RAM — not trimmed to live window
- _FULL_AUTO_ACTIVE flag prevents 12k trim in historical_df
- collect_historical_data() runs in background thread
- Fetches up to 3 aux symbols (per-tab dropdowns)
- Stored per-symbol for training augmentation in Stage 3
- Learning Rate · ATR Label Multiplier
- Regime Weight Boost · Predict Horizon
- Sequence Length · ZigZag Window (ZZ mode)
- 30-epoch quick train with trial hyperparams
- Backtest → score = Sharpe × win-rate × P&L
- TPE posterior updates → smarter next-trial params
- Winning hyperparams applied to globals + UI fields immediately
- Full FULL_EPOCHS retrain — BiLSTM (2-layer bidirectional) + XGBoost in parallel · Temperature scaling on val set
- Model saved to MODELS_DIR · validation_metrics populated with ensemble accuracy
Gate?
- Combine primary + aux symbol bars · ZigZag or Traditional labels applied to full dataset
- Class imbalance: inverse-frequency weighting (BUY/SELL vs HOLD, capped at 10×)
- BiLSTM + XGBoost trained in parallel · early stopping on val loss · holdout split reserved for Stage 8
below?
- Full backtest with current model + params
- P&L · Sharpe · Profit Factor · Max Drawdown · Capture rate
- Pred-accuracy gate: if < 55% → trigger additional retrain
- auto_calc_params(): derives Stop Loss from ATR distribution
- auto_calc_confidence(): 14-backtest sweep → optimal confidence threshold
- Both narrow Stage 5 search bounds (Optuna warms faster)
- MIN_DELTA · CONSECUTIVE_SIGNAL_REQUIRED
- LSTM / XGB Ensemble Weights
- BULL_FILTER_LOOKBACK · ZIGZAG_ARGMAX_FLOOR
- MIN_CONFIDENCE_TO_TRADE · STOP_LOSS_PCT
- Each trial: full backtest (no training — fast)
- Score = P&L × Sharpe × capture rate multiplier
- Live chart updated on every new best trial
- Winning params applied to globals + UI immediately
- Total P&L % · Sharpe Ratio · Profit Factor
- Expectancy per trade · Max Drawdown %
- Directional accuracy · Capture rate of opportunities
- Exit breakdown: SELL / STOP_LOSS / TRAIL_STOP counts
- SELL exit % — healthy model exits cleanly on signal
- All metrics persisted to run_summary JSON immediately
- save_current_as_defaults() — every winning param to disk
- LR, ATR×, horizon, seq len (Stage 2) · delta, consec, weights (Stage 5)
- Loaded automatically on next application launch
- update_signal_cache() — pre-computes BUY/SELL signals on current bars
- Auto-trader hot-swapped to new model — no restart required
- Rolling train → test windows across full history
- Measures consistency score + CV of Sharpe across market regimes
- Low CV = strategy stable across varying conditions
- Evaluates on bars never seen during any training phase
- True out-of-sample performance measurement
- All metrics written to run_summary JSON
zz_self_accuracy feature encodes a lagged rolling ZigZag alignment score from Phase 1 inference — how often the model called BUY/SELL correctly over the prior 50 confirmed bars. Phase 2 learns which market regimes produce reliable signals and adjusts confidence accordingly. The holdout window is withheld from all training phases and evaluated only in Stage 8.5. Validation Methodology
A fixed holdout set — the most recent bars of the dataset — is withheld from all training, optimization, and intermediate backtesting. This holdout set is only evaluated in Stage 8, after all parameter decisions have been finalized. This prevents the common issue of inadvertent optimization on test data that occurs when backtests are repeatedly run and parameters adjusted.
Walk-forward validation slices the training history into sequential windows and evaluates model generalization across different market periods. This provides an estimate of how well the model adapts to non-stationary crypto price dynamics over time.
5.1 Trade-Level Sharpe Ratio
The Sharpe ratio is computed at the trade level — mean and standard deviation are calculated across completed round-trip returns only. Including flat-period bars in the denominator artificially suppresses standard deviation and produces misleadingly large Sharpe values when trade count is low. The trade-level approach gives a statistically honest measure of risk-adjusted return per trade, annualized by observed trade frequency. Note that Sharpe estimates remain wide with fewer than ~30 trades; a larger sample is required for the number to be statistically reliable.
5.2 Per-Trade Audit Log
Every backtest run appends a structured entry-by-entry record to the daily debug log at %APPDATA%\OddCollective\logs\debug_signal_YYYYMMDD.log. Each completed trade is logged with its entry price, exit price, exit reason (sell signal, stop loss, or trailing stop), P&L contribution, position size multiplier, and running total. A summary line records total trades, cumulative P&L, Sharpe, and capture rate — allowing independent verification of any backtest result shown in the dashboard.
6. Risk Management
The system incorporates several risk controls at both the model and execution layer:
- Stop-loss percentage — A configurable per-trade stop-loss is applied at the execution layer. The stop level is optimized alongside execution parameters.
- Minimum confidence threshold — Trades are only executed when the model's signal confidence exceeds a tunable floor, reducing low-conviction entries.
- Consecutive signal confirmation — Multiple consecutive bars must agree before a position is entered, reducing false positives from single-bar noise.
- Maximum position exposure — A hard cap on the fraction of available capital allocated to any single position.
- Paper trading mode — All features are available in paper trading mode via Alpaca, enabling live market testing without capital at risk.
7. Multi-Tab Trading & Broadcast Execution
7.1 Multi-Tab Architecture
The chart panel hosts a tabbed notebook that supports up to five simultaneously active crypto trading tabs. Each tab is an independent trading unit with its own:
- Primary symbol and three auxiliary symbol dropdowns for multi-symbol training
- Matplotlib chart, confidence panel, P/L label, and trade count display
- Independent background trader loop fetching live bars for that symbol
- Saved sidebar settings (ML parameters, thresholds, aux selections) that persist across tab switches
- Backtest snapshot that reloads when the tab is re-selected
When a tab's symbol is changed, the old trader loop is stopped and a new one starts for the selected symbol. Tabs are closed via a per-frame button that stops the trader and removes the tab; the minimum tab count is one.
7.2 Shared Model with Per-Tab Fine-Tuning
After any training run completes, the trained model is broadcast to all open tabs via _broadcast_model_to_tabs. Each tab's SymbolState receives a reference to the same model weights, scaler, and temperature. From that point, each tab independently applies incremental fine-tuning (train_on_batch at 5% of the base learning rate) every 50 new confirmed ZigZag-labeled bars for its symbol, allowing per-symbol specialization without a full retrain. New tabs added while a trained model exists inherit it automatically at creation time.
7.3 Broadcast Multi-Exchange Execution
When multiple exchange API keys are entered and tested, all active exchanges are selected for simultaneous execution. A BUY or SELL signal fans out to every active broker adapter in sequence — each adapter executes an independent market order sized to its own available balance. The status bar displays a per-exchange cash breakdown (e.g., A:$200.00 R:$219.61) so the combined position across platforms is always visible. Market data is always sourced from Alpaca for model consistency regardless of which exchanges are selected for execution.