Combines real market data with AI sentiment analysis to simulate and evaluate trading strategies. Built with Go, TimescaleDB, and Azure OpenAI.
Three asynchronous processes sharing a single TimescaleDB instance.
Cron-based daily job. Fetches EOD market data and news from Polygon.io. Upserts with ON CONFLICT DO NOTHING for crash-safe idempotency.
Scans for un-scored news articles. Batches 10-20 headlines per API call to Azure OpenAI. Returns sentiment scores from -1.0 (bearish) to 1.0 (bullish).
Gin REST server with JWT auth. Handles backtest requests: loads data into memory, runs the strategy loop, calculates Sharpe Ratio & Max Drawdown.
Professional Go project structure following the standard Go layout.
Environment variable parsing with sensible defaults. Provides DSN() and PgxDSN() connection string builders.
GORM models, connection pool (25 max / 10 idle), auto-migrations with TimescaleDB hypertable creation, repository pattern.
Polygon.io client for daily bars and news. Rate-limited (12s delay). Crash-safe upserts with ON CONFLICT DO NOTHING.
THE CORE. Portfolio state management, strategy signal evaluation, backtesting loop with strict look-ahead bias prevention.
Azure OpenAI client with batch processing. Groups 10-20 headlines per request. Structured prompt engineering for sentiment analysis.
Pure functions: Daily Returns, Sharpe Ratio (ร โ252), Maximum Drawdown. Stateless and fully unit-testable.
Gin framework with JWT authentication middleware. CORS support. GET /assets, POST /backtest endpoints.
Shared libraries: structured zerolog logger, custom AppError types with HTTP status codes.
Try the API endpoints interactively. See the exact JSON payloads and responses.
{
"username": "analyst",
"password": "password"
}
{
"status": "success",
"token": "eyJhbGciOiJIUzI1NiIs...",
"expires_at": "2024-01-16T12:00:00Z"
}
curl -X GET http://localhost:8080/api/v1/assets \
-H "Authorization: Bearer <token>"
{
"status": "success",
"count": 8,
"data": [
{"ticker": "AAPL", "name": "Apple Inc.", "asset_type": "stock"},
{"ticker": "AMZN", "name": "Amazon.com Inc.", "asset_type": "stock"},
{"ticker": "GOOGL", "name": "Alphabet Inc.", "asset_type": "stock"},
{"ticker": "JPM", "name": "JPMorgan Chase", "asset_type": "stock"},
{"ticker": "META", "name": "Meta Platforms", "asset_type": "stock"},
{"ticker": "MSFT", "name": "Microsoft Corp.", "asset_type": "stock"},
{"ticker": "NVDA", "name": "NVIDIA Corp.", "asset_type": "stock"},
{"ticker": "TSLA", "name": "Tesla Inc.", "asset_type": "stock"}
]
}
{
"ticker": "AAPL",
"start_date": "2022-01-01",
"end_date": "2024-01-01",
"initial_capital": 100000,
"strategy_params": {
"sentiment_threshold": 0.6,
"moving_average_days": 14
}
}
{
"status": "success",
"data": {
"final_portfolio_value": 132450.75,
"total_return_pct": 32.45,
"sharpe_ratio": 1.87,
"max_drawdown_pct": -12.3,
"total_trades": 24,
"trades": [
{"date": "2022-03-15", "action": "BUY",
"ticker": "AAPL", "quantity": 612.5,
"price": 155.09},
{"date": "2022-05-20", "action": "SELL",
"ticker": "AAPL", "quantity": 612.5,
"price": 142.56}
],
"equity_curve": [
{"date": "2022-01-03", "equity": 100000},
{"date": "2022-01-04", "equity": 100230},
{"date": "2024-01-02", "equity": 132450}
]
}
}
Every technology choice is deliberate, optimized for performance and reliability.
Core language. High performance for the simulation loop with native concurrency.
PostgreSQL extension. 10x faster time-series queries crucial for financial data.
GPT-4o-mini for cost-effective news sentiment analysis with batched requests.
One-command deployment. Multi-stage builds for API and Worker containers.
Lightweight, ultra-fast HTTP framework with middleware support.
HMAC-SHA256 token authentication. Demonstrates cybersecurity best practices.
Production-grade patterns that separate junior from senior code.
All database inserts use ON CONFLICT DO NOTHING. If the worker crashes and restarts, it won't create duplicate stock prices or news articles.
db.Clauses(clause.OnConflict{DoNothing: true})
Free APIs rate-limit you. The worker implements configurable delays (12s for Polygon.io free tier) between Go routines to avoid 429 errors.
time.Sleep(rateLimitDelay) // 12s between calls
Groups 10-20 headlines into a single JSON array for one API call. Sending one request per headline would cost a fortune in token usage.
const BatchSize = 15 // headlines per API call
When calculating trades for Tuesday, the engine only has access to Monday's close price and Monday's news. Using future data makes math fraudulent.
yesterdayClose := bars[i-1].Close // NOT bars[i]
Configurable database connection pool (25 max open, 10 idle, 5min lifetime) prevents connection exhaustion under load.
sqlDB.SetMaxOpenConns(25)
Example output of a backtest: AAPL from 2022-2024 with $100K initial capital.