using configuration file

This commit is contained in:
Oleg Sheynin 2025-06-12 16:52:49 -04:00
parent 200a1bf307
commit 671422976d
6 changed files with 162 additions and 138 deletions

33
configuration/crypto.cfg Normal file
View File

@ -0,0 +1,33 @@
{
"security_type": "CRYPTO",
"data_directory": "./data/crypto",
"datafiles": [
"20250519.mktdata.ohlcv.db"
],
"db_table_name": "bnbspot_ohlcv_1min",
"exchange_id": "BNBSPOT",
"instrument_id_pfx": "PAIR-",
"instruments": [
"BTC-USDT",
"BCH-USDT",
"ETH-USDT",
"LTC-USDT",
"XRP-USDT",
"ADA-USDT",
"SOL-USDT",
"DOT-USDT"
],
"trading_hours": {
"begin_session": "00:00:00",
"end_session": "23:59:00",
"timezone": "UTC"
},
"price_column": "close",
"min_required_points": 30,
"zero_threshold": 1e-10,
"dis-equilibrium_open_trshld": 2.0,
"dis-equilibrium_close_trshld": 0.5,
"training_minutes": 120,
"funding_per_pair": 2000.0,
"strategy_class": "strategies.StaticFitStrategy"
}

35
configuration/equity.cfg Normal file
View File

@ -0,0 +1,35 @@
{
"security_type": "EQUITY",
"data_directory": "./data/equity",
"datafiles": [
# "20250508.alpaca_sim_md.db",
"20250509.alpaca_sim_md.db",
# "20250512.alpaca_sim_md.db",
# "20250513.alpaca_sim_md.db",
# "20250514.alpaca_sim_md.db",
# "20250515.alpaca_sim_md.db",
# "20250516.alpaca_sim_md.db",
# "20250519.alpaca_sim_md.db",
# "20250520.alpaca_sim_md.db"
],
"db_table_name": "md_1min_bars",
"exchange_id": "ALPACA",
"instrument_id_pfx": "STOCK-",
"instruments": [
"COIN",
"GBTC"
],
"trading_hours": {
"begin_session": "9:30:00",
"end_session": "16:00:00",
"timezone": "America/New_York"
},
"price_column": "close",
"min_required_points": 30,
"zero_threshold": 1e-10,
"dis-equilibrium_open_trshld": 2.0,
"dis-equilibrium_close_trshld": 1.0,
"training_minutes": 120,
"funding_per_pair": 2000.0,
"strategy_class": "strategies.StaticFitStrategy"
}

View File

@ -0,0 +1 @@
Create python code that tests pairs trading strategy

28
scripts/load_crypto_1min.sh Executable file
View File

