W

WquGuru·QuantLearn

CorrelationAdvanced

Oil Money Trading

Commodity-currency correlation strategies

Historical Econometric Analysis

Comprehensive analysis of oil-currency relationships across multiple countries and time periods, demonstrating when causality exists versus pure correlation.

Granger Causality Test Results

Granger Causality Test Results

Statistical results showing periods when oil prices have significant predictive power for various petrocurrencies.

Oil-Currency Regime Analysis

Oil-Currency Regime Analysis

Rolling correlation analysis identifying strong vs weak oil-currency relationship periods with structural break detection.

Strategy Performance by Currency

Strategy Performance by Currency

Comparative performance across different petrocurrencies (CAD, NOK, RUB, MXN) during various oil market cycles.

Petrocurrency Causality Analysis

Oil Money Trading investigates whether crude oil truly drives petrocurrency movements or if the relationship is merely correlational.

Traditional research examines correlation between oil and currencies like CAD, NOK, RUB, but correlation ≠ causation.

The strategy requires rigorous econometric testing including Granger causality, cointegration, and structural break analysis.

Petrocurrencies should theoretically strengthen when oil prices rise due to improved terms of trade and current account balances.

Reality is more complex: central bank interventions, monetary policy, and global risk sentiment can override oil fundamentals.

The strategy combines quantitative oil-currency modeling with fundamental economic analysis.

Success depends on identifying when the oil-currency relationship is strong versus when other factors dominate.

Mathematical Foundation

1
Granger Causality Test

FXt=α+i=1pβiFXti+j=1qγjOiltj+ϵtFX_t = \alpha + \sum_{i=1}^{p} \beta_i FX_{t-i} + \sum_{j=1}^{q} \gamma_j Oil_{t-j} + \epsilon_t

Tests if oil prices have predictive power for currency movements beyond what currency's own history provides.

2
Error Correction Model

ΔFXt=α+λECTt1+i=1pβiΔFXti+j=0qγjΔOiltj+ϵt\Delta FX_t = \alpha + \lambda ECT_{t-1} + \sum_{i=1}^{p} \beta_i \Delta FX_{t-i} + \sum_{j=0}^{q} \gamma_j \Delta Oil_{t-j} + \epsilon_t

Long-run relationship between oil and currency with short-term adjustment dynamics.

3
Structural Break Test

SupF=maxτΛFT(τ)SupF = \max_{\tau \in \Lambda} F_T(\tau)

Tests for structural breaks in oil-currency relationship using Andrews' supremum F-test.

4
Rolling Correlation

ρt=i=tw+1t(OiliOilˉ)(FXiFXˉ)i=tw+1t(OiliOilˉ)2i=tw+1t(FXiFXˉ)2\rho_t = \frac{\sum_{i=t-w+1}^{t} (Oil_i - \bar{Oil})(FX_i - \bar{FX})}{\sqrt{\sum_{i=t-w+1}^{t} (Oil_i - \bar{Oil})^2 \sum_{i=t-w+1}^{t} (FX_i - \bar{FX})^2}}

Time-varying correlation coefficient over rolling window w to detect regime changes.

Core Algorithm Implementation

The Oil Money algorithm combines econometric testing with dynamic regime detection to identify tradeable oil-currency relationships.

Data Preparation and Testing

python
def prepare_oil_currency_data(oil_prices, fx_rates, country='CAD'):
    """Prepare and test oil-currency data for econometric analysis"""
    
    # Align data and handle missing values
    data = pd.concat([oil_prices, fx_rates], axis=1).dropna()
    data.columns = ['oil', 'fx']
    
    # Log transformation for interpretation as elasticities
    data['log_oil'] = np.log(data['oil'])
    data['log_fx'] = np.log(data['fx'])
    
    # Calculate returns
    data['oil_returns'] = data['log_oil'].diff()
    data['fx_returns'] = data['log_fx'].diff()
    
    # Test for unit roots (stationarity)
    from statsmodels.tsa.stattools import adfuller
    
    adf_oil = adfuller(data['log_oil'].dropna())
    adf_fx = adfuller(data['log_fx'].dropna())
    
    # Test for cointegration
    from statsmodels.tsa.vector_ar.vecm import coint_johansen
    
    if adf_oil[1] > 0.05 and adf_fx[1] > 0.05:  # Both non-stationary
        johansen_test = coint_johansen(data[['log_oil', 'log_fx']].dropna(), det_order=0, k_ar_diff=1)
        cointegration_p = johansen_test.lr1[0]  # Trace statistic
    else:
        cointegration_p = np.nan
    
    return data, {
        'oil_unit_root_p': adf_oil[1],
        'fx_unit_root_p': adf_fx[1], 
        'cointegration_evidence': cointegration_p,
        'country': country
    }

