Files
AlphaFlow-MT5-ML-DL-Trading…/notebooks/exploratory/integrated_pipeline_pair_trading.ipynb
T

648 KiB
Raw Blame History

Below is an integrated pipeline that ties together the various tools we discussed:

Pair Selection:
Use correlation and cointegration to narrow down candidate pairs.
Optionally, use PCA and clustering to further group similar assets.

Dynamic Signal Generation:
Once a pair is selected, use a Kalman Filter to dynamically estimate the hedge ratio (and thus the spread) between the two assets.
Compute a rolling zscore (or use the filters estimates) to generate entry/exit signals.

Backtesting:
Use vectorbt (or any backtesting framework) to simulate the paired trades based on the adaptive signals.

In [1]:
import MetaTrader5 as mt5
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from statsmodels.tsa.stattools import coint
from sklearn.decomposition import PCA
from sklearn.cluster import KMeans
from pykalman import KalmanFilter
import vectorbt as vbt

# -------------------------------
# Step 1: Data Loading using MT5 API
# -------------------------------
if not mt5.initialize():
    print("MT5 Initialization Failed")
    mt5.shutdown()
    quit()

# Retrieve all symbols from MT5
symbols = [s.name for s in mt5.symbols_get()]
print(f"✅ Found {len(symbols)} symbols in MT5")

# Limit to top 50 symbols for performance
symbols = symbols[:50]

# Function to fetch historical data from MT5
def get_mt5_data(symbol, n_bars=1000, timeframe=mt5.TIMEFRAME_D1):
    rates = mt5.copy_rates_from_pos(symbol, timeframe, 0, n_bars)
    if rates is None:
        print(f"⚠️ Could not retrieve data for {symbol}")
        return None
    df = pd.DataFrame(rates)
    df["time"] = pd.to_datetime(df["time"], unit="s")
    df.set_index("time", inplace=True)
    return df[["close"]]

# Load data for all symbols
data = {symbol: get_mt5_data(symbol) for symbol in symbols if get_mt5_data(symbol) is not None}

# Merge data into one DataFrame with a multi-index (symbol, feature)
df = pd.concat(data.values(), axis=1, keys=data.keys()).dropna()
print(f"📊 Data Loaded for {len(df.columns)//2} Symbols")
✅ Found 2061 symbols in MT5
📊 Data Loaded for 25 Symbols
In [2]:

# -------------------------------
# Step 2: Prepare Price Data for Pair Selection
# -------------------------------
# Extract just the "close" prices to get a DataFrame with single-level columns
df_prices = df.xs('close', axis=1, level=1)
returns = df_prices.pct_change().dropna()

# Compute the correlation matrix (columns are symbols now)
corr_matrix = returns.corr()
print("Correlation Matrix:")
print(corr_matrix)
Correlation Matrix:
          EURUSD    GBPUSD    USDCHF    USDJPY    USDCAD    AUDUSD    AUDNZD  \
