A high-performance C++ backtesting and trading framework built for statistical arbitrage and pairs trading. Designed for speed, scalability, and real-time market data processing.
- High Performance: Process over 1M+ market data points with a multi-threaded architecture.
- Statistical Arbitrage: Built-in support for 30+ cointegrated pairs across sectors.
- Advanced Risk Management: Stop-loss, trailing stops, sector allocation limits.
- Real-time Analytics: Sharpe ratio, drawdown analysis, performance monitoring.
- Configurable Strategies: Strategy selection through lightweight configuration files.
- Lock-free Processing: Optimized for modern multi-core systems with minimal contention.
- Comprehensive Reporting: HTML reports and CSV exports supported.
# Clone the repository
git clone https://github.com/RutvikBabar/Winter.git
cd Winter
# Build the framework
make
# Run a backtest
./build/simulate --backtest 1 your_market_data.csv- C++20-compatible compiler (GCC 10+, Clang 12+, MSVC 2019+)
- CMake 3.16+ or Make
- ZeroMQ (for real-time market data feeds)
git clone https://github.com/RutvikBabar/Winter.git
cd Winter/Winter2.0
make clean && make
# Verify installation
./build/simulate --helpCreate winter_strategies.conf:
# Strategy ID mapping
1=StatArbitrage
2=MeanReversion
3=momentum_strategy
4=pairs_trading
# Run statistical arbitrage
./build/simulate --backtest 1 market_data.csv
# Run mean reversion
./build/simulate --backtest 2 market_data.csv
# Custom initial balance
./build/simulate --backtest 1 data.csv --initial-balance 10000000timestamp,symbol,price,volume
1609459200000000,AAPL,132.69,100000
1609459200000000,MSFT,222.42,75000=== Backtest Results ===
Initial Capital: $5,000,000.00
Final Capital: $5,005,608.99
Total Return: $5,608.99 (0.11%)
Sharpe Ratio: 1.24
Max Drawdown: 8.67%
Total Trades: 8747
Win Rate: 65.50%
Profit Factor: 1.86
- 30 cointegrated pairs across sectors (Technology, Financials, Energy, ETFs)
- Multi-timeframe analysis (short, medium, long)
- Real-time beta calculation and dynamic hedge ratios
- Z-score based entries with confirmation logic
Example Pairs:
- Technology:
AAPL-MSFT,GOOGL-FB,AMD-NVDA - Financial:
JPM-BAC,C-WFC,GS-MS - Energy:
XOM-CVX,BP-SHEL,COP-MRO - ETFs:
SPY-IVV,QQQ-XLK,XLE-VDE
- RSI, Bollinger Bands, Volume Oscillator
- 200-period EMA for trend filtering
- ATR-based position sizing
- Multi-condition signal confirmation
- Throughput: 15,000+ messages/second
- Latency: Sub-millisecond signal generation
- Queue capacity: 25M+ events
- Scalability: Up to 16 worker threads
- Lock-free ring buffers
- Adaptive batching
- Memory pools for fast allocation
- SIMD-optimized math routines
- Cache-friendly data layouts
// Entry/Exit Thresholds
double ENTRY_THRESHOLD = 2.2;
double EXIT_THRESHOLD = 0.15;
double PROFIT_TARGET_MULT = 0.15;
// Risk Management
double STOP_LOSS_PCT = 0.008;
double MAX_POSITION_PCT = 0.002;
double MIN_CASH_RESERVE_PCT = 0.25;// Threading Configuration
const int MAX_THREADS = 16;
const size_t MAX_QUEUE_SIZE = 25000000;
const size_t BATCH_SIZE = 100;Market Data → Strategy Engine → Risk Management
↓ ↓ ↓
Parallel Signal Position
Queues Logic Sizing
- C++20 (concepts, coroutines, ranges,
constexpr) - Multi-threaded lock-free architecture
- Template metaprogramming for zero-cost abstractions
- RAII-based memory safety
Performance: 15420 msgs/sec
Drop Rate: 2.3%
Workers: 12/16
Cash Reserve: 78.5%
Active Positions: 15
Sharpe: 1.24
- Queue pressure-based throttling
- Emergency liquidation triggers
- Sector allocation rebalancing
- Performance-based scaling
- HTML reports with interactive visualizations
- CSV exports for offline analysis
- Real-time metrics dashboard
- Full trade logs with timestamps and PnL
We welcome pull requests. Please follow the contribution process:
# Fork and clone
git clone https://github.com/yourusername/Winter.git
cd Winter/Winter2.0
# Create a new feature branch
git checkout -b feature/your-feature
# Build and test
make clean && make
./build/simulate --backtest 1 test_data.csv- Follow C++20 best practices
- Use the Google C++ Style Guide
- Include unit tests and performance benchmarks for new code
Writing and Registering Custom strategies Follow these step-by-step instructions to create and register your own trading strategy in the Winter framework.
Create a new header file in the strategies/ directory (e.g., strategies/my_custom_strategy.hpp):
#pragma once
#include <winter/strategy/strategy_base.hpp>
#include <winter/strategy/strategy_factory.hpp>
#include <winter/core/signal.hpp>
#include <winter/core/market_data.hpp>
#include <deque>
#include <unordered_map>
#include <cmath>
#include <algorithm>
#include <numeric>
class MyCustomStrategy : public winter::strategy::StrategyBase {
private:
// Your strategy parameters
double entry_threshold = 2.0;
double exit_threshold = 0.5;
// Data storage for each symbol
std::unordered_map<std::string, std::deque<double>> price_history;
std::unordered_map<std::string, int> positions;
const int LOOKBACK_PERIOD = 20;
const double MAX_POSITION_PCT = 0.01; // 1% of capital per position
public:
// Constructor must accept string parameter for factory compatibility
MyCustomStrategy(const std::string& name = "MyCustomStrategy") : StrategyBase(name) {}
// Main strategy logic - override this method
std::vector<winter::core::Signal> process_tick(const winter::core::MarketData& data) override {
std::vector<winter::core::Signal> signals;
// Update price history
price_history[data.symbol].push_back(data.price);
if (price_history[data.symbol].size() > LOOKBACK_PERIOD) {
price_history[data.symbol].pop_front();
}
// Only trade if we have enough history
if (price_history[data.symbol].size() < LOOKBACK_PERIOD) {
return signals;
}
// Calculate moving average
double sum = std::accumulate(price_history[data.symbol].begin(),
price_history[data.symbol].end(), 0.0);
double moving_average = sum / price_history[data.symbol].size();
// Calculate standard deviation
double variance = 0.0;
for (double price : price_history[data.symbol]) {
variance += (price - moving_average) * (price - moving_average);
}
double std_dev = std::sqrt(variance / price_history[data.symbol].size());
// Calculate z-score
double z_score = (data.price - moving_average) / std_dev;
// Get current position
int current_position = positions[data.symbol];
// Generate signals based on z-score
if (current_position == 0) {
// Entry logic
if (z_score > entry_threshold) {
// Price is high, go short
winter::core::Signal signal;
signal.symbol = data.symbol;
signal.type = winter::core::SignalType::SELL;
signal.price = data.price;
signal.strength = std::min(1.0, z_score / entry_threshold);
signals.push_back(signal);
positions[data.symbol] = -1; // Mark as short
}
else if (z_score < -entry_threshold) {
// Price is low, go long
winter::core::Signal signal;
signal.symbol = data.symbol;
signal.type = winter::core::SignalType::BUY;
signal.price = data.price;
signal.strength = std::min(1.0, -z_score / entry_threshold);
signals.push_back(signal);
positions[data.symbol] = 1; // Mark as long
}
}
else {
// Exit logic
if (std::abs(z_score) < exit_threshold) {
// Price has reverted, close position
winter::core::Signal signal;
signal.symbol = data.symbol;
signal.type = current_position > 0 ? winter::core::SignalType::SELL : winter::core::SignalType::BUY;
signal.price = data.price;
signal.strength = 1.0;
signals.push_back(signal);
positions[data.symbol] = 0; // Close position
}
}
return signals;
}
};
// Register the strategy with the factory
namespace {
bool my_custom_registered = []() {
winter::strategy::StrategyFactory::register_type<MyCustomStrategy>("MyCustomStrategy");
return true;
}();
}
Add your strategy header to src/simulate/simulate.cpp:
#include "strategies/stat_arbitrage.hpp"
#include "strategies/mean_reversion_strategy.hpp"
#include "strategies/my_custom_strategy.hpp" // Add this line
Add your strategy to winter_strategies.conf:
# winter_strategies.conf
# Format: strategy_id=strategy_name
1=StatArbitrage
2=MeanReversion
3=MyCustomStrategy
4=momentum_strategy
5=pairs_trading
Compile the framework with your new strategy:
make clean
make
Test your strategy:
# Run backtest with your custom strategy (ID 3)
./build/simulate --backtest 3 your_market_data.csv
# Run trade simulation
./build/simulate --trade 3 your_market_data.csv
Make your strategy configurable by adding parameters:
class MyCustomStrategy : public winter::strategy::StrategyBase {
private:
// Configurable parameters
double entry_threshold;
double exit_threshold;
int lookback_period;
double max_position_pct;
public:
MyCustomStrategy(const std::string& name = "MyCustomStrategy",
double entry_thresh = 2.0,
double exit_thresh = 0.5,
int lookback = 20)
: StrategyBase(name),
entry_threshold(entry_thresh),
exit_threshold(exit_thresh),
lookback_period(lookback) {}
Implement position sizing and risk controls:
private:
double calculate_position_size(const std::string& symbol, double price) {
// Simple position sizing based on capital percentage
const double CAPITAL = 5000000.0; // $5M
return (CAPITAL * max_position_pct) / price;
}
bool check_risk_limits(const std::string& symbol, double price) {
// Add your risk checks here
// e.g., maximum exposure, correlation limits, etc.
return true;
}
Track strategy performance:
private:
struct PerformanceMetrics {
int total_trades = 0;
int winning_trades = 0;
double total_pnl = 0.0;
double max_drawdown = 0.0;
} performance;
void update_performance(double trade_pnl) {
performance.total_trades++;
performance.total_pnl += trade_pnl;
if (trade_pnl > 0) {
performance.winning_trades++;
}
// Update other metrics...
}
class MeanReversionTemplate : public winter::strategy::StrategyBase {
// Implement mean reversion logic
// - Calculate moving averages
// - Detect overbought/oversold conditions
// - Generate contrarian signals
};
class MomentumTemplate : public winter::strategy::StrategyBase {
// Implement momentum logic
// - Calculate price momentum
// - Detect trend breakouts
// - Generate trend-following signals
};
class PairsTradingTemplate : public winter::strategy::StrategyBase {
// Implement pairs trading logic
// - Calculate spread between correlated assets
// - Detect spread divergence
// - Generate market-neutral signals
};
Create tests for your strategy:
// tests/test_my_custom_strategy.cpp
#include "strategies/my_custom_strategy.hpp"
#include <cassert>
void test_signal_generation() {
MyCustomStrategy strategy;
winter::core::MarketData data;
data.symbol = "TEST";
data.price = 100.0;
data.volume = 1000;
auto signals = strategy.process_tick(data);
// Add your assertions here
}
Test with historical data:
./build/simulate --backtest 3 data_2020.csv
./build/simulate --backtest 3 data_2021.csv
./build/simulate --backtest 3 data_2022.csv
Test different parameter combinations:
// Buy signal signal.type = winter::core::SignalType::BUY;
// Sell signal
signal.type = winter::core::SignalType::SELL;
// Exit signal (close position) signal.type = winter::core::SignalType::EXIT;
// Strong signal (1.0) signal.strength = 1.0;
// Moderate signal (0.5-0.8) signal.strength = 0.7;
// Weak signal (0.1-0.4) signal.strength = 0.3;
std::vector<winter::core::Signal> process_tick(const winter::core::MarketData& data) override {
std::vector<winter::core::Signal> signals;
try {
// Your strategy logic here
} catch (const std::exception& e) {
// Log error and return empty signals
winter::utils::Logger::error() << "Strategy error: " << e.what() << winter::utils::Logger::endl;
return signals;
}
return signals;
}
Your custom strategy is now ready to use with the Winter framework!