224 lines
8.1 KiB
Python
224 lines
8.1 KiB
Python
"""
|
|
Configuration file for MMAR Volatility Forecasting Model
|
|
Based on: "Volatility Forecasting with the Multifractal Model of Asset Returns" (Zhang, 2017)
|
|
"""
|
|
|
|
import numpy as np
|
|
from pathlib import Path
|
|
|
|
|
|
BASE_DIR = Path(__file__).resolve().parent
|
|
|
|
# =============================================================================
|
|
# DATA PARAMETERS
|
|
# =============================================================================
|
|
|
|
# Symbol and timeframe
|
|
SYMBOL = "EURUSD"
|
|
TIMEFRAME_MT5 = "M5" # MT5 timeframe code: M1, M5, M10, M15, M30, H1, H4, D1
|
|
TIMEFRAME_MINUTES = 5 # For internal calculations (1 min = 1)
|
|
|
|
# Date range for historical data (training period)
|
|
START_DATE = "2024-08-03"
|
|
END_DATE = "2026-03-01"
|
|
|
|
# Forecast parameters
|
|
FORECAST_DAYS = 25 # Number of days to forecast
|
|
FORECAST_INTERVAL_MINUTES = TIMEFRAME_MINUTES # Keep forecast units aligned with loaded bars
|
|
FORECAST_LENGTH = int(FORECAST_DAYS * (24 * 60) / TIMEFRAME_MINUTES) # Match actual forecast horizon
|
|
TRADING_DAYS_PER_YEAR = 252
|
|
|
|
# MetaTrader 5 Settings
|
|
MT5_ENABLED = True # Set to False to use CSV files only
|
|
MT5_LOGIN = None # Set your MT5 login (None = use current terminal)
|
|
MT5_PASSWORD = "" # Leave empty if already logged in
|
|
MT5_SERVER = "" # Leave empty if already connected
|
|
|
|
# =============================================================================
|
|
# STEP 1: PARTITION FUNCTION PARAMETERS
|
|
# =============================================================================
|
|
|
|
# Delta t range for partition function (in NUMBER OF OBSERVATIONS)
|
|
# Zhang used values spaced by factor of 1.1, from ~400s to 9000s
|
|
# For 1-minute data: 400s = 7 obs, 9000s = 150 obs
|
|
DELTA_T_MIN = 1 # Minimum number of observations per interval
|
|
DELTA_T_MAX = 150 # Maximum number of observations per interval
|
|
DELTA_T_SPACING_FACTOR = 1.1 # Logarithmic spacing
|
|
NUM_DELTA_T_VALUES = 30 # Number of delta_t values to test
|
|
|
|
# q values for moment scaling analysis
|
|
# Paper used q from 0.01 to 30.00
|
|
Q_MIN = 0.01
|
|
Q_MAX = 30.0
|
|
Q_STEP = 0.5 # Step size for q values
|
|
|
|
# Linearity threshold (R-squared for partition plots)
|
|
# Paper achieved average R² of 0.66
|
|
MIN_R_SQUARED = 0.60 # Minimum R² to consider scaling behavior valid
|
|
|
|
# =============================================================================
|
|
# STEP 2: SCALING FUNCTION PARAMETERS
|
|
# =============================================================================
|
|
|
|
# Number of discrete q values for scaling function estimation
|
|
NUM_Q_VALUES = 60
|
|
|
|
# =============================================================================
|
|
# STEP 3: MULTIFRACTAL SPECTRUM PARAMETERS
|
|
# =============================================================================
|
|
|
|
# Grid search parameters for fitting spectrum to distributions
|
|
ALPHA_0_MIN = 0.1
|
|
ALPHA_0_MAX = 1.0
|
|
ALPHA_0_STEP = 0.01
|
|
|
|
# For binomial distribution
|
|
ALPHA_MIN_RANGE = (0.01, 0.5)
|
|
ALPHA_MAX_RANGE = (0.5, 2.0)
|
|
ALPHA_GRID_STEP = 0.01
|
|
|
|
# For gamma distribution
|
|
GAMMA_MIN = 0.1
|
|
GAMMA_MAX = 10.0
|
|
GAMMA_STEP = 0.1
|
|
|
|
# =============================================================================
|
|
# STEP 4-6: CASCADE AND FBM PARAMETERS
|
|
# =============================================================================
|
|
|
|
# Multiplicative cascade parameters for standalone Step 4/5 artifacts
|
|
CASCADE_B = 2 # Binary cascade (divide into 2 intervals at each step)
|
|
CASCADE_K_MAX = 10 # Standalone cascade depth (2^10 = 1024 intervals)
|
|
|
|
# FBM generation parameters
|
|
FBM_METHOD = "cholesky" # Method for generating FBM: 'cholesky' or 'fft'
|
|
|
|
# =============================================================================
|
|
# STEP 7: MONTE CARLO SIMULATION PARAMETERS
|
|
# =============================================================================
|
|
|
|
# Number of Monte Carlo simulations
|
|
NUM_SIMULATIONS = 1000 # Paper used 10,000
|
|
|
|
# Random seed for reproducibility
|
|
RANDOM_SEED = 42
|
|
|
|
# =============================================================================
|
|
# OUTPUT PARAMETERS
|
|
# =============================================================================
|
|
|
|
# Directory for saving results
|
|
OUTPUT_DIR = BASE_DIR / "results"
|
|
|
|
# Directory for saving plots
|
|
PLOT_DIR = BASE_DIR / "plots"
|
|
|
|
# Directory for data
|
|
DATA_DIR = BASE_DIR / "data"
|
|
|
|
# Verbose output
|
|
VERBOSE = True
|
|
|
|
# Save intermediate results
|
|
SAVE_INTERMEDIATE = True
|
|
|
|
# =============================================================================
|
|
# HELPER FUNCTIONS
|
|
# =============================================================================
|
|
|
|
def generate_q_values():
|
|
"""Generate array of q values for partition function."""
|
|
return np.arange(Q_MIN, Q_MAX + Q_STEP, Q_STEP)
|
|
|
|
def generate_delta_t_values():
|
|
"""
|
|
Generate array of delta t values with logarithmic spacing.
|
|
|
|
Returns values in NUMBER OF OBSERVATIONS (not seconds or minutes).
|
|
For 1-minute data, delta_t=60 means 60 one-minute returns = 1 hour.
|
|
|
|
Returns:
|
|
--------
|
|
np.ndarray
|
|
Array of delta_t values (integers, number of observations)
|
|
"""
|
|
delta_t_values = []
|
|
current = DELTA_T_MIN
|
|
while current <= DELTA_T_MAX:
|
|
delta_t_values.append(int(current))
|
|
current *= DELTA_T_SPACING_FACTOR
|
|
|
|
# Remove duplicates and sort
|
|
return np.unique(np.array(delta_t_values))
|
|
|
|
def periods_per_day():
|
|
"""Return the number of forecast intervals in a 24-hour day."""
|
|
return (24 * 60) / FORECAST_INTERVAL_MINUTES
|
|
|
|
def periods_per_year():
|
|
"""Return the annualization factor for the configured forecast interval."""
|
|
return periods_per_day() * TRADING_DAYS_PER_YEAR
|
|
|
|
def daily_window_size():
|
|
"""Return the nearest whole-number rolling window for one day."""
|
|
return max(1, int(round(periods_per_day())))
|
|
|
|
def interval_label(minutes=None):
|
|
"""Return a short display label for an interval length in minutes."""
|
|
minutes = FORECAST_INTERVAL_MINUTES if minutes is None else minutes
|
|
if minutes < 60:
|
|
return f"{minutes:g}-min"
|
|
|
|
hours = minutes / 60
|
|
return f"{hours:g}-hour"
|
|
|
|
def get_trading_hours_filter():
|
|
"""
|
|
Return function to filter trading hours.
|
|
For EURUSD (24h FX market), we use full day without filtering.
|
|
|
|
Note: Seasonality filtering has been removed as we test without it first.
|
|
"""
|
|
def filter_func(hour, minute):
|
|
# Allow full 24h trading day
|
|
return True
|
|
return filter_func
|
|
|
|
# =============================================================================
|
|
# VALIDATION
|
|
# =============================================================================
|
|
|
|
def validate_config():
|
|
"""Validate configuration parameters."""
|
|
assert DELTA_T_MIN > 0, "DELTA_T_MIN must be positive"
|
|
assert DELTA_T_MAX > DELTA_T_MIN, "DELTA_T_MAX must be greater than DELTA_T_MIN"
|
|
assert Q_MIN > 0, "Q_MIN must be positive"
|
|
assert Q_MAX > Q_MIN, "Q_MAX must be greater than Q_MIN"
|
|
assert 0 <= MIN_R_SQUARED <= 1, "MIN_R_SQUARED must be between 0 and 1"
|
|
assert TIMEFRAME_MINUTES > 0, "TIMEFRAME_MINUTES must be positive"
|
|
assert FORECAST_INTERVAL_MINUTES > 0, "FORECAST_INTERVAL_MINUTES must be positive"
|
|
assert FORECAST_LENGTH > 0, "FORECAST_LENGTH must be positive"
|
|
assert FORECAST_INTERVAL_MINUTES == TIMEFRAME_MINUTES, (
|
|
"FORECAST_INTERVAL_MINUTES should match TIMEFRAME_MINUTES so forecasts, "
|
|
"realized volatility, and annualization use the same return interval"
|
|
)
|
|
assert NUM_SIMULATIONS > 0, "NUM_SIMULATIONS must be positive"
|
|
assert CASCADE_B >= 2, "CASCADE_B must be at least 2"
|
|
assert CASCADE_K_MAX > 0, "CASCADE_K_MAX must be positive"
|
|
|
|
print("✓ Configuration validated successfully")
|
|
|
|
if __name__ == "__main__":
|
|
validate_config()
|
|
print(f"\nMMar Forecast Configuration")
|
|
print(f"=" * 50)
|
|
print(f"Symbol: {SYMBOL}")
|
|
print(f"Period: {START_DATE} to {END_DATE}")
|
|
print(f"Forecast: {FORECAST_DAYS} days ahead")
|
|
print(f"Forecast interval: {FORECAST_INTERVAL_MINUTES} minutes")
|
|
print(f"Forecast simulation length: {FORECAST_LENGTH} returns")
|
|
print(f"Monte Carlo simulations: {NUM_SIMULATIONS}")
|
|
print(f"\nΔt range: {DELTA_T_MIN}s to {DELTA_T_MAX}s")
|
|
print(f"q range: {Q_MIN} to {Q_MAX}")
|
|
print(f"Number of q values: {len(generate_q_values())}")
|
|
print(f"Number of Δt values: {len(generate_delta_t_values())}")
|