EURUSD  1.000000  0.780128 -0.736896 -0.434969 -0.586613  0.674502  0.020042   
GBPUSD  0.780128  1.000000 -0.619409 -0.420554 -0.630336  0.719728  0.021344   
USDCHF -0.736896 -0.619409  1.000000  0.540276  0.493095 -0.589198  0.024836   
USDJPY -0.434969 -0.420554  0.540276  1.000000  0.252563 -0.407078  0.092968   
USDCAD -0.586613 -0.630336  0.493095  0.252563  1.000000 -0.775543 -0.175122   
AUDUSD  0.674502  0.719728 -0.589198 -0.407078 -0.775543  1.000000  0.254445   
AUDNZD  0.020042  0.021344  0.024836  0.092968 -0.175122  0.254445  1.000000   
AUDCAD  0.466675  0.494919 -0.427767 -0.381727 -0.218942  0.785352  0.220496   
AUDCHF  0.150693  0.312526  0.190804 -0.003642 -0.495450  0.680458  0.332438   
AUDJPY  0.247187  0.302866 -0.073294  0.508348 -0.505924  0.579337  0.322672   
CHFJPY  0.164979  0.075318 -0.279135  0.656318 -0.154203  0.064901  0.088684   
EURGBP  0.129716 -0.517883 -0.022158  0.075540  0.200760 -0.220507 -0.003304   
EURAUD  0.076317 -0.201345  0.069790  0.123846  0.467535 -0.683390 -0.314569   
EURJPY  0.349502  0.187286 -0.029188  0.691392 -0.207146  0.116779  0.113334   
EURCHF  0.337276  0.201239  0.387249  0.159975 -0.112317  0.098045  0.059334   
EURNZD  0.089424 -0.189548  0.084643  0.181434  0.358556 -0.522560  0.315850   
EURCAD  0.570032  0.269095 -0.358609 -0.250556  0.330649 -0.001048 -0.153771   
GBPCHF  0.157704  0.548169  0.316533  0.067746 -0.236948  0.242437  0.052546   
GBPJPY  0.255988  0.461779 -0.012844  0.610297 -0.303377  0.230589  0.110227   
CADCHF -0.252025 -0.087914  0.616146  0.347262 -0.379968  0.076600  0.188453   
CADJPY -0.038807  0.001811  0.198868  0.788334 -0.395077  0.107089  0.202341   
GBPAUD -0.018070  0.182280  0.092229  0.075331  0.340525 -0.549892 -0.325153   
GBPCAD  0.432050  0.671358 -0.317319 -0.294898  0.151622  0.175517 -0.140375   
GBPNZD -0.004872  0.193578  0.108581  0.133700  0.225985 -0.382261  0.335656   
NZDCAD  0.415465  0.439923 -0.409072 -0.406133 -0.087239  0.551517 -0.451996   
NZDCHF  0.144437  0.309318  0.180933 -0.055658 -0.409912  0.553028 -0.235439   
NZDJPY  0.250581  0.307299 -0.088876  0.489990 -0.451117  0.490462 -0.119616   
NZDUSD  0.673139  0.718219 -0.607766 -0.451989 -0.702332  0.891053 -0.208942   
USDSGD -0.808615 -0.750526  0.682546  0.563995  0.656198 -0.793887 -0.041271   
AUDSGD  0.442617  0.545053 -0.400662 -0.215658 -0.689571  0.919537  0.338295   
CHFSGD  0.335283  0.222428 -0.789993 -0.261336 -0.130315  0.147784 -0.055654   
EURDKK -0.011267 -0.036107  0.011558 -0.010886  0.002326 -0.030063  0.031869   
EURHKD  0.994846  0.772789 -0.729696 -0.431183 -0.581641  0.669474  0.024709   
EURNOK -0.151581 -0.308677  0.197846  0.150674  0.519171 -0.517902 -0.086608   
EURPLN -0.304999 -0.263237  0.154693  0.122370  0.287150 -0.280998 -0.025852   
EURSEK -0.267557 -0.340078  0.262215  0.165725  0.403234 -0.456200 -0.050783   
EURSGD  0.807214  0.509212 -0.506677 -0.134883 -0.292870  0.296343 -0.004976   
EURTRY  0.333257  0.269465 -0.246226 -0.131904 -0.182316  0.199602  0.006226   
EURZAR  0.044968 -0.103782  0.028639  0.086699  0.197120 -0.274857 -0.083140   
GBPDKK -0.131499  0.515171  0.030288 -0.066628 -0.200157  0.219327  0.012875   
GBPNOK -0.230155  0.020595  0.209628  0.107297  0.379954 -0.367915 -0.078186   
GBPSEK -0.315768  0.087188  0.238888  0.090355  0.196097 -0.224007 -0.033351   
GBPSGD  0.496274  0.856301 -0.358180 -0.159346 -0.400840  0.423732  0.005438   
GBPTRY  0.281417  0.389010 -0.220466 -0.139287 -0.221339  0.241587  0.008949   
NOKJPY  0.367305  0.362742 -0.151723  0.415457 -0.513605  0.448873  0.157618   
NOKSEK -0.049602  0.074701  0.003827 -0.022183 -0.244101  0.203806  0.070538   
SEKJPY  0.427013  0.338836 -0.161708  0.471799 -0.391819  0.346699  0.126414   
SGDJPY -0.061900 -0.078301  0.259451  0.881815 -0.070735 -0.034588  0.147259   
USDCNH -0.571956 -0.545428  0.498127  0.422045  0.486012 -0.597839 -0.046366   
USDCZK -0.881107 -0.697077  0.646868  0.385782  0.558194 -0.620403 -0.000073   

          AUDCAD    AUDCHF    AUDJPY  ...    GBPNOK    GBPSEK    GBPSGD  \
