Updated Jun 21, 2026 Overview

Solana Arbitrage Trading

An automated arbitrage bot trading between JitoSOL and cbBTC (Coinbase-wrapped Bitcoin) on the Solana blockchain via the Jupiter aggregator. The goal is to accumulate JitoSOL through repeated buy-low/sell-high roundtrips.

Bot script: trading_bot.py (runs on GitHub Actions)

Tech stack: Python 3.12, Solana RPC (Alchemy), Jupiter Aggregator API, GitHub Actions, Slack webhooks

Django integration: dashboard/ app on dolejsek.cz — syncs run data, displays history, manages config


How It Runs

The bot executes one cycle per trigger — no persistent process. There are two trigger modes:

1. GitHub Actions cron — the workflow runs on its own schedule. Timing is imprecise (native GitHub cron).

2. Dash agent price monitoring (primary)run_dash fires every 10 minutes via cron on dolejsek.cz: - Syncs the latest run data from GitHub Actions artifacts into the DB - Checks heartbeat: if it's a whole hour (XX:00), fires the bot unconditionally as a safety net - Otherwise: fetches the current JitoSOL/cbBTC price from Jupiter and compares it against the active slot thresholds - If price crosses a BUY or SELL threshold → fires a workflow_dispatch event on the GitHub repo, triggering the bot immediately

This gives near real-time responsiveness without running a persistent process.

Mutual exclusion — only one trigger can be active at a time. The config modal (same modal used for bot parameters) has two independent toggles: - Bot Autorun — enables/disables the GitHub Actions cron schedule (comments/uncomments the schedule: block in bot.yml and commits it) - Dash — enables/disables the Dash price monitor (is_active flag in dash.conf)

Turning Dash ON while Bot Autorun is active is blocked at the API level (DashToggleView) — the toggle reverts and shows a warning. The reverse direction (Bot Autorun on while Dash is on) is the operator's responsibility to manage via the same modal. Both cannot run simultaneously.


Trading Strategy — The Slot System

Each slot is an independent position holding 1.5 JitoSOL of capital. Slots operate in one of two states:

State Meaning Trigger
JitoSOL Waiting to buy — holds JitoSOL Fires BUY when price drops to next_swap_price
cbBTC Open position — holds cbBTC Fires SELL when price rises to next_swap_price

Slot count at any moment: - Always exactly one JitoSOL slot — the buy ladder position, repositioned below current price after every cycle - Zero or more cbBTC slots — each is an open position from a previous BUY, waiting for the market to move up to its individual sell price - Total open slots grows with each BUY and shrinks with each SELL — reflecting market movement history - Maximum: 20 slots (configurable). Each holds 1.5 JitoSOL.

Per cycle (one GitHub Actions run): 1. Fetch current JitoSOL balance and JitoSOL/cbBTC price from Jupiter 2. Scan all slots — execute at most one swap per cycle (break after first hit) 3. Run optimize_slots() — reposition the JitoSOL slot in a step-ladder below current price 4. Save slots.json as a GitHub Actions artifact for the next run to load 5. Log summary and send Slack notification on BUY or SELL

Pre-SELL profit check: Before executing a SELL, the bot verifies the quote would return at least 1 lamport more JitoSOL than was spent on the original BUY. If slippage or fees would cause a loss, the SELL is blocked for that attempt.


One Roundtrip

A complete roundtrip = one BUY + one SELL on the same slot.

  • BUY: JitoSOL → cbBTC. Slot transitions from JitoSOL to cbBTC state. next_swap_price is set to buy_price × (1 + SWAP_THRESH).
  • SELL: cbBTC → JitoSOL. Slot transitions back to JitoSOL state (or is closed if above MIN_SLOTS).
  • Profit = JitoSOL received on SELL − JitoSOL spent on BUY.
  • Profit metric is JitoSOL accumulated — USD value is tracked for reference only.

Configuration (trading-bot.conf)

INI file committed to the GitHub repo. Key parameters:

Parameter Current Meaning
MIN_SLOTS 1 Minimum number of slots to keep open
MAX_SLOTS 20 Maximum total slots allowed
BASE_STEP 0.005 Base price step between slots (0.5%)
SWAP_THRESH 0.0075 Spread between BUY and SELL price (0.75%)
SAFETY_THRESH 0 cbBTC safety haircut after BUY
SLIPPAGE_BPS 75 Slippage tolerance in basis points
COMPUTE_UNIT_PRICE 200000 Priority fee in micro-lamports
MAX_RETRIES 3 Swap retry attempts per cycle
ALLOW_BUY / ALLOW_SELL TRUE Kill switches for each direction

The Django dashboard can read the live config from DB and push changes back to GitHub via the upload_config() method, which commits an updated .conf file to the repo.


Django Integration (dashboard/ app)

The dashboard Django app bridges the GitHub-hosted bot with dolejsek.cz.

DB Models

Model Purpose
Run One record per GitHub Actions run — outcome, price, timestamps, totals
Swap One record per BUY or SELL — on-chain amounts, block, tx signature
Roundtrip Pairs a BUY swap with its matching SELL swap
Slot Slot state snapshot linked to each run (M2M)
Config Mirrors trading-bot.conf and the workflow YML from GitHub

Sync Flow

manage.py sync_runsSyncProcessor.download_run_data(): 1. Pulls GitHub Actions run metadata (paginated) 2. Downloads artifacts (ZIP containing swaps.log + slots.json) for each new run 3. Parses the log via regex to extract: outcome (BUY/SELL/ERROR/no_action), price, tx signature, slot index 4. Fetches on-chain swap details via Alchemy RPC (SolanaProcessor) 5. Creates Run, Swap, Roundtrip, and Slot records in the DB

For failed runs with no artifact, slot state is carried forward from the previous run.

Dash Agent Integration

Dash reads from these models to answer questions about bot performance. His observe() method (called by run_dash every 10 minutes) is the price monitoring loop — it does not just report, it actively triggers the bot when thresholds are crossed.

Notifications

  • BUY or SELL: Slack webhook with amounts, price, and Solscan tx link. Also creates a TeoNotification for Teo's morning briefing.
  • ERROR or FAILURE: TeoNotification with urgent priority.
  • No action / price check failure: Silent — no notification created.

Dashboard Views

Run list, run detail, swap list, roundtrip list. Config editor with live push to GitHub. Workflow enable/disable toggle (comments/uncomments the cron schedule in the YML and commits it).


Tokens

Token Mint Decimals
JitoSOL J1toso1uCk3RLmjorhTtrVwY9HJ7X8V9yYac6Y7kGCPn 9
cbBTC cbbtcf3aa214zXHbiAZQwf4122FBYbraNdFqgw4iMij 8
USDC EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v 6 (reference only)

Price is expressed as JitoSOL per cbBTC, derived by quoting 0.01 cbBTC → JitoSOL via Jupiter and scaling.


Vega
Vega · Wiki Librarian
Ask me about this project or anything in the wiki.