Building the Price Oracle
The price oracle fetches reference prices from external exchanges to guide your trading agent's order placement. This ensures your orders are placed at market-relevant prices.
Note: Before starting this section, ensure you've completed the Project Setup and installed all dependencies with
pnpm install.
Why Use an External Price Feed?
Your trading agent needs to know the "fair" market price to:
- Place buy orders above market (to ensure fills)
- Place sell orders below market (to ensure fills)
- Avoid placing orders too far from market (wasting capital)
- Generate realistic trading activity
Create the Bitget Client
The Bitget client fetches real-time prices from the Bitget exchange using the CCXT library. This provides reference prices for your trading agent.
Create the price oracle file:
touch src/bitget.tsAdd the following content to src/bitget.ts:
import ccxt from 'ccxt';
import type { Exchange } from 'ccxt';
export class BitgetClient {
private exchange: Exchange;
constructor() {
// Initialize Bitget exchange client
this.exchange = new ccxt.bitget({
// No API keys needed for public data (market prices)
apiKey: '',
secret: '',
password: '',
// Use production API (not sandbox)
sandbox: false,
// Automatically throttle requests to respect rate limits
enableRateLimit: true,
});
}
/**
* Fetch the latest price for a trading pair
* @param symbol - Trading pair in BASE/QUOTE format (e.g., "ETH/USDC")
* @returns Current price as a number
*/
async fetchPrice(symbol: string): Promise<number> {
// Load market metadata (cached after first call)
await this.exchange.loadMarkets();
// Fetch ticker data (includes last price, bid, ask, volume, etc.)
const ticker = await this.exchange.fetchTicker(symbol);
// Return the last traded price
return Number(ticker.last);
}
}Why CCXT?
CCXT is an industry-standard package that provides:
- Unified API across 100+ exchanges
- Automatic rate limiting
- Error handling and retries
- WebSocket support (optional)
- Free for public data (no API keys needed)
Price Conversion for Non-Standard Pairs
Some o2 markets may not have direct price feeds on Bitget. For example, FUEL/USDC might not exist on Bitget, but FUEL/USDT does.
Strategy: Convert Through Stable Pairs
When you need a price that's not directly available (e.g., FUEL/USDC), you can derive it from two related pairs:
// Fetch prices for pairs that exist on Bitget
const fuelUsdtPrice = await bitgetClient.fetchPrice('FUEL/USDT'); // e.g., 0.05
const usdcUsdtPrice = await bitgetClient.fetchPrice('USDC/USDT'); // e.g., 1.0001
// Convert FUEL/USDT to FUEL/USDC using cross-rate calculation
// (FUEL/USDT) / (USDC/USDT) = FUEL/USDC
const fuelUsdcPrice = fuelUsdtPrice / usdcUsdtPrice; // e.g., 0.04999This conversion is handled automatically in the bot via the convert_to_usdc configuration flag. When set to true, the bot will fetch both prices and calculate the cross-rate.
Alternative Price Oracles
You can swap Bitget for other exchanges by changing the CCXT exchange. CCXT provides a unified API across 100+ exchanges, so switching is as simple as changing the exchange name.
Bybit
// src/bitget.ts (alternative exchange)
// Replace the constructor with:
this.exchange = new ccxt.bybit({
enableRateLimit: true,
});Binance
// Replace the constructor with:
this.exchange = new ccxt.binance({
enableRateLimit: true,
});KuCoin
// Replace the constructor with:
this.exchange = new ccxt.kucoin({
enableRateLimit: true,
});All exchanges expose the same fetchTicker() API, so no other code changes are needed. Just make sure the trading pair you're using exists on the exchange you choose.