EURUSD  0.466675  0.150693  0.247187  ... -0.230155 -0.315768  0.496274   
GBPUSD  0.494919  0.312526  0.302866  ...  0.020595  0.087188  0.856301   
USDCHF -0.427767  0.190804 -0.073294  ...  0.209628  0.238888 -0.358180   
USDJPY -0.381727 -0.003642  0.508348  ...  0.107297  0.090355 -0.159346   
USDCAD -0.218942 -0.495450 -0.505924  ...  0.379954  0.196097 -0.400840   
AUDUSD  0.785352  0.680458  0.579337  ... -0.367915 -0.224007  0.423732   
AUDNZD  0.220496  0.332438  0.322672  ... -0.078186 -0.033351  0.005438   
AUDCAD  1.000000  0.565956  0.399575  ... -0.196221 -0.153524  0.262599   
AUDCHF  0.565956  1.000000  0.638453  ... -0.256766 -0.054440  0.190713   
AUDJPY  0.399575  0.638453  1.000000  ... -0.250614 -0.129661  0.256832   
CHFJPY -0.050720 -0.173207  0.646573  ... -0.063442 -0.110353  0.140370   
EURGBP -0.146002 -0.288362 -0.140673  ... -0.341194 -0.565890 -0.675112   
EURAUD -0.599313 -0.767567 -0.534300  ...  0.273187 -0.007963 -0.077966   
EURJPY -0.023343  0.116142  0.726552  ... -0.073037 -0.158512  0.231417   
EURCHF  0.039792  0.469541  0.234600  ... -0.023426 -0.097946  0.178234   
EURNZD -0.458246 -0.558219 -0.331283  ...  0.221284 -0.031043 -0.080747   
EURCAD  0.321503 -0.327312 -0.225228  ...  0.117067 -0.168921  0.171733   
GBPCHF  0.142527  0.581423  0.288795  ...  0.247214  0.362134  0.653186   
GBPJPY  0.059248  0.269393  0.761640  ...  0.122838  0.165042  0.591761   
CADCHF -0.254767  0.651879  0.382185  ... -0.121187  0.074771 -0.016828   
CADJPY -0.221984  0.311628  0.804380  ... -0.138866 -0.039497  0.104590   
GBPAUD -0.516244 -0.584795 -0.451655  ...  0.548969  0.422677  0.433145   
GBPCAD  0.420465 -0.075036 -0.098236  ...  0.389177  0.299075  0.707910   
GBPNZD -0.369797 -0.365745 -0.241540  ...  0.494348  0.398800  0.429507   
NZDCAD  0.767643  0.298219  0.157431  ... -0.125556 -0.119188  0.242996   
NZDCHF  0.453129  0.835442  0.471793  ... -0.216859 -0.036481  0.196162   
NZDJPY  0.316314  0.515959  0.899567  ... -0.226732 -0.120895  0.268549   
NZDUSD  0.689204  0.530909  0.436685  ... -0.332387 -0.210989  0.430053   
USDSGD -0.583712 -0.344420 -0.244979  ...  0.291769  0.268401 -0.306053   
AUDSGD  0.745726  0.754451  0.674381  ... -0.340100 -0.151655  0.407408   
CHFSGD  0.100951 -0.535991 -0.093919  ... -0.042204 -0.107670  0.242536   
EURDKK -0.044080 -0.025725 -0.037852  ... -0.068231 -0.054789 -0.027115   
EURHKD  0.463624  0.150992  0.245835  ... -0.231851 -0.314401  0.492031   
EURNOK -0.292664 -0.449901 -0.353495  ...  0.797190  0.214135 -0.178615   
EURPLN -0.152179 -0.202186 -0.155986  ...  0.148743  0.215036 -0.138348   
EURSEK -0.310669 -0.315561 -0.280924  ...  0.376451  0.706847 -0.193384   
EURSGD  0.169826 -0.099198  0.158403  ... -0.082719 -0.246854  0.495780   
EURTRY  0.128421  0.019390  0.070045  ... -0.026937 -0.096512  0.198107   
EURZAR -0.234060 -0.307788 -0.182175  ...  0.184971  0.014182 -0.000049   
GBPDKK  0.144478  0.294371  0.147369  ...  0.343769  0.571244  0.680225   
GBPNOK -0.196221 -0.256766 -0.250614  ...  1.000000  0.565720  0.249443   
GBPSEK -0.153524 -0.054440 -0.129661  ...  0.565720  1.000000  0.325864   
GBPSGD  0.262599  0.190713  0.256832  ...  0.249443  0.325864  1.000000   
GBPTRY  0.155539  0.093958  0.103188  ...  0.072453  0.057482  0.366262   
NOKJPY  0.189831  0.408101  0.793006  ... -0.581065 -0.254856  0.314942   
NOKSEK  0.075289  0.251699  0.172680  ... -0.548945  0.355114  0.060996   
SEKJPY  0.151464  0.274446  0.746343  ... -0.259071 -0.507523  0.300513   
SGDJPY -0.123542  0.194079  0.754121  ... -0.034170 -0.045399 -0.004955   
USDCNH -0.447486 -0.272675 -0.186632  ...  0.204401  0.148480 -0.225541   
USDCZK -0.410759 -0.166643 -0.239922  ...  0.233200  0.320419 -0.426494   

          GBPTRY    NOKJPY    NOKSEK    SEKJPY    SGDJPY    USDCNH    USDCZK  
