Zillions Core is a professional-grade, scalable, and modular trading bot engine built with Node.js, TypeScript, and a Hexagonal Architecture. It is designed to be exchange-agnostic, strategy-pluggable, and production-ready with built-in risk management and structured logging.
- 🚀 Key Features
- 🛠 Prerequisites
- 📦 Installation
- 🏃♂️ Usage
- 📦 Zillions SDK
- 🛠 Available Strategies
- 🛡 Risk Management
- Deployment
- 🏦 Vault System
- 🔮 Roadmap
- 🚀 REST API
- 🤝 Contributing
- 🔗 Connect
- Hexagonal Architecture: Core logic is isolated from external adapters (Exchanges, Database), allowing easy swapping of components.
- Multi-Exchange Support:
- Real Market Data: Decoupled data provider supporting
Binance Public API(Free, no-auth) for Paper Trading and Backtesting. - Paper Trading: Simulated matching engine using real-world price data for realistic testing.
- Prepared for: Binance, Hyperliquid, Drift, CCXT, OKX (Stubs ready).
- Real Market Data: Decoupled data provider supporting
- Robust Risk Management:
- TradeManager: Global position management system that monitors all open positions across all symbols and strategies.
- Automated Protection: Stop Loss and Take Profit execution with real-time price monitoring.
- Middleware Checks: Max Order Size and Daily Drawdown limits.
- Backtesting Engine: Dedicated runner to validate strategies against historical market data (no random walks).
- Live Historical Replay: Simulate paper trading over historical periods using real engine logic and persist results to Supabase.
- Strategy System: Pluggable strategy interface. Simply add a new class to
src/strategies. - Persistence: Integration with Supabase (PostgreSQL) for trade history and portfolio snapshots.
- Vault System: Implementation of a decentralized-style vault for pooled funding. Automatically manages share prices (LPs) based on portfolio performance and handles dynamic deposits/withdrawals.
- Production Ready:
- Smart Polling: Interval-based execution loop to minimize API overhead and synchronize with candle boundaries.
- Structured Logging: JSON-formatted logs via
winston. - Dockerized: Optimized multi-stage
Dockerfile. - Process Management:
PM2ecosystem config included.
- Node.js: v18+
- npm: v9+
- Supabase: (Optional) For data persistence.
- Docker: (Optional) For containerized deployment.
-
Clone the repository:
git clone https://github.com/your-username/zillion-core.git cd zillion-core -
Install & Build for SDK Usage:
npm install npm run build npm link # Makes the 'zillions' package available locally
Tip
After running npm link in this directory, you can use the SDK in any other local project by running npm link zillions in that project's root.
-
Environment Setup: Copy the example configuration:
cp .env.example .env
Edit
.envto configure your exchange and database credentials:NODE_ENV=development # Exchange Selection EXCHANGE_DRIVER=PAPER # Paper Trading Settings PAPER_INITIAL_BALANCE=10000 PAPER_BALANCE_ASSET=USDT # Vault Settings VAULT_ENABLED=false VAULT_SHARE_ASSET=ZILLIONS # Supabase (Service role key required for vault access) # IMPORTANT: Use the SERVICE ROLE key (not anon key) to bypass RLS and keep data private # Find this in: Supabase Dashboard → Settings → API → service_role key SUPABASE_URL= SUPABASE_KEY= # Strategy Settings STRATEGY_NAME=MACD STRATEGY_SYMBOL=BTC/USDT STRATEGY_INTERVAL=1d # Real-time Monitoring (seconds between checks) TICK_INTERVAL_SECONDS=30 # Leverage Settings LEVERAGE_ENABLED=true LEVERAGE_VALUE=5 MAX_LEVERAGE_UTILIZATION=50 # Vercel / Cron Configuration CRON_SECRET=your_random_secret_string_here # Risk Management (All percentages as full numbers, e.g. 5 = 5%) MAX_DAILY_DRAWDOWN_PERCENT=3 MAX_TOTAL_RISK_PERCENT=10 MAX_POSITION_SIZE_PERCENT=10 DEFAULT_STOP_LOSS_PERCENT=2 DEFAULT_TAKE_PROFIT_PERCENT=6 RISK_PER_TRADE_PERCENT=1 # Trailing Stop Loss TRAILING_STOP_ENABLED=true TRAILING_STOP_ACTIVATION_PERCENT=1 TRAILING_STOP_TRAIL_PERCENT=1 # Position Management ALLOW_MULTIPLE_POSITIONS=false CLOSE_ON_OPPOSITE_SIGNAL=true MAX_OPEN_TRADES=5
-
Database Setup (Supabase): Run the SQL methods found in
supabase_schema.sqlin your Supabase SQL Editor to create the necessary tables (trades,portfolio_snapshots,backtest_results).
The core bot runs standalone with basic Supabase tables. If you want to offer your trading bot to other users and enable a referral/commission system:
👉 Head over to the Zillions App Repository
The app extends the core with:
- User Authentication - Users can sign up and manage their accounts
- Invitation System - Create referral links with custom commission rates (e.g., 10%)
- Commission Tracking - Real-time commission payments to inviters when their referrals profit
- Dashboard UI - User-friendly interface to view portfolios, trades, and earnings
How the Commission System Works:
- Users create invite links with configurable commission rates (e.g., 5%, 10%, 15%)
- New users register using an invite code
- When a referred user closes a profitable trade, the inviter earns a commission
- Commissions are calculated per-trade in real-time by the bot
- Both inviter and invited user can view their commission history in the app
Database Setup for App+Bot:
If you deploy the app, run app/frontend_schema.sql instead of the basic supabase_schema.sql - it includes all tables for the commission system.
Runs the bot with hot-reloading.
npm run devBuilds the TypeScript code and starts the optimized engine.
npm run build
npm startRuns the simulation runner against historical data. Includes Winrate, Profit Factor, and Buy & Hold benchmarks.
npm run backtestRuns comprehensive backtests comparing all 24 built-in strategies against each other. Generates detailed reports with rankings, performance metrics, and Buy&Hold analysis.
npm run backtest:compareFeatures:
- All Strategies: Automatically tests all available strategies (24 total)
- Comprehensive Report: Ranked performance table with trades, winrate, profit factor, PnL %, and Buy&Hold differences
- Best/Worst Analysis: Highlights top performers and statistical summaries
- Configurable: Uses
BACKTEST_CANDLE_COUNTenv var (default: 100 candles) - Buy&Hold Comparison: Shows which strategies outperform passive holding
Usage Examples:
# Compare all strategies on BTC/USDT 1d with default settings
npm run backtest:compare
# Compare on different symbol/timeframe
npm run backtest:compare ETH/USDT 4h
# With verbose logging
npm run backtest:compare BTC/USDT 1d verboseConfiguration:
Set BACKTEST_CANDLE_COUNT in your .env to change the number of historical candles used for backtesting (default: 100).
The Replay feature simulates paper trading over a historical period using the exact same engine logic as production. Results are stored in the main database alongside live trades for analysis in your dashboard.
Key Benefits:
- True Simulation: Uses the same BotEngine, VaultManager, CommissionManager, and PortfolioManager as live trading
- Time-Aware Vault: Vault transactions are filtered by simulation time (deposits only count after their timestamp)
- Commission Tracking: Commission payments use trade timestamps
- Seamless Continuation: After replay completes, run
npm startto continue trading into real-time from where replay left off
npm run replayOptions:
symbol: Trading pair (default: from.env)interval: Timeframe (default: from.env)days: Number of days to replay (default: 120)
Example:
# Replay 30 days of 1h candles for ETH/USDT
npm run replay ETH/USDT 1h 30
# Replay 7 days of 15m candles
npm run replay BTC/USDT 15m 7The replay system advances simulation time through historical candles:
- Candle Fetching: Downloads historical candles from Binance Public API
- Time Synchronization: A shared
SimulationTimeProvidercoordinates all time-sensitive operations:VaultManager.getTotalDepositedBalance()only includes transactions wheretimestamp <= simulationTimePortfolioManagergenerates snapshots with simulation timestampsCommissionManageruses trade timestamps for commission tracking
- Engine Tick Loop: For each candle:
- Sets simulation time to candle's end time
- Updates market data buffer
- Runs
engine.tick()which processes signals, manages positions, and executes trades
When migrating historical vault transactions, insert them with their original timestamps:
INSERT INTO vault_transactions (email, amount, shares, type, timestamp)
VALUES
('user@example.com', 10000, 10000, 'DEPOSIT', 1700000000000),
('user@example.com', 5000, 4852.46, 'DEPOSIT', 1702500000000);During replay:
- Before
1700000000000: Balance = 0 - Between
1700000000000and1702500000000: Balance = 10,000 - After
1702500000000: Balance = 14,852.46
When replay completes:
- The database contains all trades, vault transactions, and portfolio snapshots from the replay period
- Simply run
npm startto begin live trading - The bot will continue from real-time, seamlessly transitioning from where replay left off
Important: Replay and live trading share the same database. Trades and vault transactions from replay are preserved and visible in the dashboard alongside future live activity.
Open positions manually with professional risk management (SL/TP and sizing calculated automatically based on your .env risk settings).
# Open a Long position
npm run open:long -- --symbol=BTC/USDT
# Open a Short position
npm run open:short -- --symbol=BTC/USDT
# Optional: Custom Stop Loss (sl) and Take Profit (tp) percentages
npm run open:long -- --symbol=BTC/USDT --sl=1.5 --tp=4.5Close all open positions across all symbols immediately.
npm run close:tradesClears all data from the database tables while preserving table structures. Useful for resetting your development environment.
npm run cleanupZillion Core supports runtime strategy configuration for both long-running and serverless deployments:
const bot = new BotEngine('MACD');
await bot.start('BTC/USDT', '15m', {
// Strategy-specific configuration
rsiPeriod: 14,
rsiOverbought: 70,
rsiOversold: 30,
macdFast: 12,
macdSlow: 26,
macdSignal: 9
});const bot = new BotEngine('MACD');
await bot.tick('BTC/USDT', '15m', {
// Same configuration options available
rsiPeriod: 14,
rsiOverbought: 70,
rsiOversold: 30
});Benefits:
- Dynamic Configuration: Adjust strategy parameters without code changes
- Environment Flexibility: Different configs for development/production
- Strategy Agnostic: Works with any strategy that accepts configuration
- Serverless Compatible: Full configuration support in stateless deployments
Zillion Core includes dynamic, research-backed default parameters for all standard strategies. These defaults are automatically applied based on your configured timeframe (STRATEGY_INTERVAL) if no custom parameters are provided.
How It Works:
- Check Config: The bot first checks for explicitly provided parameters (e.g., in
src/index.tsor via API). - Load Dynamic Default: If no custom config is found, it loads optimal defaults for the current
STRATEGY_INTERVAL(e.g., "Scalping" settings for1m/5m, "Trend" settings for1h/4h). - Fallback: If no timeframe match is found, it falls back to a hardcoded safe default.
Supported Strategies:
All standard strategies (MACD, RSI, BB, STOCH, etc.) support this dynamic loading. You can view and edit these defaults in:
src/config/strategy_defaults.ts
Example Precedence:
User Config > Timeframe Default (1m, 1h, etc.) > Hardcoded Fallback
Supported Timeframes:
1m,5m(Scalping)15m,1h,4h(Intraday/Swing)1d(Long-term)
You can easily override these defaults by passing your own values during bot initialization.
Long-Running Bot (src/index.ts):
// Override defaults for MACD on 15m timeframe
await bot.start('BTC/USDT', '15m', {
fast: 14, // Custom Fast EMA
slow: 28, // Custom Slow EMA
signal: 9 // Standard Signal
});Serverless Cron (api/cron.ts):
// Override defaults for RSI on 1h timeframe
await bot.tick('ETH/USDT', '1h', {
rPeriod: 21, // Custom RSI Period
kPeriod: 3,
dPeriod: 3
});You can use Zillions Core as an SDK in your own projects by installing it directly from the GitHub repository.
Install the SDK directly from GitHub in your project:
npm install https://github.com/zillionsapp/core.gitTip
This installs the built package directly from the repository, so you don't need to clone or build the project locally.
Import the BotEngine and start the bot with a built-in strategy:
import { BotEngine, startApi } from 'zillions';
async function main() {
// Optional: Start the dashboard on port 3000
startApi(3000);
const bot = new BotEngine('MACD');
await bot.start('BTC/USDT', '15m');
}Zillion's strategy system is highly extensible. You can implement the IStrategy interface and inject your instance directly into BotEngine.
import { IStrategy, Candle, Signal } from 'zillions';
class MyStrategy implements IStrategy {
name = 'MY_STRATEGY';
async update(candle: Candle): Promise<Signal | null> {
if (candle.close > 100) {
return { action: 'BUY', symbol: candle.symbol, stopLoss: 5, takeProfit: 10 };
}
return null;
}
}
const bot = new BotEngine(new MyStrategy());For strategies with dynamic stop losses, custom exit conditions, or complex position management:
import { IStrategy, StrategyConfig } from '../interfaces/strategy.interface';
import { Candle, Signal, Trade } from '../core/types';
export class AdvancedStrategy implements IStrategy {
name = 'ADVANCED_STRATEGY';
private positionCount = 0;
init(config: StrategyConfig): void {
// Initialize with config
}
async update(candle: Candle): Promise<Signal | null> {
// Entry logic - can still use static SL/TP or rely on checkExit
if (this.shouldEnter(candle)) {
return {
action: 'BUY',
symbol: candle.symbol,
stopLoss: 2, // Wide initial stop, will be managed dynamically
takeProfit: 20
};
}
return null;
}
async checkExit(trade: Trade, candle: Candle): Promise<'HOLD' | 'CLOSE' | { action: 'UPDATE_SL' | 'UPDATE_TP' | 'PARTIAL_CLOSE', quantity?: number, newPrice?: number }> {
const profitPercent = calculateProfitPercent(trade, candle.close);
// Dynamic trailing stop based on profit
if (profitPercent > 3) {
const trailPercent = Math.min(1.5, profitPercent * 0.3); // Tighter trail as profit grows
const newSL = trade.side === 'BUY'
? candle.close * (1 - trailPercent / 100)
: candle.close * (1 + trailPercent / 100);
return { action: 'UPDATE_SL', newPrice: newSL };
}
// Time-based exit (avoid holding overnight)
const positionAge = Date.now() - trade.timestamp;
if (positionAge > 8 * 60 * 60 * 1000) { // 8 hours
return 'CLOSE';
}
// Momentum-based exit
if (this.detectReversal(candle)) {
return 'CLOSE';
}
return 'HOLD';
}
async onPositionOpened(trade: Trade): Promise<void> {
this.positionCount++;
console.log(`Position opened: ${trade.id}, total positions: ${this.positionCount}`);
// Set up custom tracking, alerts, etc.
}
async onPositionClosed(trade: Trade): Promise<void> {
this.positionCount--;
const pnl = calculatePnL(trade);
console.log(`Position closed: ${trade.id}, PnL: ${pnl}%, total positions: ${this.positionCount}`);
// Performance analysis, logging, etc.
}
private shouldEnter(candle: Candle): boolean {
// Your entry conditions
return candle.close > this.calculateSupport(candle.symbol);
}
private detectReversal(candle: Candle): boolean {
// Custom reversal detection logic
return false; // Placeholder
}
private calculateSupport(symbol: string): number {
// Calculate support level
return 0; // Placeholder
}
}
function calculateProfitPercent(trade: Trade, currentPrice: number): number {
return trade.side === 'BUY'
? ((currentPrice - trade.price) / trade.price) * 100
: ((trade.price - currentPrice) / trade.price) * 100;
}
function calculatePnL(trade: Trade): number {
if (!trade.exitPrice) return 0;
return calculateProfitPercent(trade, trade.exitPrice);
}For long-running processes, use the start() method with your custom strategy:
import { BotEngine, startApi } from 'zillions';
async function main() {
// Optional: Start the dashboard on port 3000
startApi(3000);
// Use your custom strategy in a long-running bot
const bot = new BotEngine(new AdvancedStrategy());
await bot.start('BTC/USDT', '15m', {
// Optional: Strategy-specific configuration
rsiPeriod: 14,
rsiOverbought: 70,
rsiOversold: 30
});
}
main().catch(console.error);For serverless environments, use the tick() method for stateless execution:
import { BotEngine } from 'zillions';
export default async function handler(req, res) {
const bot = new BotEngine(new MyCustomStrategy());
await bot.tick('BTC/USDT', '1h');
res.status(200).json({ status: 'ok' });
}Zillion includes 24 professional-grade strategies from the indicatorts library, organized by category:
| Category | Strategies |
|---|---|
| Trend | MACD, APO, AROON, BOP, CFO, KDJ, PSAR, TYPPRICE, VWMA, VORTEX |
| Momentum | AO, ICHIMOKU, RSI2, STOCH, WILLR |
| Volatility | BB, AB, PO |
| Volume | CMF, EMV, FI, MFI, NVI, VWAP |
The RiskManager module (src/core/risk.manager.ts) implements professional risk management following the "Golden Sequence":
- Risk Per Trade: Fixed percentage of equity risked per trade (Default: 1%)
- Technical SL Levels: Stop Loss based on percentages of entry price (chart-based levels)
- Position Sizing: Calculated to match risk amount with technical SL distance
Key Concepts:
- Risk Amount:
Equity × RISK_PER_TRADE_PERCENT - SL Distance:
EntryPrice × STOP_LOSS_PERCENT - Position Size:
Risk Amount ÷ SL Distance
Practical Example:
"I want to risk max 1% of my $10,000 account on this trade."
- Scenario A (Tight Stop): SL at 1%.
- Risk: $100.
- Position Size: $10,000. (If price drops 1%, you lose $100).
- Scenario B (Wide Stop): SL at 5%.
- Risk: $100.
- Position Size: $2,000. (If price drops 5%, you lose $100).
Key Features:
- Consistent Risk: Every trade risks the same percentage of your account, regardless of volatility.
- Daily Drawdown Protection: Halts trading if equity drops by a specific percentage from the start-of-day balance. Resets daily at 00:00 UTC. (Default: 3%)
- Max Open Trades: Limits the total number of concurrent open positions to prevent over-exposure. (Default: 5)
Zillion Core includes professional leveraged trading with built-in safety measures:
How It Works:
- Margin Trading: Control larger positions with less capital
- Amplified Position Sizing: Leverage multiplies position size for same risk level
- Safety Limits: Automatic position reduction to prevent over-leveraging
- Liquidation Protection: Losses capped at margin amount (no account blowup)
Key Calculations:
- Margin Required:
position_value ÷ leverage - Position Size:
(risk_amount × leverage) ÷ sl_distance - P&L: Percentage returns (leverage doesn't amplify profit/loss percentages)
- Liquidation: Losses cannot exceed margin amount
Safety Features:
- Margin Limits: Maximum 95% of balance can be used as margin
- Position Caps: Maximum position size limited to prevent over-exposure
- Automatic Reduction: Position sizes reduced if they would exceed safety limits
- Balance Protection: Emergency buffers prevent account depletion
Configuration:
LEVERAGE_ENABLED=true
LEVERAGE_VALUE=5 # 5x leverage
RISK_PER_TRADE_PERCENT=1 # 1% risk per trade
MAX_LEVERAGE_UTILIZATION=50 # Max 50% leverage utilization (conservative)Example with 5x Leverage:
- Account: $10,000
- Risk: 1% ($100)
- SL: 5% of entry price
- Position Size: ($100 × 5) ÷ (5% × price) = Larger position with same $100 risk
- Margin Used: 20% of account (safe buffer maintained)
The TradeManager (src/core/trade.manager.ts) provides global position management across all trading activities:
- Centralized Monitoring: Tracks all open positions from any strategy or symbol in real-time.
- Automated SL/TP Execution: Continuously monitors price movements and automatically executes stop-loss and take-profit orders.
- Trailing Stop Loss: Dynamic stop loss that trails behind profitable price movements.
- Multi-Position Support: Unlike the previous single-position-per-engine limitation, TradeManager handles unlimited concurrent positions.
- Cross-Strategy Protection: Ensures risk management works regardless of which strategy opened the position.
- Real-time Price Tracking: Uses live market data to check exit conditions on every tick.
Key Benefits:
- No Position Left Behind: Even if a strategy instance stops, positions remain protected.
- Improved Risk Control: Centralized system prevents conflicting risk management logic.
- Scalability: Supports multiple strategies running simultaneously with proper position isolation.
Zillion Core now includes a suite of "Bulletproof" features designed to eliminate risk early and adapt to market conditions automatically. These features are enabled by default to ensure maximum safety.
1. Breakeven Trigger (The "Safety Net")
- Goal: Eliminate risk as soon as the trade moves in your favor.
- How it works: When a position reaches a configurable profit percentage (Default: 1%), the Stop Loss is automatically moved to your Entry Price + Fees.
- Benefit: If the market reverses after a small pop, you exit with $0 loss instead of a full Stop Loss hit. This dramatically improves your "non-losing" rate.
2. ATR-Based Dynamic Stops (The "Smart Guard")
- Goal: Adapt Stop Loss and Take Profit levels to current market volatility (Noise).
- How it works: Instead of arbitrary fixed percentages (e.g., 5%), the bot calculates the Average True Range (ATR) of the last 14 candles.
- Stop Loss:
1.5 x ATR(Tighter in quiet markets, wider in volatile ones). - Take Profit:
3.0 x ATR(Ensures a consistent 1:2 Risk/Reward ratio).
- Stop Loss:
- Benefit: Prevents being stopped out by normal market noise while ensuring targets are statistically reachable.
3. Trailing Stop Loss (The "Profit Locker")
- Goal: Let winners run while securing gains.
- How it works: Once a trade is profitable (Default: >2%), the Stop Loss trails the price distance (Default: 1%).
- Benefit: Captures the "fat tail" of big trends without manual intervention.
Configuration (Hardened Defaults):
# Breakeven Trigger
BREAKEVEN_TRIGGER_PERCENT=1 # Move SL to Entry at 1% profit
# Dynamic ATR Stops
USE_ATR_BASED_STOPS=true # Enable Volatility Sensing
ATR_PERIOD=14
ATR_MULTIPLIER_SL=1.5
ATR_MULTIPLIER_TP=3.0
# Trailing Stop
TRAILING_STOP_ENABLED=true # Enable Profit LockingZillion Core provides flexible position management to handle conflicting signals and maintain strategy control over risk management:
When a strategy generates a new signal while positions are already open, you can configure how the system responds:
- Close on Opposite Signal (
CLOSE_ON_OPPOSITE_SIGNAL=true): Automatically closes existing positions when a strategy signals the opposite direction. This prevents holding conflicting positions and ensures the strategy's latest intent is executed. - Allow Multiple Positions (
ALLOW_MULTIPLE_POSITIONS=true): Enables hedging by allowing multiple positions to be open simultaneously. The strategy can build complex position structures. - Force Close (Signal-level): Strategies can include
forceClose: truein their signal to override all risk management and immediately close conflicting positions before opening new ones.
# Position Management
ALLOW_MULTIPLE_POSITIONS=false # Allow hedging/multiple positions
CLOSE_ON_OPPOSITE_SIGNAL=false # Close existing position on opposite signal- Signal Generation: Strategy always generates signals regardless of existing positions
- Conflict Detection: Engine checks for positions that conflict with the new signal
- Resolution: Applies configured behavior:
- Force close conflicting positions if
signal.forceClose=true - Close positions on opposite signals if
CLOSE_ON_OPPOSITE_SIGNAL=true - Skip new signals if multiple positions not allowed and positions exist
- Allow new positions alongside existing ones if
ALLOW_MULTIPLE_POSITIONS=true
- Force close conflicting positions if
Strategies maintain full control over position management:
// Force close existing positions before opening new one
return {
action: 'SELL',
symbol: 'BTC/USDT',
forceClose: true // Closes all conflicting positions immediately
};By default, maintains backward compatibility - waits for positions to close naturally (via SL/TP) before opening new ones.
Benefits:
- Strategy Autonomy: Strategies can override risk management when needed
- Flexible Risk Management: Choose between conservative single-position or aggressive multi-position approaches
- Conflict Prevention: Avoid unintended hedging or conflicting positions
- Backward Compatible: Existing configurations continue to work unchanged
The PortfolioManager (src/core/portfolio.manager.ts) provides comprehensive portfolio analytics and snapshot generation:
- Real-time Metrics: Calculates PnL, Win Rate, Profit Factor, and other key performance indicators.
- Position Tracking: Maintains detailed information about open and closed trades with current valuations.
- Equity Monitoring: Tracks current balance and equity including unrealized gains/losses.
- Automated Snapshots: Generates portfolio snapshots periodically (every 5 minutes) for performance tracking.
- Historical Analysis: Stores complete trade history with entry/exit prices and realized PnL.
Key Metrics Calculated:
- PnL: Total realized profit/loss from closed trades.
- Win Rate: Percentage of profitable trades (0-100%).
- Profit Factor: Ratio of gross profits to gross losses.
- Open Trades: Current positions with unrealized PnL based on live market prices.
- Closed Trades: Historical trades with confirmed realized PnL.
- Current Equity: Total account value including unrealized gains/losses (
Wallet Balance + Unrealized PnL). - Current Balance: Available cash balance for new trades (
Wallet Balance - Used Margin). Note: This intelligently falls back to a calculated value if the exchange API is unavailable.
Key Benefits:
- Performance Tracking: Monitor trading performance with industry-standard metrics.
- Risk Assessment: Evaluate strategy effectiveness through comprehensive analytics.
- Portfolio Visibility: Real-time view of all positions and their current status.
- Historical Records: Complete audit trail of all trading activity.
Note
All risk management percentages are configured as full numbers in the .env file (e.g., 5 means 5%).
Zillion Core includes a professional Vault System designed for pooled funding and decentralized-style asset management. When enabled, the bot ignores the static PAPER_INITIAL_BALANCE and instead derives its trading capital dynamically from deposited funds.
The vault uses a Share Price (NAV) model similar to modern DeFi protocols or Traditional Finance funds:
- Initial State: Vault starts at a Share Price of 1.00.
- Deposits: Users receive shares based on the current Share Price (
Amount / SharePrice). - Performance: As the bot generates profit/loss, the Total Assets (Equity) of the vault changes, causing the Share Price to move up or down (
TotalAssets / TotalShares). - Withdrawals: Users burn shares to receive assets back at the current Share Price.
Enable the vault in your .env:
VAULT_ENABLED=true
VAULT_SHARE_ASSET=ZILLION-SHARES # The name of your LP token- Internal Initialization: The
VaultManageris managed internally by the exchange driver. - Dynamic Balance: The
PortfolioManagerautomatically queries the vault for the total deposited balance to use as the starting capital. - Persistence: Transactions (
DEPOSIT,WITHDRAW) and state snapshots are persisted to Supabase for full auditing.
- Equity-Linked Valuation: Share price is always calculated against real-time portfolio equity, ensuring accurate entry/exit for all participants.
- Withdrawal Verification: (Planned) Verification of available cash vs. margin-locked funds before processing withdrawals.
- Build Image:
docker build -t zillion-core . - Run Container:
docker run -d --env-file .env --name zillion-bot zillion-core
Zillion includes an ecosystem.config.js for process management.
npm install -g pm2
npm run build
pm2 start ecosystem.config.jsZillion is optimized for Vercel Cron deployment. This mode uses a "pulsed" execution model where the bot runs once per minute and state is recovered from Supabase.
- Preparation:
- Database: You must use Supabase for Vercel deployment. Run the SQL in
supabase_schema.sqlAND the migration script inwalkthrough.mdin your Supabase SQL Editor.
- Database: You must use Supabase for Vercel deployment. Run the SQL in
- Deployment:
- Import your project into Vercel.
- Add the following Environment Variables in the Vercel Dashboard:
SUPABASE_URL/SUPABASE_KEYEXCHANGE_DRIVER(useBINANCEorCCXTfor real trading)EXCHANGE_API_KEY/EXCHANGE_API_SECRETSTRATEGY_NAME,STRATEGY_SYMBOL,STRATEGY_INTERVALCRON_SECRET: Generate a random string (e.g. viaopenssl rand -base64 32).
- Security:
- Vercel will automatically detect
vercel.jsonand protect your cron endpoint using theCRON_SECRET. - The Express Dashboard API is also accessible at
https://your-domain.vercel.app/api/...via the bridging setup.
- Vercel will automatically detect
Vercel Hobby limited crons to once per day. To run your bot every minute for free:
- Use an External Pinger: Sign up for a free service like Cron-job.org.
- Configure the Job:
- URL:
https://your-project.vercel.app/api/cron - Schedule: Every 1 minute.
- Headers: Add
Authorization: Bearer your_cron_secret_here.
- URL:
- Execution: This will "wake up" your Vercel function every minute, bypassing the built-in cron limit.
Important
When running on Vercel, the bot does not use npm start. It is triggered automatically by the Vercel Cron scheduler (Pro) or an External Pinger (Hobby). Ensure you do not have the same account running locally simultaneously to avoid duplicate orders.
- Exchange Support: Implement Drift.trade adapter.
- Exchange Support: Implement Hyperliquid adapter.
- Strategies: Implement standard strategy library (RSI, MACD, etc.).
- Connectivity: REST APIs for custom dashboards.
- Connectivity: WebSocket for custom dashboards.
- UI: Build a simple in-built dashboard.
- Intelligence: AI/ML implementation for signal optimization.
Zillion Core includes a built-in REST API to expose portfolio data, trade history, market prices, and backtest functionality. The API is available in two deployment modes:
- Server Mode (
/src/api/): Full Express.js server for local development and VPS deployments - Serverless Mode (
/api/): Vercel-compatible serverless functions for production deployments
Both modes expose identical endpoints with the same request/response formats.
The API and Dashboard start automatically when you run the main bot:
npm run dev # or npm startAccess the dashboard at http://localhost:3000
To run only the API server:
npm run apiDeploy to Vercel and access endpoints at:
https://your-project.vercel.app/api/*
Endpoint: GET /health
Description: System health check to verify the API is running.
Response:
{
"status": "ok",
"timestamp": 1704384000000
}Example:
curl http://localhost:3000/healthEndpoint: GET /api/portfolio
Description: Retrieves the most recent portfolio snapshot including balance, equity, PnL, and performance metrics.
Response:
{
"id": "uuid",
"timestamp": 1704384000000,
"currentBalance": 10500.50,
"currentEquity": 10750.25,
"totalPnL": 750.25,
"totalPnLPercent": 7.50,
"winRate": 65.5,
"profitFactor": 2.1,
"totalTrades": 42,
"openPositions": 2,
"closedPositions": 40
}Error Responses:
404: No portfolio snapshots found500: Internal server error
Example:
curl http://localhost:3000/api/portfolioEndpoint: GET /api/portfolio-history
Description: Retrieves historical portfolio snapshots for charting. Data is cached and optimized for performance.
Query Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
period |
string | all |
Time period filter: 1d, 1w, 1m, 1y, all |
Response:
[
{
"timestamp": 1704384000000,
"currentEquity": 10750.25,
"currentBalance": 10500.50,
"totalPnL": 750.25
},
{
"timestamp": 1704297600000,
"currentEquity": 10600.00,
"currentBalance": 10400.00,
"totalPnL": 600.00
}
]Example:
# Get all historical data
curl http://localhost:3000/api/portfolio-history
# Get last 7 days
curl http://localhost:3000/api/portfolio-history?period=1w
# Get last 30 days
curl http://localhost:3000/api/portfolio-history?period=1mEndpoint: GET /api/trades
Description: Retrieves trade execution history including both open and closed positions with pagination support.
Query Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
symbol |
string | - | Filter trades by symbol (e.g., BTC/USDT) |
limit |
number | 50 |
Maximum number of trades to return |
offset |
number | 0 |
Number of trades to skip (for pagination) |
Response:
{
"trades": [
{
"id": "uuid",
"symbol": "BTC/USDT",
"side": "BUY",
"price": 45000.00,
"quantity": 0.1,
"timestamp": 1704384000000,
"status": "OPEN",
"stopLossPrice": 43000.00,
"takeProfitPrice": 48000.00,
"leverage": 5,
"strategy": "MACD",
"entryTime": 1704384000000,
"duration": null,
"exitPrice": null,
"pnl": null,
"pnlPercent": null
},
{
"id": "uuid",
"symbol": "ETH/USDT",
"side": "SELL",
"price": 2500.00,
"quantity": 2.0,
"timestamp": 1704297600000,
"status": "CLOSED",
"stopLossPrice": 2600.00,
"takeProfitPrice": 2300.00,
"leverage": 1,
"strategy": "RSI",
"entryTime": 1704297600000,
"duration": "2h 15m",
"exitPrice": 2350.00,
"exitReason": "TAKE_PROFIT",
"pnl": 300.00,
"pnlPercent": 6.0
}
],
"total": 42
}Example:
# Get all trades (first 50)
curl http://localhost:3000/api/trades
# Filter by symbol
curl http://localhost:3000/api/trades?symbol=BTC/USDT
# Pagination (get next 50 trades)
curl http://localhost:3000/api/trades?limit=50&offset=50
# Custom limit
curl http://localhost:3000/api/trades?limit=10Endpoint: GET /api/prices
Description: Fetches current market prices for specified symbols from Binance.
Query Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
symbols |
string | Yes | Comma-separated list of symbols (e.g., BTC/USDT,ETH/USDT) |
Response:
{
"BTC/USDT": 45123.50,
"ETH/USDT": 2456.75,
"SOL/USDT": 98.32
}Error Handling:
- If a symbol fails to fetch, it returns
0as fallback - Individual symbol errors are logged but don't fail the entire request
Example:
# Single symbol
curl "http://localhost:3000/api/prices?symbols=BTC/USDT"
# Multiple symbols
curl "http://localhost:3000/api/prices?symbols=BTC/USDT,ETH/USDT,SOL/USDT"Endpoint: GET /api/backtests
Description: Retrieves historical backtest results.
Query Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
limit |
number | 10 |
Maximum number of results to return |
Response:
[
{
"id": "uuid",
"strategyName": "MACD",
"symbol": "BTC/USDT",
"interval": "1h",
"timestamp": 1704384000000,
"totalTrades": 150,
"winRate": 58.5,
"profitFactor": 1.85,
"totalPnL": 1250.50,
"maxDrawdown": -8.5
}
]Example:
# Get last 10 backtest results
curl http://localhost:3000/api/backtests
# Get last 5 results
curl http://localhost:3000/api/backtests?limit=5Endpoint: POST /api/backtest/run
Description: Triggers a new backtest execution for a specified strategy, symbol, and timeframe.
Request Body:
{
"strategyName": "MACD",
"symbol": "BTC/USDT",
"interval": "1h"
}Required Fields:
strategyName: Strategy to test (e.g.,MACD,RSI,BB)symbol: Trading pair (e.g.,BTC/USDT,ETH/USDT)interval: Timeframe (e.g.,1m,5m,15m,1h,4h,1d)
Response:
{
"message": "Backtest completed successfully",
"result": {
"strategyName": "MACD",
"symbol": "BTC/USDT",
"interval": "1h",
"totalTrades": 150,
"winRate": 58.5,
"profitFactor": 1.85,
"totalPnL": 1250.50,
"maxDrawdown": -8.5,
"sharpeRatio": 1.42
}
}Error Responses:
400: Missing required parameters500: Backtest execution failed
Example:
curl -X POST http://localhost:3000/api/backtest/run \
-H "Content-Type: application/json" \
-d '{
"strategyName": "MACD",
"symbol": "BTC/USDT",
"interval": "1h"
}'Endpoint: POST /api/cron
Description: Serverless cron endpoint for scheduled bot execution. This endpoint is automatically called by Vercel Cron or external cron services.
Authentication:
Requires Authorization header with Bearer token in production:
Authorization: Bearer YOUR_CRON_SECRET
Configuration:
Set CRON_SECRET environment variable in your Vercel project settings.
Response:
{
"status": "ok",
"timestamp": 1704384000000
}Error Responses:
401: Unauthorized (invalid or missing CRON_SECRET)500: Internal error during bot execution
Example (with authentication):
curl -X POST https://your-project.vercel.app/api/cron \
-H "Authorization: Bearer your_cron_secret_here"External Cron Setup (Vercel Hobby Plan): Use Cron-job.org or similar service:
- URL:
https://your-project.vercel.app/api/cron - Schedule: Every 1 minute
- Method: POST
- Headers:
Authorization: Bearer your_cron_secret_here
The server mode API includes CORS support, allowing cross-origin requests from web applications.
- Portfolio and trade endpoints use
Cache-Control: no-cache, no-store, must-revalidateheaders to ensure fresh data - Portfolio history endpoint uses cached data for performance optimization
All endpoints return consistent error responses:
{
"error": "Error message description"
}No rate limiting is currently implemented. Consider adding rate limiting for production deployments.
Currently, only the /api/cron endpoint requires authentication (in production). Other endpoints are publicly accessible. Consider implementing authentication for production use.
// Fetch portfolio data
const portfolio = await fetch('http://localhost:3000/api/portfolio')
.then(res => res.json());
// Fetch trades with pagination
const trades = await fetch('http://localhost:3000/api/trades?limit=20&offset=0')
.then(res => res.json());
// Get current prices
const prices = await fetch('http://localhost:3000/api/prices?symbols=BTC/USDT,ETH/USDT')
.then(res => res.json());
// Run backtest
const backtest = await fetch('http://localhost:3000/api/backtest/run', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
strategyName: 'MACD',
symbol: 'BTC/USDT',
interval: '1h'
})
}).then(res => res.json());import requests
# Fetch portfolio data
portfolio = requests.get('http://localhost:3000/api/portfolio').json()
# Fetch trades
trades = requests.get('http://localhost:3000/api/trades', params={
'symbol': 'BTC/USDT',
'limit': 50
}).json()
# Run backtest
backtest = requests.post('http://localhost:3000/api/backtest/run', json={
'strategyName': 'MACD',
'symbol': 'BTC/USDT',
'interval': '1h'
}).json()We welcome contributions! Please read our CONTRIBUTING.md for details on our code of conduct and the process for submitting pull requests.
License: Apache License 2.0. contains NOTICE file with mandatory attribution to Zillions.app / @christonomous.