Comprehensive data preparation including stationarity testing and cointegration analysis for oil-currency pairs.

Granger Causality Analysis

python
def granger_causality_analysis(data, max_lags=5):
    """Test for Granger causality between oil and currency"""
    from statsmodels.tsa.stattools import grangercausalitytests
    
    # Test oil -> currency causality
    oil_to_fx_results = grangercausalitytests(
        data[['fx_returns', 'oil_returns']].dropna(), 
        maxlag=max_lags,
        verbose=False
    )
    
    # Test currency -> oil causality  
    fx_to_oil_results = grangercausalitytests(
        data[['oil_returns', 'fx_returns']].dropna(),
        maxlag=max_lags, 
        verbose=False
    )
    
    # Extract p-values for each lag
    oil_to_fx_pvals = [oil_to_fx_results[lag+1][0]['ssr_ftest'][1] for lag in range(max_lags)]
    fx_to_oil_pvals = [fx_to_oil_results[lag+1][0]['ssr_ftest'][1] for lag in range(max_lags)]
    
    # Find optimal lag based on minimum p-value
    best_lag_oil_fx = np.argmin(oil_to_fx_pvals) + 1
    best_lag_fx_oil = np.argmin(fx_to_oil_pvals) + 1
    
    return {
        'oil_to_fx_pval': min(oil_to_fx_pvals),
        'fx_to_oil_pval': min(fx_to_oil_pvals),
        'best_lag_oil_fx': best_lag_oil_fx,
        'best_lag_fx_oil': best_lag_fx_oil,
        'oil_granger_causes_fx': min(oil_to_fx_pvals) < 0.05,
        'fx_granger_causes_oil': min(fx_to_oil_pvals) < 0.05
    }

Rigorous Granger causality testing to establish whether oil has predictive power for currency movements.

Dynamic Regime Detection

python
def detect_oil_fx_regimes(data, window=60, correlation_threshold=0.3):
    """Detect regime changes in oil-currency relationship"""
    
    # Rolling correlations and statistics
    data['rolling_corr'] = data['oil_returns'].rolling(window).corr(data['fx_returns'])
    data['rolling_oil_vol'] = data['oil_returns'].rolling(window).std() * np.sqrt(252)
    data['rolling_fx_vol'] = data['fx_returns'].rolling(window).std() * np.sqrt(252)
    
    # Regime identification
    data['strong_oil_regime'] = (
        (abs(data['rolling_corr']) > correlation_threshold) &
        (data['rolling_oil_vol'] > data['rolling_oil_vol'].quantile(0.6))
    )
    
    # Structural break detection using CUSUM test
    from statsmodels.stats.diagnostic import breaks_cusumolsresid
    
    try:
        # Simple regression for CUSUM test
        y = data['fx_returns'].dropna()
        x = data['oil_returns'].dropna()
        aligned_data = pd.concat([y, x], axis=1).dropna()
        
        if len(aligned_data) > 30:
            cusum_stat, cusum_p = breaks_cusumolsresid(
                aligned_data.iloc[:, 0], 
                aligned_data.iloc[:, 1:2]
            )
            data['cusum_break_detected'] = cusum_p < 0.05
        else:
            data['cusum_break_detected'] = False
            
    except:
        data['cusum_break_detected'] = False
    
    return data

Dynamic regime detection using rolling correlations and structural break tests to identify periods of strong oil-currency relationships.

Trading Signal Generation