EURUSD  0.281417  0.367305 -0.049602  0.427013 -0.061900 -0.571956 -0.881107  
GBPUSD  0.389010  0.362742  0.074701  0.338836 -0.078301 -0.545428 -0.697077  
USDCHF -0.220466 -0.151723  0.003827 -0.161708  0.259451  0.498127  0.646868  
USDJPY -0.139287  0.415457 -0.022183  0.471799  0.881815  0.422045  0.385782  
USDCAD -0.221339 -0.513605 -0.244101 -0.391819 -0.070735  0.486012  0.558194  
AUDUSD  0.241587  0.448873  0.203806  0.346699 -0.034588 -0.597839 -0.620403  
AUDNZD  0.008949  0.157618  0.070538  0.126414  0.147259 -0.046366 -0.000073  
AUDCAD  0.155539  0.189831  0.075289  0.151464 -0.123542 -0.447486 -0.410759  
AUDCHF  0.093958  0.408101  0.251699  0.274446  0.194079 -0.272675 -0.166643  
AUDJPY  0.103188  0.793006  0.172680  0.746343  0.754121 -0.186632 -0.239922  
CHFJPY  0.041248  0.611892 -0.026081  0.685167  0.774575  0.035608 -0.138834  
EURGBP -0.226357 -0.071311 -0.185332  0.049402  0.044778  0.084697 -0.097373  
EURAUD -0.043852 -0.238907 -0.322484 -0.041345 -0.010056  0.245766 -0.030998  
EURJPY  0.080202  0.726216 -0.062158  0.832348  0.867558 -0.018716 -0.304521  
EURCHF  0.075029  0.288785 -0.063726  0.356626  0.276797 -0.083697 -0.301266  
EURNZD -0.046456 -0.142260 -0.279888  0.035422  0.081427  0.213887 -0.032137  
EURCAD  0.102587 -0.093607 -0.305640  0.099188 -0.144576 -0.171067 -0.459961  
GBPCHF  0.234189  0.276800  0.096117  0.235910  0.181892 -0.127323 -0.153094  
GBPJPY  0.203548  0.722846  0.044254  0.756556  0.793673 -0.063483 -0.230890  
CADCHF -0.029673  0.307563  0.226774  0.187223  0.343123  0.090686  0.182686  
CADJPY  0.010736  0.722287  0.134918  0.699043  0.882958  0.092465  0.011274  
GBPAUD  0.130603 -0.194207 -0.196885 -0.077522 -0.039863  0.194455  0.042925  
GBPCAD  0.284675 -0.029624 -0.138230  0.055901 -0.168638 -0.229395 -0.353266  
GBPNZD  0.127186 -0.094668 -0.151361  0.000835  0.053467  0.161279  0.042212  
NZDCAD  0.141507  0.077171  0.024695  0.063377 -0.204069 -0.375677 -0.376099  
NZDCHF  0.094466  0.333169  0.221066  0.213806  0.118090 -0.255230 -0.171058  
NZDJPY  0.106488  0.761318  0.151524  0.726707  0.723334 -0.173311 -0.251473  
NZDUSD  0.243096  0.384553  0.173964  0.297222 -0.099768 -0.580420 -0.626784  
USDSGD -0.254303 -0.282964 -0.061406 -0.258780  0.121736  0.720614  0.741324  
AUDSGD  0.183973  0.463450  0.250176  0.334456  0.032393 -0.391870 -0.409643  
CHFSGD  0.094198 -0.016495 -0.054639  0.020509 -0.241200 -0.078291 -0.265235  
EURDKK -0.010976  0.016808  0.029726 -0.001277 -0.019047  0.005057  0.012764  
EURHKD  0.280634  0.365970 -0.047117  0.423811 -0.062986 -0.562073 -0.876379  
EURNOK -0.074157 -0.645186 -0.680546 -0.240464 -0.015080  0.261665  0.174212  
EURPLN -0.057076 -0.194816  0.034838 -0.238395 -0.029718  0.191912  0.425565  
EURSEK -0.130082 -0.371128  0.265947 -0.574695 -0.027070  0.245836  0.298274  
EURSGD  0.199391  0.314376 -0.144204  0.436964  0.026660 -0.202339 -0.680463  
EURTRY  0.956103  0.116731 -0.045961  0.158437 -0.012373 -0.162475 -0.266109  
EURZAR  0.022006 -0.133484 -0.197193 -0.006390  0.007360  0.189717  0.024857  
GBPDKK  0.233856  0.081647  0.195001 -0.041527 -0.033322 -0.081112  0.101044  
GBPNOK  0.072453 -0.581065 -0.548945 -0.259071 -0.034170  0.204401  0.233200  
GBPSEK  0.057482 -0.254856  0.355114 -0.507523 -0.045399  0.148480  0.320419  
GBPSGD  0.366262  0.314942  0.060996  0.300513 -0.004955 -0.225541 -0.426494  
GBPTRY  1.000000  0.127127 -0.003160  0.140754 -0.018215 -0.170311 -0.224689  
NOKJPY  0.127127  1.000000  0.430911  0.798540  0.663458 -0.186918 -0.348383  
NOKSEK -0.003160  0.430911  1.000000 -0.188751  0.009826 -0.077549  0.049930  
SEKJPY  0.140754  0.798540 -0.188751  1.000000  0.720977 -0.143944 -0.407972  
SGDJPY -0.018215  0.663458  0.009826  0.720977  1.000000  0.103027  0.042909  
USDCNH -0.170311 -0.186918 -0.077549 -0.143944  0.103027  1.000000  0.519997  
USDCZK -0.224689 -0.348383  0.049930 -0.407972  0.042909  0.519997  1.000000  

