Skip to content

About

Crypto perpetual futures research workspace built on NautilusTrader — download real exchange ticks, backtest on them, tune parameters with Optuna, and run the same strategy live on Binance

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

Nautilus Trading Workspace

Algorithmic trading research & execution workspace for crypto perpetual futures, built on NautilusTrader. It covers the full loop:

download exchange tick data → backtest on real ticks → optimize parameters with Optuna → run live on Binance.

Python NautilusTrader Package manager


Overview

Everything is driven by a small set of strategy modules and three command-line scripts. Backtests and optimizations run against real trade ticks (not synthetic OHLC) downloaded from Binance, Gate.io and Bybit and stored locally as Parquet. The same strategy code that is backtested and tuned can then be deployed live on Binance USDT-margined perpetual futures.

Piece What it does
strategies/ Trading strategy modules (signal + order management)
scripts/download_ticks.py Download historical trade ticks from an exchange
scripts/run_backtest.py Backtest a strategy on ticks, print stats & reports
scripts/optimize_volume_spike.py Optuna parameter search (multi-objective / scored)
scripts/run_live_binance.py Run a strategy live on Binance futures
configs/ Pair presets, optimizer ranges, live bot config, API keys

Strategies

1. VolumeSpikeLong — primary strategy

Long-only momentum entry on a volume + price spike.

  • Signal: a bar whose close-to-close rise ≥ price_rise_pct and whose volume ≥ volume_multiplier × the average volume over the last lookback_bars bars.
  • Entry: market BUY (immediate, taker fee).
  • Exit: stop-loss is always placed. Optionally a take-profit, and/or a trailing stop that arms after price moves trailing_activation_pct in profit and then follows the high by trailing_stop_pct. Whichever exit triggers first closes the position.
  • One position per instrument at a time.

This is the strategy that is parameter-optimized and ships with tuned presets in configs/volume_spike_long.json. See strategies/volume_spike_long.py.

2. PullbackLong — limit-entry pullback

Long-only strategy that waits for a pullback instead of chasing the spike.

  • Signal: a bullish spike bar (close > open, rise ≥ candle_rise_pct, volume > 0).
  • Entry: a Limit BUY placed entry_offset_pct below that bar's close, so it fills on the retrace (maker fee). Can also be configured as a market-if-touched entry (taker).
  • Exit: take-profit + stop-loss, each configurable as maker (limit) or taker (market-if-touched). Supports pre-placed reduce-only exits so they sit on the exchange for live trading, with full partial-fill handling.

This is the strategy wired into the live Binance runner. See strategies/pullback_long.py.

3. MACD — reference example

A minimal MACD zero-cross strategy (long when MACD crosses above zero, short when below), adapted from the NautilusTrader tutorial. Kept as a compact reference for how a Strategy / StrategyConfig pair is structured. See strategies/macd_strategy.py.


Project Structure

├── strategies/
│   ├── volume_spike_long.py   # primary: volume/price spike, long-only
│   ├── pullback_long.py       # limit-entry pullback (used live)
│   └── macd_strategy.py       # MACD crossover reference example
├── scripts/
│   ├── download_ticks.py      # download trade ticks (Binance / Gate / Bybit)
│   ├── run_backtest.py        # backtest on real ticks + HTML reports
│   ├── optimize_volume_spike.py  # Optuna parameter optimization
│   ├── run_live_binance.py    # live trading on Binance USDT-M futures
│   └── utils/                 # tick helpers, fee/exchange comparisons, order tests
├── configs/
│   ├── volume_spike_long.json      # tuned pair presets (backtest)
│   ├── optimize_volume_spike.json  # parameter search ranges per pair
│   ├── bot/live_binance.json       # live bot config (pairs, leverage, sizing)
│   └── secrets.json                # Binance API keys (gitignored)
├── catalog/                   # Parquet tick catalog (gitignored, per-machine)
├── db/                        # Optuna study databases (gitignored)
├── reports/                   # generated HTML backtest reports (gitignored)
└── pyproject.toml

Installation

Dependencies are managed with uv.

# Install uv (if not already installed)
curl -LsSf https://astral.sh/uv/install.sh | sh

# Install dependencies (creates .venv automatically)
uv sync

Requires Python 3.12+. All scripts are run through uv run python ....


Workflow

1. Download tick data

Trade ticks are downloaded per symbol/exchange and stored as Parquet under catalog/data/trade_tick/{SYMBOL}-PERP.{EXCHANGE}/. This directory is not committed (large files) — each machine downloads its own data.

# Full download from a start date
uv run python scripts/download_ticks.py --exchange binance --symbol SIREN --start 2025-01-01

# Backfill older history behind existing data
uv run python scripts/download_ticks.py --exchange gate --symbol FHE --prepend 2025-04-10

# Append only new data (Binance only)
uv run python scripts/download_ticks.py --exchange binance --symbol SIREN --incremental

Supported exchanges: binance, gate, bybit.

