A Laravel 11 + Tailwind CSS signal dashboard that fetches live crypto candle data from Binance, runs a rule-based vote engine to determine direction, and uses Claude AI to write the reasoning. Displays predictions for upcoming Myriad Markets candle prediction slots — helping users decide whether to bet More Green or More Red on each 5-minute market window.
- Fetches the last 60 x 1-minute candles per coin from Binance (no API key needed)
- Fetches live order book depth and recent aggressor trade data from Binance
- Fetches higher timeframe (5m, 15m, 1h, 4h, 1d) regime snapshots for comprehensive trend context
- A vote engine determines direction from 5 leading signals (no lagging indicators)
- Requires strong signal consensus before generating a prediction — mixed signals produce a skip
- Claude AI writes a 2-sentence explanation of why the vote engine chose that direction
- Predictions are stored in MySQL and displayed on a live dashboard
- After each slot closes, the resolver fetches the actual candles and scores the prediction
- Win rate is tracked and displayed (last 20 resolved trades per coin)
- Confidence bar turns green at 75%+ — the system's visual recommendation indicator
- Multi-exchange symbol mappings prepared for enhanced data reliability
- Replaced Claude-as-direction-decider with a deterministic PHP vote engine
- Claude is now used only to write the reasoning — direction and confidence are computed, not generated
- Engine requires 3 of 4 leading signals to agree before a prediction is made
- Signals that don't reach the threshold produce an intentional skip (shown on dashboard with reason)
Based on performance analysis showing lagging indicators (RSI, EMA, Bollinger, VWAP, candle streak, volume) had near-zero predictive edge for 5-minute predictions and actually hurt accuracy at high agreement, the vote engine was restructured to use only forward-looking signals. Recently enhanced with funding rate data and market regime awareness for improved accuracy:
| Signal | Source | What it measures |
|---|---|---|
| HTF 5m trend | Binance 5m klines | EMA20 vs EMA50 on the 5-minute timeframe |
| HTF 15m trend | Binance 15m klines | EMA20 vs EMA50 on the 15-minute timeframe |
| Order book imbalance | /api/v3/depth |
Bid volume vs ask volume across top 20 levels (thresholds adjust for volatility: 3-7%) |
| Aggressor trade imbalance | /api/v3/aggTrades |
Buy-initiated vs sell-initiated volume in last 200 trades (thresholds adjust for volatility: 3-7%) |
| Funding rate | Binance Futures API | Current funding rate sentiment (>0.01% bearish, < -0.01% bullish) |
| Funding rate trend | Historical funding rates | Recent funding rate changes (increasing bearish, decreasing bullish) |
| BTC correlation | Price correlation analysis | 30-minute return correlation with BTC (for altcoins only) |
| Open interest trend | Binance Futures API | Recent OI changes (increasing bullish, decreasing bearish) |
| On-chain activity | Blockchain.com/Etherscan/BscScan APIs | BTC/ETH/BNB network activity levels (high activity bullish, low activity bearish) |
Market Regime Detection: Analyzes 1h/4h/1d timeframes to classify overall market conditions (bullish/bearish/sideways), providing context for signal interpretation.
ML Feature Engineering: Extracts 50+ technical features including RSI, MACD, Bollinger Bands, statistical measures (skewness, kurtosis), momentum indicators, and time-based features for machine learning integration.
ML Model Training: Successfully trained gradient boosting models on 587 historical predictions (52.81% accuracy) using candlecall:train-ml command. Models can be used for ensemble predictions combining rule-based and ML approaches. XGBoost/LightGBM integration available via Python subprocess calls.
Ensemble Methods: Rule-based vote engine now incorporates ML predictions as an additional signal, creating a hybrid approach that combines traditional technical analysis with machine learning insights for improved decision making.
Real-Time Processing: Implemented intelligent caching for market regime data (3 minutes), order book data (30 seconds), and aggressor trade data (30 seconds) to reduce API latency and improve prediction generation speed.
Error Handling Improvements: Enhanced API resilience with progressive retry logic (up to 3 attempts), exponential backoff for connection failures, separate timeouts for connection vs data transfer, and comprehensive error logging with fallback URL support for Binance API outages.
Data Validation: Comprehensive checks for data anomalies and potential manipulation including price sanity validation, volume spike detection, statistical outlier analysis, pump-and-dump pattern recognition, wash trading detection, and OHLC relationship validation with severity-based logging.
Kelly Criterion Implementation: Optimal position sizing using Kelly Criterion formula (K = (bp - q) / b) based on historical win rates and estimated odds ratios. Dynamically adjusts bet sizes per coin and confidence level for maximum long-term growth while managing risk.
Performance Attribution Analysis: Comprehensive analysis of which signals contribute most to wins/losses using candlecall:analyze-attribution command. Tracks signal impact scores, win rates with/without signals, and generates optimization recommendations for improving prediction accuracy.
Seasonal Analysis: Time-based pattern analysis using candlecall:analyze-seasonal command to identify optimal prediction timing. Analyzes monthly, weekly, and hourly performance patterns, detecting seasonal effects like weekend performance and optimal trading hours.
xAI Integration: Conceptual implementation of xAI Grok integration for enhanced signal analysis and prediction generation. Includes GrokService for API communication, model training capabilities, and advanced data processing using xAI's language models for cryptocurrency analysis.
Testing & Validation Framework: Comprehensive testing framework for safe deployment of improvements. Includes candlecall:test-baseline for establishing performance baselines, candlecall:test-walk-forward for out-of-sample testing, and candlecall:monitor-performance for live performance monitoring with automatic rollback triggers when accuracy degrades below thresholds.
- 75% — 3 of 4 signals agree (Moderate / Lean)
- 90% — 4 of 4 signals agree (Strong / Official Pick)
- Confidence bar is green at 75%+ regardless of direction — visual cue that the system recommends the trade
- Below 75% is never shown (predictions are skipped if fewer than 3 signals agree)
- VWAP now anchors to midnight UTC (full session) instead of a rolling 60-candle window
- Removes false signals caused by the window shifting, not actual market conditions
- Scheduler cron was pointing at a different project — fixed, CandleCall now auto-runs every 5 minutes
- Added strict next-cycle targeting in prediction generation (never current slot)
- Added per-coin command output for
candlecall:predict([OK]/[SKIP]/[FAIL]+ target slot) - Added Binance endpoint fallback support via
BINANCE_API_URLS - Added slot-switch animation and stronger live slot cues in dashboard
- Added real coin logos and mobile-responsive improvements in dashboard/history UI
- Added trade history page (
/history/{coin}) with last 20 resolved markets - Added
candlecall:analyzecommand for confidence/bucket performance analysis
| Coin | Binance Symbol | Myriad URL |
|---|---|---|
| BTC | BTCUSDT | myriad.markets/candles/btc |
| ETH | ETHUSDT | myriad.markets/candles/eth |
| BNB | BNBUSDT | myriad.markets/candles/bnb |
| ZEC | ZECUSDT | myriad.markets/candles/zec |
| PENGU | PENGUUSDT | myriad.markets/candles/pengu |
- Each market is a 5-minute window of 5 x 1-minute candles (e.g. 14:00–14:04:59 UTC)
- Resolves More Green if 3 or more of the 5 candles close green (close >= open)
- Resolves More Red if 3 or more close red
- Markets open at fixed UTC boundaries: :00, :05, :10 … :55
- Users must enter before the boundary — the market closes at the exact start of the window
- Data source used by Myriad for resolution: Binance spot USDT pairs
- PHP 8.x / Laravel 11
- MySQL (database:
candlecall) - Tailwind CSS v4 via
@tailwindcss/vite - Alpine.js (CDN) for UI interactions
- Binance public APIs — klines, depth, aggTrades (no key required)
- Anthropic Claude API (
claude-haiku-4-5-20251001) — reasoning text only
Each predict run performs the following steps per coin:
BinanceService::fetchCandles() requests the last 60 closed one-minute candles via the Binance public klines API.
BinanceService::fetchSessionCandles() fetches all 1m candles from midnight UTC to now. Used to compute a session-anchored VWAP (meaningful daily reference) instead of a rolling 60-candle window.
BinanceService::fetchMarketRegime() fetches 5m and 15m klines and computes EMA20 vs EMA50 trend on each timeframe. Returns bullish, bearish, or neutral per timeframe.
BinanceService::fetchOrderBook() hits /api/v3/depth for the top 20 bid/ask levels. The vote engine computes bid volume vs ask volume — imbalance > 5% either way counts as a directional signal.
BinanceService::fetchAggressorImbalance() hits /api/v3/aggTrades for the last 200 executed trades. Each trade is tagged as buyer-initiated (m=false) or seller-initiated (m=true). Imbalance > 5% counts as a directional signal.
VoteEngine::computeVotes() tallies the 4 signals. Each votes +1 (bullish), -1 (bearish), or 0 (neutral). If fewer than 3 signals vote the same direction, the result is skip. If 3 or 4 agree, direction is set and confidence is computed:
3/4 signals agree → confidence = 75%
4/4 signals agree → confidence = 90%
ClaudeService sends the vote summary to Claude with a system prompt instructing it to write a 2-sentence explanation citing the strongest signals. Claude does not decide direction — it only explains the vote engine's decision.
The prediction (direction, confidence, reasoning, bet size) is saved to MySQL via updateOrCreate. The dashboard displays it as a More Green or More Red card with a green confidence bar when ≥75%.
Prediction generation enforces that the written slot is strictly after the current slot boundary.
app/
├── Console/Commands/
│ ├── PredictCommand.php # candlecall:predict
│ ├── AnalyzePerformanceCommand.php # candlecall:analyze
│ ├── ResolveCommand.php # candlecall:resolve
│ ├── PruneOldData.php # candlecall:prune
│ ├── TestBaseline.php # candlecall:test-baseline
│ ├── TestWalkForward.php # candlecall:test-walk-forward
│ ├── MonitorPerformance.php # candlecall:monitor-performance
│ ├── AnalyzePerformanceAttribution.php # candlecall:analyze-attribution
│ ├── AnalyzeSeasonalPatterns.php # candlecall:analyze-seasonal
│ └── OptimizeParameters.php # candlecall:optimize-parameters
├── Http/Controllers/
│ ├── DashboardController.php # GET /
│ └── ApiController.php # GET /api/predictions[/{coin}]
├── Models/
│ ├── Candle.php
│ ├── Prediction.php
│ ├── FundingRate.php # Stores funding rate data
│ └── OpenInterest.php # Stores open interest data
└── Services/
├── BinanceService.php # Candles, session candles, regime, order book, aggressor trades
├── ClaudeService.php # Orchestrates vote engine + Claude reasoning, saves predictions
├── VoteEngine.php # 9-signal vote engine — determines direction and confidence
├── IndicatorService.php # Pure-PHP indicators: RSI, EMA, Bollinger, VWAP (context only)
├── PredictionService.php # Runs all 5 coins, handles skips vs failures
├── SignalStrengthService.php # Maps confidence to weak/moderate/strong + action labels
├── ResolverService.php # Resolves past slots against actual Binance data
├── TestingService.php # Baseline establishment, walk-forward testing, performance monitoring
├── PerformanceAttributionService.php # Signal contribution analysis
├── SeasonalAnalysisService.php # Time-based pattern analysis
├── WalkForwardOptimizationService.php # Parameter optimization
├── KellyCriterionService.php # Position sizing calculations
├── DataValidationService.php # Data anomaly detection and validation
├── GrokService.php # xAI Grok integration (conceptual)
└── MLTrainingService.php # Machine learning model training
database/migrations/
- create_candles_table
- create_predictions_table
- add_resolve_attempts_to_predictions_table
- create_funding_rates_table
- add_signal_votes_to_predictions_table
resources/views/
layouts/app.blade.php # Dark theme layout, UTC clock, navbar
dashboard.blade.php # Main dashboard, JS polling, slot switch animations, accuracy tracker
history.blade.php # Last-20 resolved trades page per coin
routes/
web.php # Dashboard + API routes + history page route
console.php # Scheduler entries
Stores raw 1-minute Binance candles fetched during predict runs.
Pruned to last 24 hours by candlecall:prune.
| Column | Type | Notes |
|---|---|---|
| coin | varchar(10) | btc, eth, bnb, zec, pengu |
| open_time | datetime UTC | Indexed with coin |
| close_time | datetime UTC | |
| open/high/low/close_price | decimal(18,8) | |
| volume | decimal(18,8) | |
| is_green | tinyint | 1 if close >= open |
Stores vote engine predictions and resolution results.
Pruned to last 20 resolved rows per coin by candlecall:prune.
| Column | Type | Notes |
|---|---|---|
| coin | varchar(10) | |
| slot_time | datetime UTC | Start of the 5-min window. Indexed with coin |
| direction | varchar(5) | 'green' or 'red' |
| confidence | tinyint | 75 or 90 (from new engine) |
| reasoning | text | Claude's 2-sentence explanation |
| bet_size_pct | tinyint | 9 at 75%, 18 at 90% |
| resolved | tinyint | 0 = pending, 1 = resolved |
| actual_result | varchar(5) | Filled after resolution |
| was_correct | tinyint | 1 = correct, 0 = wrong, null = unresolved |
| resolve_attempts | tinyint | Failed fetch attempts, max 5 before giving up |
Admin query — full all-time win rate:
SELECT
coin,
COUNT(*) as total_resolved,
SUM(was_correct) as total_correct,
COUNT(*) - SUM(was_correct) as total_wrong,
ROUND(SUM(was_correct) / COUNT(*) * 100, 1) as all_time_win_rate_pct
FROM predictions
WHERE resolved = 1
GROUP BY coin
ORDER BY all_time_win_rate_pct DESC;- PHP 8.2+
- MySQL running (XAMPP or similar)
- Node.js + npm
- Composer
composer install
npm installcp .env.example .env
php artisan key:generateEdit .env:
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=candlecall
DB_USERNAME=root
DB_PASSWORD=
ANTHROPIC_API_KEY=sk-ant-...
CLAUDE_MODEL=claude-haiku-4-5-20251001
BINANCE_API_URL=https://api.binance.com
BINANCE_API_URLS=https://api.binance.com,https://api-gcp.binance.com,https://data-api.binance.vision
GROK_API_KEY=your_xai_grok_api_key_here# Create the database first (MySQL must be running)
mysql -u root -e "CREATE DATABASE candlecall CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;"
php artisan migratenpm run buildphp artisan candlecall:predictcrontab -eAdd:
* * * * * /path/to/php /path/to/candlecall/artisan schedule:run >> /dev/null 2>&1
| Command | What it does |
|---|---|
php artisan candlecall:predict |
Fetches all data, runs vote engine, writes reasoning, saves predictions. Prints [OK]/[SKIP]/[FAIL] per coin |
php artisan candlecall:analyze |
Analyzes resolved prediction quality by confidence buckets and walk-forward splits |
php artisan candlecall:resolve |
Resolves past slots — fetches actual candles, scores predictions |
php artisan candlecall:prune |
Deletes candles older than 24h, keeps last 20 resolved predictions per coin |
php artisan candlecall:test-baseline "name" |
Establishes performance baseline before implementing changes |
php artisan candlecall:test-walk-forward "name" |
Performs walk-forward testing to validate improvements |
php artisan candlecall:monitor-performance baseline-key |
Monitors live performance with automatic rollback triggers |
php artisan candlecall:analyze-attribution |
Analyzes which signals contribute most to wins/losses |
php artisan candlecall:analyze-seasonal |
Analyzes seasonal patterns in prediction performance |
| Schedule | Command |
|---|---|
| Every 5 minutes | PredictionService::runForAllCoins() + candlecall:resolve |
| Daily at 00:00 UTC | candlecall:prune |
| Weekly on Sundays at 00:00 UTC | candlecall:train-ml |
| Monthly on 1st at 01:00 UTC | candlecall:optimize |
All times are UTC. The single cron entry * * * * * php artisan schedule:run drives everything.
| Endpoint | Returns |
|---|---|
GET / |
Dashboard (Blade view) |
GET /history/{coin} |
Last 20 resolved trades page for a coin |
GET /api/predictions |
JSON — all coins, next-slot predictions + accuracy |
GET /api/predictions/{coin} |
JSON — single coin next-slot-forward predictions |
The dashboard JS polls /api/predictions every 60 seconds and updates the DOM without a page reload.
| Key | Description |
|---|---|
ANTHROPIC_API_KEY |
Your Anthropic API key |
CLAUDE_MODEL |
Claude model ID (default: claude-haiku-4-5-20251001) |
BINANCE_API_URL |
Binance base URL (default: https://api.binance.com) |
BINANCE_API_URLS |
Comma-separated Binance fallback base URLs |
GROK_API_KEY |
Your xAI Grok API key (optional, for enhanced analysis) |
'claude' => [
'api_key' => env('ANTHROPIC_API_KEY'),
'model' => env('CLAUDE_MODEL', 'claude-haiku-4-5-20251001'),
'base_url' => 'https://api.anthropic.com',
],
'binance' => [
'api_url' => env('BINANCE_API_URL', 'https://api.binance.com'),
'api_urls' => array_values(array_filter(array_map(
'trim',
explode(',', env(
'BINANCE_API_URLS',
'https://api.binance.com,https://api-gcp.binance.com,https://data-api.binance.vision'
))
))),
],To switch to a different Claude model:
- Update
CLAUDE_MODELin.env - If the new model requires prompt changes, update the system prompt in
app/Services/ClaudeService.php - Adjust
max_tokensinClaudeService::predictSlots()if needed
- Add the coin slug and Binance symbol to
BinanceService::COIN_SYMBOLS - Add the coin to the
COINSconstant in:PredictionServiceDashboardControllerApiControllerPruneOldData
- Add the coin logo/URL mappings in
dashboard.blade.phpandhistory.blade.php - Add the coin to the
COINSJS array indashboard.blade.php - Verify the coin exists on
myriad.markets/candles/{coin}
- All datetimes are stored and compared in UTC.
config/app.phptimezone is set toUTC. - MySQL
NOW()may differ from PHPCarbon::now('UTC')if your MySQL server runs on local time. The app uses PHP Carbon for all comparisons — this is intentional and correct. - Dashboard/API target the next slot first. If next-slot rows are missing, cards show
Awaiting prediction...until a successful predict run. - Skipped slots (fewer than 3 signals agreeing) are shown on the dashboard with the reason — this is intentional, not a failure.
- Predictions expire as slots pass. If the scheduler isn't running, run
php artisan candlecall:predictmanually to refresh. - The resolver waits 6 minutes after a slot closes before fetching actual candles (to ensure Binance has the data). It retries up to 5 times before giving up on a slot.
- Not financial advice.