[50 rows x 50 columns]
In [3]:

# -------------------------------
# Step 3: Candidate Pair Selection using Correlation & Cointegration
# -------------------------------
candidate_pairs = []
symbol_list = df_prices.columns.tolist()

for i, sym1 in enumerate(symbol_list):
    for sym2 in symbol_list[i+1:]:
        corr_value = corr_matrix.loc[sym1, sym2]
        if corr_value > 0.8:
            # Run cointegration test on the two price series
            score, pvalue, _ = coint(df_prices[sym1], df_prices[sym2])
            if pvalue < 0.05:
                candidate_pairs.append((sym1, sym2, pvalue, corr_value))
                
print("Candidate Pairs (High Correlation & Cointegrated):")
for pair in candidate_pairs:
    print(pair)

if len(candidate_pairs) == 0:
    raise ValueError("No candidate pairs found with high correlation and cointegration.")

# Optionally, you can also use PCA & Clustering here to further group symbols,
# but for this example, we'll proceed with candidate pairs.
Candidate Pairs (High Correlation & Cointegrated):
('AUDUSD', 'NZDUSD', np.float64(0.029071952477892585), np.float64(0.891053344243205))
('AUDJPY', 'CADJPY', np.float64(0.020139018449132847), np.float64(0.8043796863766559))
('CHFJPY', 'EURJPY', np.float64(0.025397607487565806), np.float64(0.8154419546327693))
In [4]:
# Optional: PCA & Clustering for additional insight
pca = PCA(n_components=2)
pca_components = pca.fit_transform(returns.T)
pca_df = pd.DataFrame(pca_components, index=returns.columns, columns=['PC1','PC2'])
print("PCA Components:")
print(pca_df)