2. Backtest

Backtests run on real trade ticks with a 10,000 USDT starting balance, 5× leverage and a realistic maker/taker fee model. Parameters come either from a named preset in configs/volume_spike_long.json or from explicit CLI overrides.

# Run a tuned preset by name
uv run python scripts/run_backtest.py \
    --strategy volume_spike_long \
    --pair beat \
    --timeframe 15m \
    --start 2025-01-01

# Or specify all parameters manually
uv run python scripts/run_backtest.py \
    --strategy volume_spike_long \
    --pair siren \
    --start 2025-01-01 \
    --timeframe 15m \
    --lookback 50 --rise 0.4 --sl 12.5 --tp 5.5 --vol-mul 12.1 \
    --trailing-activation 0.0 --trailing-stop 0.0

Output includes win rate, total / average P&L, profit factor, max drawdown, and P&L broken down by week and by month (with commissions). Add --generate-report trades for an interactive HTML report, or --export-trades out.csv to dump every position.

Timeframes: 1m, 5m, 15m, 30m, 1h, 4h, 1d.

3. Optimize (Optuna)

optimize_volume_spike.py searches the parameter space with Optuna and stores every trial in a SQLite study you can browse in the dashboard. Search ranges per pair live in configs/optimize_volume_spike.json as [low, high, step].

uv run python scripts/optimize_volume_spike.py \
    --pair siren \
    --start 2025-01-01 \
    --end 2026-01-01 \
    --trials 5000 \
    --workers 5 \
    --sampler tpe \
    --mode multiparam \
    --timeframe 15m \
    --db db/optuna_volspike_siren_15m.db \
    --reset

# Inspect the study
uv run optuna-dashboard sqlite:///db/optuna_volspike_siren_15m.db --port 8081

Samplers: tpe (default) or nsga2. Modes:

  • pareto — multi-objective: maximize Sharpe, total P&L, and −|max drawdown| simultaneously.
  • multiparam — single weighted score (sigmoid-normalized Calmar / Sharpe / profit factor).
  • zero-dd — prioritizes strategies with (near-)zero drawdown.

Metrics computed per trial: Sharpe, Sortino, Calmar, profit factor, win rate, total P&L, max drawdown, and trade count.

4. Live trading (Binance futures)

run_live_binance.py runs a strategy live on Binance USDT-margined perpetual futures through a NautilusTrader TradingNode (with position reconciliation on startup). The live bot config lives in configs/bot/live_binance.json.

# Live (real account)
PYTHONPATH=. uv run python scripts/run_live_binance.py \
    --config configs/bot/live_binance.json

# Testnet
PYTHONPATH=. uv run python scripts/run_live_binance.py \
    --config configs/bot/live_binance.json \
    --testnet

API keys are read from the BINANCE_API_KEY / BINANCE_API_SECRET environment variables, or from configs/secrets.json (binance_api_key / binance_api_secret). For testnet, set BINANCE_TESTNET_API_KEY / BINANCE_TESTNET_API_SECRET. configs/secrets.json is gitignored — never commit real keys.


Configuration

File Purpose
configs/volume_spike_long.json Tuned VolumeSpikeLong presets per pair (used by the backtester). Each preset is a full parameter set with a note on its historical behavior.
configs/optimize_volume_spike.json Optuna search ranges [low, high, step] per pair, plus a trailing on/off flag.
configs/bot/live_binance.json Live bot: trader id, testnet flag, leverage, timeframe, and per-pair strategy settings.
configs/secrets.json Binance API keys (gitignored).

Note: preset values in these configs are the result of long optimization runs — treat them as data. When adding parameters, only add new fields; don't overwrite existing tuned values.


Data

Tick data is stored as Parquet in catalog/data/trade_tick/{SYMBOL}-PERP.{EXCHANGE}/, with instrument metadata under catalog/data/crypto_perpetual/. The catalog/, db/ and reports/ directories are gitignored (large / machine-local), so a fresh clone starts empty — run download_ticks.py to populate ticks before backtesting.

Quick per-month tick count for a symbol:

uv run python -c "
import pyarrow.parquet as pq, pandas as pd, os
from collections import defaultdict
d = 'catalog/data/trade_tick/SIREN-PERP.BINANCE'
monthly = defaultdict(int)
for f in sorted(os.listdir(d)):
    if not f.endswith('.parquet'): continue
    ts = pd.to_datetime(pq.read_table(os.path.join(d, f), columns=['ts_init'])['ts_init'].to_pandas(), unit='ns')
    for m, c in ts.dt.to_period('M').value_counts().items(): monthly[str(m)] += c
for m in sorted(monthly): print(f'{m}: {monthly[m]:>12,}')
print(f'TOTAL: {sum(monthly.values()):>12,}')
"

Links

About

Crypto perpetual futures research workspace built on NautilusTrader — download real exchange ticks, backtest on them, tune parameters with Optuna, and run the same strategy live on Binance

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages