Created
December 22, 2024 16:51
-
-
Save AlanGreyjoy/384fe1af7341825e91b1b74a03f330f2 to your computer and use it in GitHub Desktop.
Paper trading price simulator
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { usePrices } from "../hooks/usePrices"; //Implement your own service for fetching realtime stock prices or mock data. | |
interface SimulatedPrice { | |
price: number; | |
timestamp: Date; | |
} | |
class PriceSimulator { | |
private simulatedPrices: Map<string, SimulatedPrice> = new Map(); | |
private volatility = 0.002; // 0.2% base volatility | |
private trendStrength = 0.3; // How strong the trend is | |
private meanReversionStrength = 0.2; // How strongly price returns to base | |
private trends: Map<string, number> = new Map(); // Track trend direction per symbol | |
simulatePrice(symbol: string, basePrice: number): number { | |
const existing = this.simulatedPrices.get(symbol); | |
const now = new Date(); | |
// Generate new price every second | |
if (!existing || now.getTime() - existing.timestamp.getTime() > 1000) { | |
// Initialize or update trend | |
if (!this.trends.has(symbol)) { | |
this.trends.set(symbol, Math.random() > 0.5 ? 1 : -1); | |
} else if (Math.random() < 0.1) { | |
// 10% chance to switch trend | |
this.trends.set(symbol, this.trends.get(symbol)! * -1); | |
} | |
const trend = this.trends.get(symbol)!; | |
// Random component (volatility) | |
const randomWalk = (Math.random() - 0.5) * 2 * this.volatility; | |
// Trend component | |
const trendComponent = trend * this.trendStrength * this.volatility; | |
// Mean reversion component | |
const meanReversion = existing | |
? (basePrice - existing.price) * this.meanReversionStrength | |
: 0; | |
// Combine all components | |
let newPrice = | |
(existing?.price || basePrice) * (1 + randomWalk + trendComponent) + | |
meanReversion; | |
// Add some noise to make it more realistic | |
newPrice *= 1 + (Math.random() - 0.5) * 0.0001; | |
// Prevent extreme deviations from base price (±30%) | |
const maxDeviation = basePrice * 0.3; | |
newPrice = Math.max( | |
basePrice - maxDeviation, | |
Math.min(basePrice + maxDeviation, newPrice) | |
); | |
this.simulatedPrices.set(symbol, { | |
price: newPrice, | |
timestamp: now, | |
}); | |
return newPrice; | |
} | |
return existing.price; | |
} | |
setVolatility(value: number) { | |
this.volatility = value; | |
} | |
} | |
export const priceSimulator = new PriceSimulator(); | |
// Hook to get simulated prices | |
export function useSimulatedPrices() { | |
const { prices: realPrices } = usePrices(); | |
const getSimulatedPrice = (symbol: string) => { | |
const basePrice = realPrices[symbol]; | |
if (!basePrice) return null; | |
return priceSimulator.simulatePrice(symbol, basePrice); | |
}; | |
return { | |
getSimulatedPrice, | |
setVolatility: priceSimulator.setVolatility.bind(priceSimulator), | |
}; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment