WU Trading Library 0.2.0
A backtesting and trading strategy library
Loading...
Searching...
No Matches
pairs_trading.c
Go to the documentation of this file.
1#include <assert.h>
2#include <stdlib.h>
3#include <math.h>
4#include "wu.h"
5
6#define NUM_INPUTS 2
7#define NUM_OUTPUTS 2
8
13
15
17 const void* inputs[]) {
18 WU_PairsTradingStrat strat = (WU_PairsTradingStrat)strat_;
19
20 // Validate input count
21 assert(strat->base.num_inputs == NUM_INPUTS);
22
23 // Cast inputs with proper types
24 const WU_Single* asset_a = (const WU_Single*)inputs[0];
25 const WU_Single* asset_b = (const WU_Single*)inputs[1];
26
27 // Validate input types
28 assert(asset_a->data_type == WU_DATA_TYPE_SINGLE_VALUE);
29 assert(asset_b->data_type == WU_DATA_TYPE_SINGLE_VALUE);
30
31 // Initialize signal buffer with HOLD signals for both assets
32 strat->base.signal_buffer[0] = wu_signal_init(asset_a->timestamp, WU_SIDE_HOLD,
33 asset_a->value, 1.0);
34 strat->base.signal_buffer[1] = wu_signal_init(asset_b->timestamp, WU_SIDE_HOLD,
35 asset_b->value, 1.0);
36
37 // Calculate the spread: spread = asset_a - (ratio * asset_b)
38 double spread = asset_a->value - (strat->ratio * asset_b->value);
39
40 // Update spread statistics
41 double spread_mean = wu_indicator_update(strat->spread_ma, spread);
42 double spread_stdev = wu_indicator_update(strat->spread_std, spread);
43
44 // Wait for indicators to warm up
45 if (isnan(spread_mean) || isnan(spread_stdev))
46 return strat->base.signal_buffer;
47
48 // Calculate entry/exit thresholds
49 double upper_band = spread_mean + strat->threshold * spread_stdev;
50 double lower_band = spread_mean - strat->threshold * spread_stdev;
51
52 // Pairs trading logic:
53 // When spread is below lower band: Asset A is cheap relative to B
54 // → BUY Asset A, SELL Asset B (expecting mean reversion)
55 // When spread is above upper band: Asset A is expensive relative to B
56 // → SELL Asset A, BUY Asset B (expecting mean reversion)
57 // When spread returns near mean: Close position
58
59 if (spread < lower_band && strat->last_signal != WU_SIDE_BUY) {
60 // Spread below lower band: Asset A undervalued
61 // Signal to BUY Asset A and SELL Asset B
62 strat->last_signal = WU_SIDE_BUY;
63 strat->base.signal_buffer[0].side = WU_SIDE_BUY;
64 strat->base.signal_buffer[1].side = WU_SIDE_SELL;
65 }
66 else if (spread > upper_band && strat->last_signal != WU_SIDE_SELL) {
67 // Spread above upper band: Asset A overvalued
68 // Signal to SELL Asset A and BUY Asset B
69 strat->last_signal = WU_SIDE_SELL;
70 strat->base.signal_buffer[0].side = WU_SIDE_SELL;
71 strat->base.signal_buffer[1].side = WU_SIDE_BUY;
72 }
73 else if (strat->last_signal != WU_SIDE_HOLD) {
74 // Check if spread has mean-reverted (exit condition)
75 // Exit when spread crosses back through the mean
76 bool spread_reverted = false;
77
78 if (strat->last_signal == WU_SIDE_BUY && spread > spread_mean) {
79 // We were long (bought at low spread), now spread returned to mean
80 spread_reverted = true;
81 }
82 else if (strat->last_signal == WU_SIDE_SELL && spread < spread_mean) {
83 // We were short (sold at high spread), now spread returned to mean
84 spread_reverted = true;
85 }
86
87 if (spread_reverted) {
88 // Mean reversion occurred - close position
89 // Generate opposite signals to close both positions
90 strat->base.signal_buffer[0].side = (strat->last_signal == WU_SIDE_BUY) ? WU_SIDE_SELL : WU_SIDE_BUY;
91 strat->base.signal_buffer[1].side = (strat->last_signal == WU_SIDE_BUY) ? WU_SIDE_BUY : WU_SIDE_SELL;
92 strat->last_signal = WU_SIDE_HOLD;
93 }
94 }
95
96 return strat->base.signal_buffer;
97}
98
99static void pairs_trading_strat_free(struct WU_Strategy_* strategy) {
100 WU_PairsTradingStrat strat = (WU_PairsTradingStrat)strategy;
101 wu_indicator_delete(strat->spread_ma);
102 wu_indicator_delete(strat->spread_std);
103 free(strat);
104}
105
106WU_PairsTradingStrat wu_pairs_trading_strat_new(int window, double threshold, double ratio) {
107 WU_PairsTradingStrat strat = malloc(sizeof(struct WU_PairsTradingStrat_));
108
109 // Set up base strategy interface
110 strat->base.update = pairs_trading_strat_update;
111 strat->base.delete = pairs_trading_strat_free;
112
113 // Declare input requirements (point to static const)
114 strat->base.input_types = input_types;
115 strat->base.num_inputs = NUM_INPUTS;
116
117 // Declare output count (symbols set by backtest runner)
118 // strat->base.output_symbols = NULL; // Will be set by runner
119 strat->base.num_outputs = NUM_OUTPUTS;
120 strat->base.signal_buffer = signal_buffer;
121
122 // Initialize spread statistics indicators
123 strat->spread_ma = wu_sma_new(window);
124 strat->spread_std = wu_mstdev_new(window, 1); // dof=1 for sample std deviation
125
126 // Initialize strategy parameters
127 strat->threshold = threshold;
128 strat->ratio = ratio;
129 strat->last_signal = WU_SIDE_HOLD;
130
131 return strat;
132}
#define NUM_OUTPUTS
Definition crossover.c:6
static WU_Signal signal_buffer[NUM_OUTPUTS]
Definition crossover.c:9
static const WU_DataType input_types[]
Definition crossover.c:8
#define NUM_INPUTS
Definition crossover.c:5
WU_Signal wu_signal_init(WU_TimeStamp timestamp, WU_Side side, double price, double quantity)
Definition init.c:39
#define wu_indicator_delete(indicator)
Delete the indicator and free any resources allocated by it.
Definition indicators.h:56
#define wu_indicator_update(indicator, value)
Header file for technical indicators.
Definition indicators.h:41
WU_MStDev wu_mstdev_new(int window_size, int dof)
Creates a new WU_MStDev (Moving Standard Deviation) indicator with the specified window size and degr...
Definition mstdev.c:17
WU_SMA wu_sma_new(int window_size)
Creates a new WU_SMA (Simple Moving Average) indicator with the specified window size.
Definition sma.c:22
WU_PairsTradingStrat wu_pairs_trading_strat_new(int window, double threshold, double ratio)
Creates a new pairs trading strategy.
static void pairs_trading_strat_free(struct WU_Strategy_ *strategy)
static WU_Signal * pairs_trading_strat_update(struct WU_Strategy_ *strat_, const void *inputs[])
WU_PairsTradingStrat implements a classic pairs trading strategy that trades the spread between two c...
Definition strategies.h:79
WU_Signal represents a trading signal generated by a strategy.
Definition types.h:38
WU_Single represents a single value with a timestamp, which can be a price, an indicator value,...
Definition data.h:47
WU_DataType data_type
Definition data.h:50
WU_TimeStamp timestamp
Definition data.h:48
double value
Definition data.h:49
@ WU_SIDE_HOLD
Definition types.h:12
@ WU_SIDE_SELL
Definition types.h:14
@ WU_SIDE_BUY
Definition types.h:13
WU_DataType
WU_DataType represents the type of input data, which can be a candle, a trade, or a single value.
Definition types.h:24
@ WU_DATA_TYPE_SINGLE_VALUE
Definition types.h:27