python
def generate_oil_money_signals(data, causality_results, min_correlation=0.4):
    """Generate trading signals based on oil-currency analysis"""
    
    data['signal'] = 0
    data['regime_strength'] = 0
    
    # Only trade when Granger causality is detected
    if not causality_results['oil_granger_causes_fx']:
        return data
    
    # Get optimal lag from causality analysis
    lag = causality_results['best_lag_oil_fx']
    
    for i in range(lag, len(data)):
        current_corr = data['rolling_corr'].iloc[i]
        in_strong_regime = data['strong_oil_regime'].iloc[i]
        
        if pd.notna(current_corr) and abs(current_corr) > min_correlation and in_strong_regime:
            
            # Oil returns for signal generation
            oil_signal = np.sign(data['oil_returns'].iloc[i-lag:i].mean())
            
            # Direction depends on correlation sign
            if current_corr > 0:  # Positive correlation
                fx_signal = oil_signal  # Same direction
            else:  # Negative correlation
                fx_signal = -oil_signal  # Opposite direction
                
            data.loc[data.index[i], 'signal'] = fx_signal
            data.loc[data.index[i], 'regime_strength'] = abs(current_corr)
    
    # Risk management: exit signals during regime breaks
    break_points = data['cusum_break_detected'].shift(1).fillna(False)
    data.loc[break_points, 'signal'] = 0
    
    # Position management
    data['position'] = data['signal'].replace(0, np.nan).fillna(method='ffill').fillna(0)
    
    return data

Signal generation that only trades when Granger causality is detected and during strong oil-currency correlation regimes.

Implementation Steps

  1. 1Select appropriate oil-currency pairs (WTI/Brent with CAD, NOK, RUB, MXN)
  2. 2Test for unit roots and cointegration between oil prices and exchange rates
  3. 3Conduct Granger causality tests to establish predictive relationships
  4. 4Implement rolling correlation analysis to detect regime changes
  5. 5Use structural break tests to identify relationship instability
  6. 6Generate signals only during periods of strong, causal oil-currency relationships
  7. 7Apply position sizing based on regime strength and volatility
  8. 8Monitor for structural breaks and adjust exposure accordingly
  9. 9Incorporate fundamental analysis (oil inventories, OPEC decisions, geopolitical events)

Key Metrics

Granger causality test p-values and optimal lag selection
Rolling correlation stability and regime persistence
Structural break frequency and recovery time
Signal accuracy during different oil volatility regimes
Performance comparison across different petrocurrencies
Risk-adjusted returns during oil bull vs bear markets
Model parameter sensitivity and robustness testing

Risk Considerations

Oil-currency relationships can break down during financial crises or central bank interventions
Geopolitical events may create temporary decoupling between oil and currencies
Monetary policy divergence can override fundamental oil-based currency drivers
Structural breaks in the relationship may not be detected in real-time
Commodity currency relationships vary significantly across different time horizons
Transaction costs and bid-ask spreads can be significant in currency markets
Model assumes stable economic structures that may change over time

Practice Implementation

Prerequisites

Mathematical Background

  • • Linear regression and OLS estimation
  • • Time series analysis (stationarity, unit roots)
  • • Hypothesis testing and p-values
  • • Basic econometrics (error correction models)

Technical Skills

  • • Python programming (pandas, numpy)
  • • Statistical libraries (statsmodels)
  • • Data visualization (matplotlib)
  • • Financial data handling (yfinance)

Complete Implementation

Access the full Python implementation from the original quantitative trading repository:

bash
# Complete pair trading implementation
git clone https://github.com/je-suis-tm/quant-trading.git
cd quant-trading
python "Pair trading backtest.py"
# Modify tickers and parameters for your own analysis

Learning Checkpoints

1

Understand Cointegration

Can you explain why two assets might be cointegrated and what breaks this relationship?

2

Interpret Statistical Tests

Practice reading ADF test results and understanding when to accept/reject cointegration.

3

Signal Generation

Implement Z-score calculations and understand threshold selection (±1σ vs ±2σ).

4

Risk Management

Understand position sizing, monitoring regime changes, and exit strategies.

Recommended Learning Path

Immediate Actions

  • Download and run the Python script
  • Test with different asset pairs
  • Experiment with threshold parameters

Advanced Studies

  • Learn Johansen cointegration test
  • Study Vector Error Correction Models
  • Explore multiple asset pair trading

Important Disclaimer

This strategy involves significant risk. Historical cointegration relationships can break permanently. Always use proper risk management, position sizing, and never risk more than you can afford to lose. Paper trade extensively before using real capital.

Quick Navigation