@ -0,0 +1,28 @@
#!/usr/bin/env bash
# -------------------------------------
# --- Given month, specific dates
# -------------------------------------
# for dt in 20250528 20250529 20250530 20250531; do
# rsync -ahvv cvtt@hs01.cvtt.vpn:/works/cvtt/md_archive/crypto/sim/2025/2025-05/${dt}.*.gz ./
# done
# -------------------------------------
# -------------------------------------
# --- Current month - all files
# -------------------------------------
pushd ./data/crypto
rsync -ahvv cvtt@hs01.cvtt.vpn:/works/cvtt/md_archive/crypto/sim/*.gz ./
# -------------------------------------
for srcfname in $(ls *.db.gz); do
dt="${srcfname:0:8}"
tgtfile=${dt}.mktdata.ohlcv.db
echo "${srcfname} -> ${tgtfile}"
gunzip -c $srcfname > temp.db
rm -f ${tgtfile} && sqlite3 temp.db ".dump md_1min_bars" | sqlite3 ${tgtfile} && rm ${srcfname}
done
rm temp.db
popd

File diff suppressed because one or more lines are too long

View File

@ -1,3 +1,6 @@
import argparse
import hjson
import importlib
from typing import Any, Dict, List from typing import Any, Dict, List
@ -9,106 +12,15 @@ from tools.trading_pair import TradingPair
from results import BacktestResult from results import BacktestResult
# ------------------------ Configuration ------------------------ def load_config(config_path: str) -> Dict:
# Default configuration with open(config_path, "r") as f:
CRYPTO_CONFIG: Dict = { config = hjson.load(f)
"security_type": "CRYPTO", return config
# --- Data retrieval
"data_directory": "./data/crypto",
"datafiles": [
"20250519.mktdata.ohlcv.db",
# "20250520.mktdata.ohlcv.db",
# "20250521.mktdata.ohlcv.db",
# "20250522.mktdata.ohlcv.db",
# "20250523.mktdata.ohlcv.db",
# "20250524.mktdata.ohlcv.db",
# "20250525.mktdata.ohlcv.db",
],
"db_table_name": "bnbspot_ohlcv_1min",
# ----- Instruments
"exchange_id": "BNBSPOT",
"instrument_id_pfx": "PAIR-",
"instruments": [
"BTC-USDT",
"BCH-USDT",
"ETH-USDT",
"LTC-USDT",
"XRP-USDT",
"ADA-USDT",
"SOL-USDT",
"DOT-USDT",
],
"trading_hours": {
"begin_session": "00:00:00",
"end_session": "23:59:00",
"timezone": "UTC",
},
# ----- Model Settings
"price_column": "close",
"min_required_points": 30,
"zero_threshold": 1e-10,
"dis-equilibrium_open_trshld": 2.0,
"dis-equilibrium_close_trshld": 0.5,
# "training_minutes": 120,
"training_minutes": 120,
# ----- Validation
"funding_per_pair": 2000.0, # USD
}
# ========================== EQUITIES
EQT_CONFIG: Dict = {
# --- Data retrieval
"security_type": "EQUITY",
"data_directory": "./data/equity",
"datafiles": [
# "20250508.alpaca_sim_md.db",
"20250509.alpaca_sim_md.db",
# "20250512.alpaca_sim_md.db",
# "20250513.alpaca_sim_md.db",
# "20250514.alpaca_sim_md.db",
# "20250515.alpaca_sim_md.db",
# "20250516.alpaca_sim_md.db",
# "20250519.alpaca_sim_md.db",
# "20250520.alpaca_sim_md.db"
],
"db_table_name": "md_1min_bars",
# ----- Instruments
"exchange_id": "ALPACA",
"instrument_id_pfx": "STOCK-",
"instruments": [
"COIN",
"GBTC",
# "HOOD",
# "MSTR",
# "PYPL",
],
"trading_hours": {
"begin_session": "9:30:00",
"end_session": "16:00:00",
"timezone": "America/New_York",
},
# ----- Model Settings
"price_column": "close",
"min_required_points": 30,
"zero_threshold": 1e-10,
"dis-equilibrium_open_trshld": 2.0,
"dis-equilibrium_close_trshld": 1.0, #0.5,
"training_minutes": 120,
# ----- Validation
"funding_per_pair": 2000.0,
}
# CONFIG = CRYPTO_CONFIG def run_all_pairs(
CONFIG = EQT_CONFIG config: Dict, datafile: str, price_column: str, bt_result: BacktestResult, strategy
STRATEGY = StaticFitStrategy() ) -> None:
# CONFIG = CRYPTO_CONFIG
# STRATEGY = SlidingFitStrategy()
def run_all_pairs(config: Dict, datafile: str, price_column: str, bt_result: BacktestResult) -> None:
def _create_pairs(config: Dict) -> List[TradingPair]: def _create_pairs(config: Dict) -> List[TradingPair]:
nonlocal datafile nonlocal datafile
@ -117,7 +29,7 @@ def run_all_pairs(config: Dict, datafile: str, price_column: str, bt_result: Bac
unique_index_pairs = [(i, j) for i in all_indexes for j in all_indexes if i < j] unique_index_pairs = [(i, j) for i in all_indexes for j in all_indexes if i < j]
pairs = [] pairs = []
market_data_df = load_market_data( market_data_df = load_market_data(
f'{config["data_directory"]}/{datafile}', config=CONFIG f'{config["data_directory"]}/{datafile}', config=config
) )
for a_index, b_index in unique_index_pairs: for a_index, b_index in unique_index_pairs:
pair = TradingPair( pair = TradingPair(
@ -129,10 +41,11 @@ def run_all_pairs(config: Dict, datafile: str, price_column: str, bt_result: Bac
pairs.append(pair) pairs.append(pair)
return pairs return pairs
pairs_trades = [] pairs_trades = []
for pair in _create_pairs(config): for pair in _create_pairs(config):
single_pair_trades = STRATEGY.run_pair(pair=pair, config=CONFIG, bt_result=bt_result) single_pair_trades = strategy.run_pair(
pair=pair, config=config, bt_result=bt_result
)
if single_pair_trades is not None and len(single_pair_trades) > 0: if single_pair_trades is not None and len(single_pair_trades) > 0:
pairs_trades.append(single_pair_trades) pairs_trades.append(single_pair_trades)
# Check if result_list has any data before concatenating # Check if result_list has any data before concatenating
@ -149,12 +62,24 @@ def run_all_pairs(config: Dict, datafile: str, price_column: str, bt_result: Bac
def main() -> None: def main() -> None:
parser = argparse.ArgumentParser(description="Run pairs trading backtest.")
parser.add_argument(
"--config", type=str, required=True, help="Path to the configuration file."
)
args = parser.parse_args()
CONFIG = load_config(args.config)
# Dynamically instantiate strategy class
strategy_class_name = CONFIG.get("strategy_class", "strategies.StaticFitStrategy")
module_name, class_name = strategy_class_name.rsplit(".", 1)
module = importlib.import_module(module_name)
STRATEGY = getattr(module, class_name)()
# Initialize a dictionary to store all trade results # Initialize a dictionary to store all trade results
all_results: Dict[str, Dict[str, Any]] = {} all_results: Dict[str, Dict[str, Any]] = {}
bt_results = BacktestResult(config=CONFIG) bt_results = BacktestResult(config=CONFIG)
# Initialize global PnL tracking variables
# Process each data file # Process each data file
price_column = CONFIG["price_column"] price_column = CONFIG["price_column"]
for datafile in CONFIG["datafiles"]: for datafile in CONFIG["datafiles"]:
@ -166,7 +91,11 @@ def main() -> None:
# Process data for this file # Process data for this file
try: try:
run_all_pairs( run_all_pairs(
config=CONFIG, datafile=datafile, price_column=price_column, bt_result=bt_results config=CONFIG,
datafile=datafile,
price_column=price_column,
bt_result=bt_results,
strategy=STRATEGY,
) )
# Store results with file name as key # Store results with file name as key
@ -175,17 +104,14 @@ def main() -> None:
print(f"Successfully processed {filename}") print(f"Successfully processed {filename}")
# No longer printing unrealized PnL since we removed that functionality
except Exception as e: except Exception as e:
print(f"Error processing {datafile}: {str(e)}") print(f"Error processing {datafile}: {str(e)}")
# BacktestResults.print_results_summary(all_results) # Calculate and print results
bt_results.calculate_returns(all_results) bt_results.calculate_returns(all_results)
# Print grand totals
bt_results.print_grand_totals() bt_results.print_grand_totals()
bt_results.print_outstanding_positions() bt_results.print_outstanding_positions()
if __name__ == "__main__": if __name__ == "__main__":
main() main()