kmeans = KMeans(n_clusters=2, random_state=42)
pca_df['cluster'] = kmeans.fit_predict(pca_df)
print("Cluster Assignment:")
print(pca_df[['cluster']])
PCA Components:
             PC1       PC2
EURUSD -0.068192 -0.020048
GBPUSD -0.089713 -0.018949
USDCHF  0.112433  0.022101
USDJPY  0.072538  0.088778
USDCAD  0.126676 -0.040845
AUDUSD -0.141829  0.039940
AUDNZD  0.023960  0.006956
AUDCAD -0.046538  0.005291
AUDCHF -0.060629  0.068135
AUDJPY -0.100707  0.134864
CHFJPY -0.008567  0.060643
EURGBP  0.053044 -0.007520
EURAUD  0.104557 -0.066161
EURJPY -0.026952  0.074751
EURCHF  0.012880  0.008218
EURNZD  0.097594 -0.052595
EURCAD  0.027150 -0.054857
GBPCHF -0.008660  0.009418
GBPJPY -0.048592  0.075931
CADCHF  0.016843  0.056910
CADJPY -0.022842  0.123524
GBPAUD  0.082859 -0.065064
GBPCAD  0.005416 -0.053869
GBPNZD  0.076163 -0.051713
NZDCAD -0.039870 -0.007613
NZDCHF -0.053501  0.055236
NZDJPY -0.093532  0.121715
NZDUSD -0.134830  0.027091
USDSGD  0.097528 -0.003666
AUDSGD -0.076452  0.042628
CHFSGD  0.016224 -0.031500
EURDKK  0.031571 -0.006063
EURHKD -0.066269 -0.019982
EURNOK  0.125667 -0.069447
EURPLN  0.072275 -0.019012
EURSEK  0.098055 -0.032709
EURSGD -0.002318 -0.017346
EURTRY -0.212486 -0.276113
EURZAR  0.088358 -0.059437
GBPDKK  0.009699 -0.004573
GBPNOK  0.103332 -0.067368
GBPSEK  0.076569 -0.031341
GBPSGD -0.024292 -0.015827
GBPTRY -0.231359 -0.277327
NOKJPY -0.123414  0.136725
NOKSEK  0.002701  0.029036
SEKJPY -0.094317  0.102124
SGDJPY  0.006600  0.086656
USDCNH  0.086062 -0.005762
USDCZK  0.149105  0.000038
Cluster Assignment:
        cluster
EURUSD        0
GBPUSD        0
USDCHF        1
USDJPY        1
USDCAD        1
AUDUSD        0
AUDNZD        1
AUDCAD        0
AUDCHF        0
AUDJPY        0
CHFJPY        0
EURGBP        1
EURAUD        1
EURJPY        0
EURCHF        1
EURNZD        1
EURCAD        1
GBPCHF        0
GBPJPY        0
CADCHF        0
CADJPY        0
GBPAUD        1
GBPCAD        1
GBPNZD        1
NZDCAD        0
NZDCHF        0
NZDJPY        0
NZDUSD        0
USDSGD        1
AUDSGD        0
CHFSGD        1
EURDKK        1
EURHKD        0
EURNOK        1
EURPLN        1
EURSEK        1
EURSGD        1
EURTRY        0
EURZAR        1
GBPDKK        1
GBPNOK        1
GBPSEK        1
GBPSGD        0
GBPTRY        0
NOKJPY        0
NOKSEK        0
SEKJPY        0
SGDJPY        0
USDCNH        1
USDCZK        1
c:\Users\moham\miniconda3\envs\ml\Lib\site-packages\joblib\externals\loky\backend\context.py:136: UserWarning: Could not find the number of physical cores for the following reason:
[WinError 2] The system cannot find the file specified
Returning the number of logical cores instead. You can silence this warning by setting LOKY_MAX_CPU_COUNT to the number of cores you want to use.
  warnings.warn(
  File "c:\Users\moham\miniconda3\envs\ml\Lib\site-packages\joblib\externals\loky\backend\context.py", line 257, in _count_physical_cores
    cpu_info = subprocess.run(
               ^^^^^^^^^^^^^^^
  File "c:\Users\moham\miniconda3\envs\ml\Lib\subprocess.py", line 548, in run
    with Popen(*popenargs, **kwargs) as process:
         ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "c:\Users\moham\miniconda3\envs\ml\Lib\subprocess.py", line 1026, in __init__
    self._execute_child(args, executable, preexec_fn, close_fds,
  File "c:\Users\moham\miniconda3\envs\ml\Lib\subprocess.py", line 1538, in _execute_child
    hp, ht, pid, tid = _winapi.CreateProcess(executable, args,
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
In [5]:

# -------------------------------
# Step 4: Select a Pair & Align the Data
# -------------------------------
# Choose the first candidate pair as an example
pair1, pair2, pval, corr_val = candidate_pairs[0]
print(f"Selected Pair: {pair1} vs {pair2} (p-value: {pval:.4f}, corr: {corr_val:.2f})")

# Align the two series
S1 = df_prices[pair1].dropna()
S2 = df_prices[pair2].dropna()
df_pair = pd.concat([S1, S2], axis=1).dropna()
df_pair.columns = [pair1, pair2]
Selected Pair: AUDUSD vs NZDUSD (p-value: 0.0291, corr: 0.89)
In [6]:

# -------------------------------
# Step 5: Dynamic Signal Generation with Kalman Filter
# -------------------------------
# Function to estimate dynamic hedge ratio using a Kalman Filter
def kalman_filter_estimate(y, x):
    n = len(y)
    beta = 0.0
    P = 1.0
    Q = 1e-5  # Process noise variance
    R = 1e-2  # Measurement noise variance
    beta_history = []
    
    for i in range(n):
        beta_pred = beta
        P_pred = P + Q
        
        # Kalman Gain computation
        K = P_pred * x[i] / (x[i]**2 * P_pred + R)
        
        # Update the state estimate using the measurement y[i]
        beta = beta_pred + K * (y[i] - beta_pred * x[i])
        P = (1 - K * x[i]) * P_pred
        
        beta_history.append(beta)
    return np.array(beta_history)

# Estimate dynamic hedge ratio for the pair: S1 = beta_t * S2 + error
beta_est = kalman_filter_estimate(df_pair[pair1].values, df_pair[pair2].values)
df_pair['beta'] = beta_est

# Compute dynamic spread: difference between S1 and the hedged S2
df_pair['spread'] = df_pair[pair1] - df_pair['beta'] * df_pair[pair2]

# Use a rolling window to compute spread mean and standard deviation (or you could use Kalman state covariances)
window = 60
df_pair['spread_mean'] = df_pair['spread'].rolling(window).mean()
df_pair['spread_std'] = df_pair['spread'].rolling(window).std()
df_pair['zscore'] = (df_pair['spread'] - df_pair['spread_mean']) / df_pair['spread_std']
In [7]:

# -------------------------------
# Step 6: Trading Signal Generation
# -------------------------------
# Define thresholds for signal generation
entry_threshold = 1.5  # for entering trades
exit_threshold = 0.5   # for exiting trades

df_pair['long_signal'] = df_pair['zscore'] < -entry_threshold
df_pair['short_signal'] = df_pair['zscore'] > entry_threshold
df_pair['exit_signal'] = abs(df_pair['zscore']) < exit_threshold
In [8]:

# -------------------------------
# Step 7: Backtesting with vectorbt
# -------------------------------
# Here we simulate trades on the first asset's price (S1) while assuming a hedged position against S2.
entries = df_pair['long_signal']
short_entries = df_pair['short_signal']
exits = df_pair['exit_signal']

portfolio = vbt.Portfolio.from_signals(
    close=df_pair[pair1],
    entries=entries,
    exits=exits,
    short_entries=short_entries,
    short_exits=exits,
    size=1,
    size_type='percent',
    init_cash=10000,
    fees=0.001,  # example fee rate
    freq='1D'
)

print(portfolio.stats())
portfolio.plot().show()
Start                                2021-04-29 00:00:00
End                                  2025-03-05 00:00:00
Period                                 996 days 00:00:00
Start Value                                      10000.0
End Value                                   10495.182943
Total Return [%]                                4.951829
Benchmark Return [%]                           -19.02309
Max Gross Exposure [%]                             100.0
Total Fees Paid                               577.999539
Max Drawdown [%]                                9.337445
Max Drawdown Duration                  521 days 00:00:00
Total Trades                                          28
Total Closed Trades                                   28
Total Open Trades                                      0
Open Trade PnL                                       0.0
Win Rate [%]                                   39.285714
Best Trade [%]                                  6.091998
Worst Trade [%]                                -4.004551
Avg Winning Trade [%]                           2.553578
Avg Losing Trade [%]                           -1.320344
Avg Winning Trade Duration    16 days 02:10:54.545454545
Avg Losing Trade Duration     16 days 05:38:49.411764705
Profit Factor                                   1.210917
Expectancy                                     17.685105
Sharpe Ratio                                    0.239466
Calmar Ratio                                    0.191375
Omega Ratio                                     1.049196
Sortino Ratio                                   0.354526
dtype: object
[Data output - unsupported data type map[string]interface {} for mime type application/vnd.plotly.v1+json]
In [9]:

# -------------------------------
# Optional: Visualization of the Dynamic Spread and Z-Score
# -------------------------------
plt.figure(figsize=(12, 6))
plt.subplot(2,1,1)
plt.plot(df_pair.index, df_pair['spread'], label='Dynamic Spread')
plt.plot(df_pair.index, df_pair['spread_mean'], label='Rolling Mean', alpha=0.7)
plt.legend()
plt.title('Dynamic Spread via Kalman Filter')

plt.subplot(2,1,2)
plt.plot(df_pair.index, df_pair['zscore'], label='Z-Score', color='orange')
plt.axhline(entry_threshold, color='red', linestyle='--')
plt.axhline(-entry_threshold, color='red', linestyle='--')
plt.axhline(exit_threshold, color='green', linestyle='--')
plt.axhline(-exit_threshold, color='green', linestyle='--')
plt.legend()
plt.title('Z-Score of Spread')
plt.tight_layout()
plt.show()

# -------------------------------
# Shutdown MT5 connection
# -------------------------------
mt5.shutdown()
Out [9]:
True