updating for pulling
This commit is contained in:
@@ -115,3 +115,4 @@
|
||||
2025-04-12 18:44:42,777 - WARNING - You are saving your model as an HDF5 file via `model.save()` or `keras.saving.save_model(model)`. This file format is considered legacy. We recommend using instead the native Keras format, e.g. `model.save('my_model.keras')` or `keras.saving.save_model(model, 'my_model.keras')`.
|
||||
2025-04-12 18:44:42,811 - INFO - Saved best LSTM model and scaler objects.
|
||||
2025-04-12 18:44:42,875 - INFO - Starting PPO training...
|
||||
2025-04-12 21:00:16,687 - INFO - PPO training completed and model saved.
|
||||
|
||||
Binary file not shown.
205
src/MidasHL/README.md
Normal file
205
src/MidasHL/README.md
Normal file
@@ -0,0 +1,205 @@
|
||||
# MidasHL
|
||||
|
||||
Hierarchical Learning for Live /MES Futures Trading
|
||||
A modular, production‑grade trading system combining an LSTM forecaster and a PPO trading agent. Designed for 5‑minute `/MES` futures trading with advanced risk management and easy extensibility.
|
||||
|
||||
---
|
||||
|
||||
## Features
|
||||
|
||||
- **Hierarchical AI Architecture**
|
||||
- **LSTM Forecaster** for short‑term price prediction (bidirectional layers, dropout, L2 regularization)
|
||||
- **PPO Trading Agent** for decision making in a custom Gym environment
|
||||
- **Risk Management**: ATR‑based trailing stops, 2:1 risk/reward filter
|
||||
- **Highly Modular**
|
||||
- Clear separation of concerns: data loading, indicators, preprocessing, modeling, trading, execution, API, logging, resource monitoring
|
||||
- **Multi‑Format Data Support**
|
||||
- CSV & JSON loaders with robust error handling and column standardization
|
||||
- **Performance‑Critical C Module**
|
||||
- Fast ATR computation via a Python C‑extension (`fast_indicators`)
|
||||
- **API Layer**
|
||||
- Flask endpoints to initialize models and generate trade signals
|
||||
- **Backtesting & Live Modes**
|
||||
- Run full backtests, train models, or integrate live trading (placeholder for IBKR API)
|
||||
|
||||
---
|
||||
|
||||
## Directory Structure
|
||||
|
||||
```
|
||||
FuturesTradingAI/
|
||||
├── README.md
|
||||
├── setup.py
|
||||
├── requirements.txt
|
||||
├── data/
|
||||
│ └── sample_data.csv # Example data
|
||||
├── src/
|
||||
│ ├── config.py # Central settings & hyperparameters
|
||||
│ ├── main.py # CLI entry point
|
||||
│ ├── data/
|
||||
│ │ ├── loader.py # CSV/JSON loader & renaming
|
||||
│ │ ├── technical_indicators.py
|
||||
│ │ └── preprocessing.py
|
||||
│ ├── models/
|
||||
│ │ ├── lstm_forecaster.py
|
||||
│ │ ├── ppo_trader.py
|
||||
│ │ └── hierarchical.py
|
||||
│ ├── trading/
|
||||
│ │ ├── env.py
|
||||
│ │ ├── execution.py
|
||||
│ │ └── risk_manager.py
|
||||
│ ├── api/
|
||||
│ │ └── api_ai.py
|
||||
│ └── utils/
|
||||
│ ├── logger.py
|
||||
│ └── resource_monitor.py
|
||||
├── src/c_modules/
|
||||
│ ├── fast_indicators.c # ATR C‑extension
|
||||
│ └── setup_fast_indicators.py
|
||||
├── tests/ # Unit tests
|
||||
├── examples/ # Example backtest/live scripts
|
||||
└── output/ # Generated models, logs, and reports
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ⚙️ Installation
|
||||
|
||||
1. **Clone the repo**
|
||||
```bash
|
||||
git clone https://github.com/YourOrg/FuturesTradingAI.git
|
||||
cd FuturesTradingAI
|
||||
```
|
||||
|
||||
2. **Create a virtual environment**
|
||||
```bash
|
||||
python3 -m venv venv
|
||||
source venv/bin/activate
|
||||
```
|
||||
|
||||
3. **Install Python dependencies**
|
||||
```bash
|
||||
pip install --upgrade pip
|
||||
pip install -r requirements.txt
|
||||
```
|
||||
|
||||
4. **Build the C‑extension (optional)**
|
||||
```bash
|
||||
cd src/c_modules
|
||||
python setup_fast_indicators.py build_ext --inplace
|
||||
cd ../..
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 💻 Usage
|
||||
|
||||
All commands assume you are in the project root with `venv` activated.
|
||||
|
||||
### 1. Training
|
||||
|
||||
Train both LSTM and PPO models on your historical data:
|
||||
|
||||
```bash
|
||||
python -m src.main \
|
||||
--mode train \
|
||||
--data path/to/your_data.csv
|
||||
```
|
||||
|
||||
- Models and scalers will be saved into `output/models/`
|
||||
|
||||
### 2. Backtesting
|
||||
|
||||
Run a backtest over historical data:
|
||||
|
||||
```bash
|
||||
python -m src.main \
|
||||
--mode backtest \
|
||||
--data path/to/your_data.csv
|
||||
```
|
||||
|
||||
- Prints total reward, number of trades, average reward, etc.
|
||||
|
||||
### 3. Live Trading (Simulation)
|
||||
|
||||
Placeholder for live trading loop (integration with IBKR API required):
|
||||
|
||||
```bash
|
||||
python -m src.main \
|
||||
--mode live \
|
||||
--data path/to/your_data.csv
|
||||
```
|
||||
|
||||
- Uses `FuturesTradingEnv` and `HierarchicalTrader.live_trading()`
|
||||
|
||||
---
|
||||
|
||||
## 📡 API Endpoints
|
||||
|
||||
Start the Flask server:
|
||||
|
||||
```bash
|
||||
python src/api/api_ai.py
|
||||
```
|
||||
|
||||
1. **Initialize Models**
|
||||
`POST /initialize`
|
||||
```json
|
||||
{
|
||||
"data_path": "data/your_data.csv",
|
||||
"lstm_model_path": "output/models/lstm_forecaster.keras",
|
||||
"ppo_model_path": "output/models/ppo_trader.zip"
|
||||
}
|
||||
```
|
||||
|
||||
2. **Get Trade Signal**
|
||||
`POST /trade_signal`
|
||||
```json
|
||||
{
|
||||
"observation": [ /* numeric vector matching env.observation_space */ ]
|
||||
}
|
||||
```
|
||||
Returns:
|
||||
```json
|
||||
{ "trade_signal": 1 }
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🧪 Testing
|
||||
|
||||
Run unit tests with:
|
||||
|
||||
```bash
|
||||
pytest tests/
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔧 Configuration
|
||||
|
||||
All hyperparameters and paths are in `src/config.py`. Key sections:
|
||||
|
||||
- **LSTM_PARAMS**
|
||||
- **PPO_PARAMS**
|
||||
- **TRADING_ENV_CONFIG**
|
||||
- **API_CONFIG**
|
||||
- **LOGGING_CONFIG**
|
||||
- **MONITOR_CONFIG**
|
||||
|
||||
---
|
||||
|
||||
## 🔜 Next Steps
|
||||
|
||||
- **IBKR Integration**:
|
||||
- Install `ibjts` package and configure `execution.py` to send orders.
|
||||
- Wire live market data feed into `FuturesTradingEnv.get_live_market_data()`.
|
||||
|
||||
- **Enhanced Backtests**:
|
||||
- Extend `HierarchicalTrader.backtest()` to log per‑trade metrics and equity curves.
|
||||
|
||||
- **Parameter Tuning**:
|
||||
- Leverage Optuna across both LSTM and PPO for automated hyperparameter search.
|
||||
|
||||
---
|
||||
|
||||
3
src/MidasHL/TODO.txt
Normal file
3
src/MidasHL/TODO.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
Objectives:
|
||||
1. We need the live bot to run the backtest on only the 10 most recent bars, and then every 5 minutes run the backtest on the
|
||||
newest bar,
|
||||
Binary file not shown.
61
src/MidasHL/examples/run_backtest_test.py
Normal file
61
src/MidasHL/examples/run_backtest_test.py
Normal file
@@ -0,0 +1,61 @@
|
||||
#!/usr/bin/env python
|
||||
"""
|
||||
examples/run_backtest.py
|
||||
|
||||
Script to run a backtesting simulation for FuturesTradingAI.
|
||||
This script loads CSV historical data, computes technical indicators,
|
||||
preprocesses the data, instantiates the hierarchical trader, and runs backtesting.
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import logging
|
||||
import pandas as pd
|
||||
|
||||
from src.data.loader import load_data
|
||||
from src.data.technical_indicators import calculate_all_indicators
|
||||
from src.data.preprocessing import preprocess_data
|
||||
from src.models.hierarchialtrader import HierarchicalTrader
|
||||
from src.utils.logger import setup_logging
|
||||
|
||||
def main():
|
||||
# Parse command-line arguments.
|
||||
parser = argparse.ArgumentParser(description="Run backtesting simulation for FuturesTradingAI")
|
||||
parser.add_argument("--data", type=str, required=True, help="Path to CSV data file for backtesting")
|
||||
args = parser.parse_args()
|
||||
|
||||
# Set up logging to output both to file and console.
|
||||
log_dir = os.path.join(os.getcwd(), "logs")
|
||||
setup_logging(log_dir)
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# Load the historical data.
|
||||
try:
|
||||
df = load_data(args.data)
|
||||
except Exception as e:
|
||||
logger.error(f"Error loading data from {args.data}: {e}")
|
||||
return
|
||||
|
||||
# Calculate technical indicators and preprocess data.
|
||||
try:
|
||||
df = calculate_all_indicators(df)
|
||||
df_processed = preprocess_data(df)
|
||||
except Exception as e:
|
||||
logger.error(f"Error in indicator calculation or data preprocessing: {e}")
|
||||
return
|
||||
|
||||
# Initialize the hierarchical trader.
|
||||
# If you have trained models, load and pass them here (e.g., lstm_model, ppo_model).
|
||||
hierarchical_trader = HierarchicalTrader(data=df_processed)
|
||||
|
||||
# Run backtesting.
|
||||
try:
|
||||
results = hierarchical_trader.backtest()
|
||||
logger.info("Backtesting Results:")
|
||||
logger.info(results)
|
||||
except Exception as e:
|
||||
logger.error(f"Error during backtesting: {e}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
BIN
src/MidasHL/output/models/lstm_forecaster.h5
Normal file
BIN
src/MidasHL/output/models/lstm_forecaster.h5
Normal file
Binary file not shown.
BIN
src/MidasHL/output/models/ppo_trader.zip
Normal file
BIN
src/MidasHL/output/models/ppo_trader.zip
Normal file
Binary file not shown.
BIN
src/MidasHL/output/models/scaler_features.pkl
Normal file
BIN
src/MidasHL/output/models/scaler_features.pkl
Normal file
Binary file not shown.
BIN
src/MidasHL/output/models/scaler_target.pkl
Normal file
BIN
src/MidasHL/output/models/scaler_target.pkl
Normal file
Binary file not shown.
@@ -9,4 +9,5 @@ joblib
|
||||
flask
|
||||
psutil
|
||||
GPUtil
|
||||
shimmy
|
||||
|
||||
|
||||
0
src/MidasHL/src/__init__.py
Normal file
0
src/MidasHL/src/__init__.py
Normal file
BIN
src/MidasHL/src/__pycache__/__init__.cpython-311.pyc
Normal file
BIN
src/MidasHL/src/__pycache__/__init__.cpython-311.pyc
Normal file
Binary file not shown.
Binary file not shown.
@@ -42,7 +42,7 @@ PPO_PARAMS = {
|
||||
# Trading environment configuration
|
||||
TRADING_ENV_CONFIG = {
|
||||
'window_size': 15, # Lookback window size for LSTM forecasting
|
||||
'transaction_cost': 0.001, # Transaction cost fee as a fraction of notional
|
||||
'transaction_cost': 0.85, # Transaction cost fee as a fraction of notional
|
||||
'max_contracts': 1, # Initial max number of contracts for trading (scalable for multi‑contract trading)
|
||||
'risk_reward_threshold': 2.0, # Minimum risk/reward ratio required to execute a trade (2:1)
|
||||
'atr_period': 14, # Period for ATR calculation
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,38 +1,15 @@
|
||||
"""
|
||||
src/data/loader.py
|
||||
|
||||
This module provides functions to load and clean market data from various file types.
|
||||
It now supports both CSV and JSON files. When a file path is passed (for example,
|
||||
using the --mode testing flag), the function detects the file extension and loads
|
||||
the data with the appropriate Pandas reader.
|
||||
|
||||
The expected columns are: time, open, high, low, close, volume.
|
||||
After loading, columns are renamed for consistency and the data is sorted chronologically.
|
||||
"""
|
||||
|
||||
import pandas as pd
|
||||
import logging
|
||||
import sys
|
||||
import os
|
||||
|
||||
def load_data(file_path):
|
||||
"""
|
||||
Load market data from a specified file, supporting both CSV and JSON formats.
|
||||
|
||||
Parameters:
|
||||
- file_path (str): Path to the data file (CSV or JSON).
|
||||
|
||||
Returns:
|
||||
- pandas.DataFrame: Loaded and cleaned data with standardized column names.
|
||||
"""
|
||||
logging.info(f"Loading data from: {file_path}")
|
||||
|
||||
# Check if the file exists
|
||||
if not os.path.exists(file_path):
|
||||
logging.error(f"Data file not found: {file_path}")
|
||||
sys.exit(1)
|
||||
|
||||
# Determine file type based on extension (case-insensitive)
|
||||
|
||||
file_ext = os.path.splitext(file_path)[1].lower()
|
||||
try:
|
||||
if file_ext == '.csv':
|
||||
@@ -40,36 +17,20 @@ def load_data(file_path):
|
||||
df = pd.read_csv(file_path, parse_dates=['time'])
|
||||
elif file_ext == '.json':
|
||||
logging.info("Detected JSON file format.")
|
||||
# For JSON files, we assume a records-oriented format.
|
||||
df = pd.read_json(file_path, convert_dates=['time'])
|
||||
else:
|
||||
logging.error("Unsupported file format. Only CSV and JSON are supported.")
|
||||
sys.exit(1)
|
||||
except FileNotFoundError:
|
||||
logging.error(f"File not found: {file_path}")
|
||||
sys.exit(1)
|
||||
except pd.errors.ParserError as e:
|
||||
logging.error(f"Error parsing file: {e}")
|
||||
sys.exit(1)
|
||||
except Exception as e:
|
||||
logging.error(f"Unexpected error: {e}")
|
||||
logging.error(f"Error loading data: {e}")
|
||||
sys.exit(1)
|
||||
|
||||
# Standardize column names. Adjust this mapping if your JSON/CSV keys differ.
|
||||
rename_mapping = {
|
||||
'time': 'Date',
|
||||
'open': 'Open',
|
||||
'high': 'High',
|
||||
'low': 'Low',
|
||||
'close': 'Close',
|
||||
'volume': 'Volume'
|
||||
}
|
||||
df.rename(columns=rename_mapping, inplace=True)
|
||||
|
||||
logging.info(f"Data columns after renaming: {df.columns.tolist()}")
|
||||
df.sort_values('Date', inplace=True)
|
||||
df.reset_index(drop=True, inplace=True)
|
||||
logging.info("Data loaded and sorted successfully.")
|
||||
|
||||
return df
|
||||
|
||||
# unify to lowercase for consistency
|
||||
df.columns = df.columns.str.lower()
|
||||
|
||||
# sort by time
|
||||
df.sort_values('time', inplace=True)
|
||||
df.reset_index(drop=True, inplace=True)
|
||||
|
||||
logging.info(f"Data columns after normalization: {df.columns.tolist()}")
|
||||
return df
|
||||
|
||||
75
src/MidasHL/src/data/old_loader.py
Normal file
75
src/MidasHL/src/data/old_loader.py
Normal file
@@ -0,0 +1,75 @@
|
||||
"""
|
||||
src/data/loader.py
|
||||
|
||||
This module provides functions to load and clean market data from various file types.
|
||||
It now supports both CSV and JSON files. When a file path is passed (for example,
|
||||
using the --mode testing flag), the function detects the file extension and loads
|
||||
the data with the appropriate Pandas reader.
|
||||
|
||||
The expected columns are: time, open, high, low, close, volume.
|
||||
After loading, columns are renamed for consistency and the data is sorted chronologically.
|
||||
"""
|
||||
|
||||
import pandas as pd
|
||||
import logging
|
||||
import sys
|
||||
import os
|
||||
|
||||
def load_data(file_path):
|
||||
"""
|
||||
Load market data from a specified file, supporting both CSV and JSON formats.
|
||||
|
||||
Parameters:
|
||||
- file_path (str): Path to the data file (CSV or JSON).
|
||||
|
||||
Returns:
|
||||
- pandas.DataFrame: Loaded and cleaned data with standardized column names.
|
||||
"""
|
||||
logging.info(f"Loading data from: {file_path}")
|
||||
|
||||
# Check if the file exists
|
||||
if not os.path.exists(file_path):
|
||||
logging.error(f"Data file not found: {file_path}")
|
||||
sys.exit(1)
|
||||
|
||||
# Determine file type based on extension (case-insensitive)
|
||||
file_ext = os.path.splitext(file_path)[1].lower()
|
||||
try:
|
||||
if file_ext == '.csv':
|
||||
logging.info("Detected CSV file format.")
|
||||
df = pd.read_csv(file_path, parse_dates=['time'])
|
||||
elif file_ext == '.json':
|
||||
logging.info("Detected JSON file format.")
|
||||
# For JSON files, we assume a records-oriented format.
|
||||
df = pd.read_json(file_path, convert_dates=['time'])
|
||||
else:
|
||||
logging.error("Unsupported file format. Only CSV and JSON are supported.")
|
||||
sys.exit(1)
|
||||
except FileNotFoundError:
|
||||
logging.error(f"File not found: {file_path}")
|
||||
sys.exit(1)
|
||||
except pd.errors.ParserError as e:
|
||||
logging.error(f"Error parsing file: {e}")
|
||||
sys.exit(1)
|
||||
except Exception as e:
|
||||
logging.error(f"Unexpected error: {e}")
|
||||
sys.exit(1)
|
||||
|
||||
# Standardize column names. Adjust this mapping if your JSON/CSV keys differ.
|
||||
rename_mapping = {
|
||||
'time': 'Date',
|
||||
'open': 'Open',
|
||||
'high': 'High',
|
||||
'low': 'Low',
|
||||
'close': 'Close',
|
||||
'volume': 'Volume'
|
||||
}
|
||||
df.rename(columns=rename_mapping, inplace=True)
|
||||
|
||||
logging.info(f"Data columns after renaming: {df.columns.tolist()}")
|
||||
df.sort_values('Date', inplace=True)
|
||||
df.reset_index(drop=True, inplace=True)
|
||||
logging.info("Data loaded and sorted successfully.")
|
||||
|
||||
return df
|
||||
|
||||
64
src/MidasHL/src/data/old_preprocessing.py
Normal file
64
src/MidasHL/src/data/old_preprocessing.py
Normal file
@@ -0,0 +1,64 @@
|
||||
"""
|
||||
src/data/preprocessing.py
|
||||
|
||||
This module provides advanced data preprocessing routines, including parallel feature engineering,
|
||||
normalization, and any additional cleanup required for the trading system.
|
||||
"""
|
||||
|
||||
import pandas as pd
|
||||
import numpy as np
|
||||
import logging
|
||||
from multiprocessing import Pool, cpu_count
|
||||
|
||||
def parallel_feature_engineering(row):
|
||||
"""
|
||||
Perform feature engineering on a single row of data.
|
||||
|
||||
This can include custom transformations, creation of new features, etc.
|
||||
Currently, this is an example that adds a feature: the ratio of high to low prices.
|
||||
|
||||
Parameters:
|
||||
- row (pandas.Series): A row from the DataFrame.
|
||||
|
||||
Returns:
|
||||
- dict: A dictionary with engineered features.
|
||||
"""
|
||||
try:
|
||||
engineered = row.to_dict()
|
||||
engineered['hl_ratio'] = row['High'] / (row['Low'] + 1e-9)
|
||||
return engineered
|
||||
except Exception as e:
|
||||
logging.error(f"Error processing row for feature engineering: {e}")
|
||||
return row.to_dict()
|
||||
|
||||
def preprocess_data(df):
|
||||
"""
|
||||
Perform preprocessing on the entire DataFrame, including parallel feature engineering
|
||||
and normalization routines.
|
||||
|
||||
Parameters:
|
||||
- df (pandas.DataFrame): Input market data.
|
||||
|
||||
Returns:
|
||||
- pandas.DataFrame: Preprocessed data ready for modeling.
|
||||
"""
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
logger.info("Starting parallel feature engineering...")
|
||||
num_workers = max(1, cpu_count() - 2)
|
||||
with Pool(processes=num_workers) as pool:
|
||||
processed_data = pool.map(parallel_feature_engineering, [row for _, row in df.iterrows()])
|
||||
|
||||
df_processed = pd.DataFrame(processed_data)
|
||||
|
||||
# Normalization: Scale price‑related columns (open, high, low, close) using min‑max scaling.
|
||||
price_cols = ['Open', 'High', 'Low', 'Close']
|
||||
for col in price_cols:
|
||||
if col in df_processed.columns:
|
||||
min_val = df_processed[col].min()
|
||||
max_val = df_processed[col].max()
|
||||
df_processed[col] = (df_processed[col] - min_val) / (max_val - min_val + 1e-9)
|
||||
|
||||
logger.info("Data preprocessing and feature engineering completed.")
|
||||
return df_processed
|
||||
|
||||
214
src/MidasHL/src/data/old_technical_indicators.py
Normal file
214
src/MidasHL/src/data/old_technical_indicators.py
Normal file
@@ -0,0 +1,214 @@
|
||||
"""
|
||||
src/data/technical_indicators.py
|
||||
|
||||
This module implements a comprehensive set of technical indicators used in the trading system.
|
||||
Indicators include:
|
||||
- RSI (Relative Strength Index)
|
||||
- MACD (Moving Average Convergence Divergence)
|
||||
- OBV (On-Balance Volume)
|
||||
- ADX (Average Directional Index)
|
||||
- Bollinger Bands
|
||||
- MFI (Money Flow Index)
|
||||
- ATR (Average True Range) for trailing stop calculations
|
||||
"""
|
||||
|
||||
import pandas as pd
|
||||
import numpy as np
|
||||
|
||||
def compute_rsi(series, window=14):
|
||||
"""
|
||||
Compute Relative Strength Index (RSI).
|
||||
|
||||
Parameters:
|
||||
- series (pandas.Series): Series of prices.
|
||||
- window (int): Number of periods to use for calculation.
|
||||
|
||||
Returns:
|
||||
- pandas.Series: RSI values.
|
||||
"""
|
||||
delta = series.diff()
|
||||
gain = delta.clip(lower=0)
|
||||
loss = -delta.clip(upper=0)
|
||||
avg_gain = gain.rolling(window=window, min_periods=window).mean()
|
||||
avg_loss = loss.rolling(window=window, min_periods=window).mean()
|
||||
rs = avg_gain / (avg_loss + 1e-9)
|
||||
rsi = 100 - (100 / (1 + rs))
|
||||
return rsi
|
||||
|
||||
def compute_macd(series, span_short=12, span_long=26, span_signal=9):
|
||||
"""
|
||||
Compute MACD (Moving Average Convergence Divergence) indicator.
|
||||
|
||||
Parameters:
|
||||
- series (pandas.Series): Series of prices.
|
||||
- span_short (int): Short‑term EMA span.
|
||||
- span_long (int): Long‑term EMA span.
|
||||
- span_signal (int): Signal line EMA span.
|
||||
|
||||
Returns:
|
||||
- pandas.Series: MACD histogram values.
|
||||
"""
|
||||
ema_short = series.ewm(span=span_short, adjust=False).mean()
|
||||
ema_long = series.ewm(span=span_long, adjust=False).mean()
|
||||
macd_line = ema_short - ema_long
|
||||
signal_line = macd_line.ewm(span=span_signal, adjust=False).mean()
|
||||
macd_hist = macd_line - signal_line
|
||||
return macd_hist
|
||||
|
||||
def compute_obv(df):
|
||||
"""
|
||||
Compute On‑Balance Volume (OBV).
|
||||
|
||||
Parameters:
|
||||
- df (pandas.DataFrame): DataFrame containing 'close' and 'volume'.
|
||||
|
||||
Returns:
|
||||
- pandas.Series: OBV values.
|
||||
"""
|
||||
direction = np.sign(df['Close'].diff()).fillna(0)
|
||||
obv = (direction * df['Volume']).cumsum()
|
||||
return obv
|
||||
|
||||
def compute_adx(df, window=14):
|
||||
"""
|
||||
Compute Average Directional Index (ADX).
|
||||
|
||||
Parameters:
|
||||
- df (pandas.DataFrame): DataFrame containing 'high', 'low', and 'close'.
|
||||
- window (int): Window size for calculation.
|
||||
|
||||
Returns:
|
||||
- pandas.Series: ADX values.
|
||||
"""
|
||||
high = df['High']
|
||||
low = df['Low']
|
||||
close = df['Close']
|
||||
|
||||
tr1 = high - low
|
||||
tr2 = (high - close.shift()).abs()
|
||||
tr3 = (low - close.shift()).abs()
|
||||
tr = pd.concat([tr1, tr2, tr3], axis=1).max(axis=1)
|
||||
|
||||
atr = tr.rolling(window=window, min_periods=window).mean()
|
||||
up_move = high.diff()
|
||||
down_move = low.diff().abs()
|
||||
|
||||
plus_dm = np.where((up_move > down_move) & (up_move > 0), up_move, 0)
|
||||
minus_dm = np.where((down_move > up_move) & (down_move > 0), down_move, 0)
|
||||
|
||||
plus_di = 100 * (pd.Series(plus_dm).rolling(window=window, min_periods=window).sum() / (atr + 1e-9))
|
||||
minus_di = 100 * (pd.Series(minus_dm).rolling(window=window, min_periods=window).sum() / (atr + 1e-9))
|
||||
|
||||
dx = (abs(plus_di - minus_di) / (plus_di + minus_di + 1e-9)) * 100
|
||||
adx = dx.rolling(window=window, min_periods=window).mean()
|
||||
return adx
|
||||
|
||||
def compute_bollinger_bands(series, window=20, num_std=2):
|
||||
"""
|
||||
Compute Bollinger Bands.
|
||||
|
||||
Parameters:
|
||||
- series (pandas.Series): Series of prices.
|
||||
- window (int): Window size for moving average.
|
||||
- num_std (int): Number of standard deviations for the bands.
|
||||
|
||||
Returns:
|
||||
- tuple: Upper band, lower band, and bandwidth as pandas.Series objects.
|
||||
"""
|
||||
sma = series.rolling(window=window, min_periods=window).mean()
|
||||
std = series.rolling(window=window, min_periods=window).std()
|
||||
upper = sma + num_std * std
|
||||
lower = sma - num_std * std
|
||||
bandwidth = (upper - lower) / (sma + 1e-9)
|
||||
return upper, lower, bandwidth
|
||||
|
||||
def compute_mfi(df, window=14):
|
||||
"""
|
||||
Compute Money Flow Index (MFI).
|
||||
|
||||
Parameters:
|
||||
- df (pandas.DataFrame): DataFrame containing 'high', 'low', 'close', and 'volume'.
|
||||
- window (int): Window size for calculation.
|
||||
|
||||
Returns:
|
||||
- pandas.Series: MFI values.
|
||||
"""
|
||||
typical_price = (df['High'] + df['Low'] + df['Close']) / 3
|
||||
money_flow = typical_price * df['Volume']
|
||||
positive_flow = []
|
||||
negative_flow = []
|
||||
|
||||
for i in range(1, len(typical_price)):
|
||||
if typical_price.iloc[i] > typical_price.iloc[i-1]:
|
||||
positive_flow.append(money_flow.iloc[i])
|
||||
negative_flow.append(0)
|
||||
elif typical_price.iloc[i] < typical_price.iloc[i-1]:
|
||||
positive_flow.append(0)
|
||||
negative_flow.append(money_flow.iloc[i])
|
||||
else:
|
||||
positive_flow.append(0)
|
||||
negative_flow.append(0)
|
||||
|
||||
positive_mf = pd.Series(positive_flow).rolling(window=window, min_periods=window).sum()
|
||||
negative_mf = pd.Series(negative_flow).rolling(window=window, min_periods=window).sum()
|
||||
|
||||
mfi = 100 - (100 / (1 + (positive_mf / (negative_mf + 1e-9))))
|
||||
mfi.index = df.index[1:]
|
||||
mfi = mfi.reindex(df.index)
|
||||
return mfi
|
||||
|
||||
def compute_atr(df, period=14):
|
||||
"""
|
||||
Compute Average True Range (ATR).
|
||||
|
||||
Parameters:
|
||||
- df (pandas.DataFrame): DataFrame containing 'high', 'low', and 'close'.
|
||||
- period (int): Number of periods to use for the ATR calculation.
|
||||
|
||||
Returns:
|
||||
- pandas.Series: ATR values.
|
||||
"""
|
||||
high = df['High']
|
||||
low = df['Low']
|
||||
close = df['Close']
|
||||
|
||||
tr1 = high - low
|
||||
tr2 = (high - close.shift()).abs()
|
||||
tr3 = (low - close.shift()).abs()
|
||||
true_range = pd.concat([tr1, tr2, tr3], axis=1).max(axis=1)
|
||||
|
||||
atr = true_range.rolling(window=period, min_periods=period).mean()
|
||||
return atr
|
||||
|
||||
def calculate_all_indicators(df):
|
||||
"""
|
||||
Calculate and append all technical indicators to the DataFrame.
|
||||
|
||||
Parameters:
|
||||
- df (pandas.DataFrame): Input market data.
|
||||
|
||||
Returns:
|
||||
- pandas.DataFrame: DataFrame enriched with technical indicator columns.
|
||||
"""
|
||||
df['RSI'] = compute_rsi(df['Close'])
|
||||
df['MACD'] = compute_macd(df['Close'])
|
||||
df['OBV'] = compute_obv(df)
|
||||
df['ADX'] = compute_adx(df)
|
||||
|
||||
bollinger_upper, bollinger_lower, bollinger_bandwidth = compute_bollinger_bands(df['Close'])
|
||||
df['BB_Upper'] = bollinger_upper
|
||||
df['BB_Lower'] = bollinger_lower
|
||||
df['BB_Bandwidth'] = bollinger_bandwidth
|
||||
|
||||
df['MFI'] = compute_mfi(df)
|
||||
df['ATR'] = compute_atr(df)
|
||||
|
||||
# Additional moving averages as sample features
|
||||
df['SMA_5'] = df['Close'].rolling(window=5, min_periods=5).mean()
|
||||
df['SMA_10'] = df['Close'].rolling(window=10, min_periods=10).mean()
|
||||
|
||||
# Drop rows with NaN values resulting from indicator calculations
|
||||
df.dropna(inplace=True)
|
||||
|
||||
return df
|
||||
|
||||
@@ -1,64 +1,29 @@
|
||||
"""
|
||||
src/data/preprocessing.py
|
||||
|
||||
This module provides advanced data preprocessing routines, including parallel feature engineering,
|
||||
normalization, and any additional cleanup required for the trading system.
|
||||
"""
|
||||
|
||||
import pandas as pd
|
||||
import numpy as np
|
||||
import logging
|
||||
from multiprocessing import Pool, cpu_count
|
||||
|
||||
def parallel_feature_engineering(row):
|
||||
"""
|
||||
Perform feature engineering on a single row of data.
|
||||
|
||||
This can include custom transformations, creation of new features, etc.
|
||||
Currently, this is an example that adds a feature: the ratio of high to low prices.
|
||||
|
||||
Parameters:
|
||||
- row (pandas.Series): A row from the DataFrame.
|
||||
|
||||
Returns:
|
||||
- dict: A dictionary with engineered features.
|
||||
"""
|
||||
try:
|
||||
engineered = row.to_dict()
|
||||
engineered['hl_ratio'] = row['high'] / (row['low'] + 1e-9)
|
||||
return engineered
|
||||
except Exception as e:
|
||||
logging.error(f"Error processing row for feature engineering: {e}")
|
||||
return row.to_dict()
|
||||
|
||||
def preprocess_data(df):
|
||||
"""
|
||||
Perform preprocessing on the entire DataFrame, including parallel feature engineering
|
||||
and normalization routines.
|
||||
|
||||
Parameters:
|
||||
- df (pandas.DataFrame): Input market data.
|
||||
|
||||
Returns:
|
||||
- pandas.DataFrame: Preprocessed data ready for modeling.
|
||||
"""
|
||||
def preprocess_data(df: pd.DataFrame) -> pd.DataFrame:
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
logger.info("Starting parallel feature engineering...")
|
||||
num_workers = max(1, cpu_count() - 2)
|
||||
with Pool(processes=num_workers) as pool:
|
||||
processed_data = pool.map(parallel_feature_engineering, [row for _, row in df.iterrows()])
|
||||
|
||||
df_processed = pd.DataFrame(processed_data)
|
||||
|
||||
# Normalization: Scale price‑related columns (open, high, low, close) using min‑max scaling.
|
||||
logger.info("Starting data preprocessing...")
|
||||
|
||||
# enforce lowercase
|
||||
df = df.rename(columns=str.lower)
|
||||
|
||||
# feature: high/low ratio
|
||||
if 'high' in df.columns and 'low' in df.columns:
|
||||
df['hl_ratio'] = df['high'] / (df['low'] + 1e-9)
|
||||
else:
|
||||
df['hl_ratio'] = np.nan
|
||||
logger.warning("Columns 'high' and/or 'low' not found; 'hl_ratio' set to NaN.")
|
||||
|
||||
# min-max normalize price columns
|
||||
price_cols = ['open', 'high', 'low', 'close']
|
||||
for col in price_cols:
|
||||
if col in df_processed.columns:
|
||||
min_val = df_processed[col].min()
|
||||
max_val = df_processed[col].max()
|
||||
df_processed[col] = (df_processed[col] - min_val) / (max_val - min_val + 1e-9)
|
||||
|
||||
logger.info("Data preprocessing and feature engineering completed.")
|
||||
return df_processed
|
||||
if col in df.columns:
|
||||
mi, ma = df[col].min(), df[col].max()
|
||||
df[col] = (df[col] - mi) / (ma - mi + 1e-9)
|
||||
else:
|
||||
logger.warning(f"Column '{col}' missing; skipping normalization.")
|
||||
|
||||
logger.info("Data preprocessing completed.")
|
||||
return df
|
||||
|
||||
@@ -1,120 +1,49 @@
|
||||
"""
|
||||
src/data/technical_indicators.py
|
||||
|
||||
This module implements a comprehensive set of technical indicators used in the trading system.
|
||||
Indicators include:
|
||||
- RSI (Relative Strength Index)
|
||||
- MACD (Moving Average Convergence Divergence)
|
||||
- OBV (On-Balance Volume)
|
||||
- ADX (Average Directional Index)
|
||||
- Bollinger Bands
|
||||
- MFI (Money Flow Index)
|
||||
- ATR (Average True Range) for trailing stop calculations
|
||||
"""
|
||||
|
||||
import pandas as pd
|
||||
import numpy as np
|
||||
|
||||
def compute_rsi(series, window=14):
|
||||
"""
|
||||
Compute Relative Strength Index (RSI).
|
||||
|
||||
Parameters:
|
||||
- series (pandas.Series): Series of prices.
|
||||
- window (int): Number of periods to use for calculation.
|
||||
|
||||
Returns:
|
||||
- pandas.Series: RSI values.
|
||||
"""
|
||||
def compute_rsi(series: pd.Series, window: int = 14) -> pd.Series:
|
||||
delta = series.diff()
|
||||
gain = delta.clip(lower=0)
|
||||
loss = -delta.clip(upper=0)
|
||||
avg_gain = gain.rolling(window=window, min_periods=window).mean()
|
||||
avg_loss = loss.rolling(window=window, min_periods=window).mean()
|
||||
rs = avg_gain / (avg_loss + 1e-9)
|
||||
rsi = 100 - (100 / (1 + rs))
|
||||
return rsi
|
||||
return 100 - (100 / (1 + rs))
|
||||
|
||||
def compute_macd(series, span_short=12, span_long=26, span_signal=9):
|
||||
"""
|
||||
Compute MACD (Moving Average Convergence Divergence) indicator.
|
||||
|
||||
Parameters:
|
||||
- series (pandas.Series): Series of prices.
|
||||
- span_short (int): Short‑term EMA span.
|
||||
- span_long (int): Long‑term EMA span.
|
||||
- span_signal (int): Signal line EMA span.
|
||||
|
||||
Returns:
|
||||
- pandas.Series: MACD histogram values.
|
||||
"""
|
||||
|
||||
def compute_macd(series: pd.Series, span_short=12, span_long=26, span_signal=9) -> pd.Series:
|
||||
ema_short = series.ewm(span=span_short, adjust=False).mean()
|
||||
ema_long = series.ewm(span=span_long, adjust=False).mean()
|
||||
macd_line = ema_short - ema_long
|
||||
signal_line = macd_line.ewm(span=span_signal, adjust=False).mean()
|
||||
macd_hist = macd_line - signal_line
|
||||
return macd_hist
|
||||
signal = macd_line.ewm(span=span_signal, adjust=False).mean()
|
||||
return macd_line - signal
|
||||
|
||||
def compute_obv(df):
|
||||
"""
|
||||
Compute On‑Balance Volume (OBV).
|
||||
|
||||
Parameters:
|
||||
- df (pandas.DataFrame): DataFrame containing 'close' and 'volume'.
|
||||
|
||||
Returns:
|
||||
- pandas.Series: OBV values.
|
||||
"""
|
||||
|
||||
def compute_obv(df: pd.DataFrame) -> pd.Series:
|
||||
direction = np.sign(df['close'].diff()).fillna(0)
|
||||
obv = (direction * df['volume']).cumsum()
|
||||
return obv
|
||||
return (direction * df['volume']).cumsum()
|
||||
|
||||
def compute_adx(df, window=14):
|
||||
"""
|
||||
Compute Average Directional Index (ADX).
|
||||
|
||||
Parameters:
|
||||
- df (pandas.DataFrame): DataFrame containing 'high', 'low', and 'close'.
|
||||
- window (int): Window size for calculation.
|
||||
|
||||
Returns:
|
||||
- pandas.Series: ADX values.
|
||||
"""
|
||||
high = df['high']
|
||||
low = df['low']
|
||||
close = df['close']
|
||||
|
||||
|
||||
def compute_adx(df: pd.DataFrame, window: int = 14) -> pd.Series:
|
||||
high, low, close = df['high'], df['low'], df['close']
|
||||
tr1 = high - low
|
||||
tr2 = (high - close.shift()).abs()
|
||||
tr3 = (low - close.shift()).abs()
|
||||
tr = pd.concat([tr1, tr2, tr3], axis=1).max(axis=1)
|
||||
|
||||
atr = tr.rolling(window=window, min_periods=window).mean()
|
||||
up_move = high.diff()
|
||||
down_move = low.diff().abs()
|
||||
|
||||
plus_dm = np.where((up_move > down_move) & (up_move > 0), up_move, 0)
|
||||
minus_dm = np.where((down_move > up_move) & (down_move > 0), down_move, 0)
|
||||
|
||||
plus_di = 100 * (pd.Series(plus_dm).rolling(window=window, min_periods=window).sum() / (atr + 1e-9))
|
||||
minus_di = 100 * (pd.Series(minus_dm).rolling(window=window, min_periods=window).sum() / (atr + 1e-9))
|
||||
|
||||
dx = (abs(plus_di - minus_di) / (plus_di + minus_di + 1e-9)) * 100
|
||||
adx = dx.rolling(window=window, min_periods=window).mean()
|
||||
return adx
|
||||
|
||||
def compute_bollinger_bands(series, window=20, num_std=2):
|
||||
"""
|
||||
Compute Bollinger Bands.
|
||||
|
||||
Parameters:
|
||||
- series (pandas.Series): Series of prices.
|
||||
- window (int): Window size for moving average.
|
||||
- num_std (int): Number of standard deviations for the bands.
|
||||
|
||||
Returns:
|
||||
- tuple: Upper band, lower band, and bandwidth as pandas.Series objects.
|
||||
"""
|
||||
up = high.diff()
|
||||
down = low.diff().abs()
|
||||
plus_dm = np.where((up > down) & (up > 0), up, 0)
|
||||
minus_dm = np.where((down > up) & (down > 0), down, 0)
|
||||
plus_di = 100 * pd.Series(plus_dm).rolling(window=window, min_periods=window).sum() / (atr + 1e-9)
|
||||
minus_di = 100 * pd.Series(minus_dm).rolling(window=window, min_periods=window).sum() / (atr + 1e-9)
|
||||
|
||||
dx = (abs(plus_di - minus_di) / (plus_di + minus_di + 1e-9)) * 100
|
||||
return dx.rolling(window=window, min_periods=window).mean()
|
||||
|
||||
|
||||
def compute_bollinger_bands(series: pd.Series, window: int = 20, num_std: int = 2):
|
||||
sma = series.rolling(window=window, min_periods=window).mean()
|
||||
std = series.rolling(window=window, min_periods=window).std()
|
||||
upper = sma + num_std * std
|
||||
@@ -122,93 +51,44 @@ def compute_bollinger_bands(series, window=20, num_std=2):
|
||||
bandwidth = (upper - lower) / (sma + 1e-9)
|
||||
return upper, lower, bandwidth
|
||||
|
||||
def compute_mfi(df, window=14):
|
||||
"""
|
||||
Compute Money Flow Index (MFI).
|
||||
|
||||
Parameters:
|
||||
- df (pandas.DataFrame): DataFrame containing 'high', 'low', 'close', and 'volume'.
|
||||
- window (int): Window size for calculation.
|
||||
|
||||
Returns:
|
||||
- pandas.Series: MFI values.
|
||||
"""
|
||||
typical_price = (df['high'] + df['low'] + df['close']) / 3
|
||||
money_flow = typical_price * df['volume']
|
||||
positive_flow = []
|
||||
negative_flow = []
|
||||
|
||||
for i in range(1, len(typical_price)):
|
||||
if typical_price.iloc[i] > typical_price.iloc[i-1]:
|
||||
positive_flow.append(money_flow.iloc[i])
|
||||
negative_flow.append(0)
|
||||
elif typical_price.iloc[i] < typical_price.iloc[i-1]:
|
||||
positive_flow.append(0)
|
||||
negative_flow.append(money_flow.iloc[i])
|
||||
else:
|
||||
positive_flow.append(0)
|
||||
negative_flow.append(0)
|
||||
|
||||
positive_mf = pd.Series(positive_flow).rolling(window=window, min_periods=window).sum()
|
||||
negative_mf = pd.Series(negative_flow).rolling(window=window, min_periods=window).sum()
|
||||
|
||||
mfi = 100 - (100 / (1 + (positive_mf / (negative_mf + 1e-9))))
|
||||
mfi.index = df.index[1:]
|
||||
mfi = mfi.reindex(df.index)
|
||||
return mfi
|
||||
|
||||
def compute_atr(df, period=14):
|
||||
"""
|
||||
Compute Average True Range (ATR).
|
||||
|
||||
Parameters:
|
||||
- df (pandas.DataFrame): DataFrame containing 'high', 'low', and 'close'.
|
||||
- period (int): Number of periods to use for the ATR calculation.
|
||||
|
||||
Returns:
|
||||
- pandas.Series: ATR values.
|
||||
"""
|
||||
high = df['high']
|
||||
low = df['low']
|
||||
close = df['close']
|
||||
|
||||
def compute_mfi(df: pd.DataFrame, window: int = 14) -> pd.Series:
|
||||
tp = (df['high'] + df['low'] + df['close']) / 3
|
||||
mf = tp * df['volume']
|
||||
pos_flow, neg_flow = [], []
|
||||
for i in range(1, len(tp)):
|
||||
if tp.iat[i] > tp.iat[i-1]:
|
||||
pos_flow.append(mf.iat[i]); neg_flow.append(0)
|
||||
elif tp.iat[i] < tp.iat[i-1]:
|
||||
pos_flow.append(0); neg_flow.append(mf.iat[i])
|
||||
else:
|
||||
pos_flow.append(0); neg_flow.append(0)
|
||||
pos_mf = pd.Series(pos_flow).rolling(window=window, min_periods=window).sum()
|
||||
neg_mf = pd.Series(neg_flow).rolling(window=window, min_periods=window).sum()
|
||||
mfi = 100 - (100 / (1 + (pos_mf / (neg_mf + 1e-9))))
|
||||
mfi.index = df.index[1:]
|
||||
return mfi.reindex(df.index)
|
||||
|
||||
|
||||
def compute_atr(df: pd.DataFrame, period: int = 14) -> pd.Series:
|
||||
high, low, close = df['high'], df['low'], df['close']
|
||||
tr1 = high - low
|
||||
tr2 = (high - close.shift()).abs()
|
||||
tr3 = (low - close.shift()).abs()
|
||||
true_range = pd.concat([tr1, tr2, tr3], axis=1).max(axis=1)
|
||||
|
||||
atr = true_range.rolling(window=period, min_periods=period).mean()
|
||||
return atr
|
||||
tr = pd.concat([tr1, tr2, tr3], axis=1).max(axis=1)
|
||||
return tr.rolling(window=period, min_periods=period).mean()
|
||||
|
||||
def calculate_all_indicators(df):
|
||||
"""
|
||||
Calculate and append all technical indicators to the DataFrame.
|
||||
|
||||
Parameters:
|
||||
- df (pandas.DataFrame): Input market data.
|
||||
|
||||
Returns:
|
||||
- pandas.DataFrame: DataFrame enriched with technical indicator columns.
|
||||
"""
|
||||
df['RSI'] = compute_rsi(df['close'])
|
||||
df['MACD'] = compute_macd(df['close'])
|
||||
df['OBV'] = compute_obv(df)
|
||||
df['ADX'] = compute_adx(df)
|
||||
|
||||
bollinger_upper, bollinger_lower, bollinger_bandwidth = compute_bollinger_bands(df['close'])
|
||||
df['BB_Upper'] = bollinger_upper
|
||||
df['BB_Lower'] = bollinger_lower
|
||||
df['BB_Bandwidth'] = bollinger_bandwidth
|
||||
|
||||
df['MFI'] = compute_mfi(df)
|
||||
df['ATR'] = compute_atr(df)
|
||||
|
||||
# Additional moving averages as sample features
|
||||
df['SMA_5'] = df['close'].rolling(window=5, min_periods=5).mean()
|
||||
df['SMA_10'] = df['close'].rolling(window=10, min_periods=10).mean()
|
||||
|
||||
# Drop rows with NaN values resulting from indicator calculations
|
||||
|
||||
def calculate_all_indicators(df: pd.DataFrame) -> pd.DataFrame:
|
||||
df['rsi'] = compute_rsi(df['close'])
|
||||
df['macd'] = compute_macd(df['close'])
|
||||
df['obv'] = compute_obv(df)
|
||||
df['adx'] = compute_adx(df)
|
||||
ub, lb, bw = compute_bollinger_bands(df['close'])
|
||||
df['bb_upper'], df['bb_lower'], df['bb_bandwidth'] = ub, lb, bw
|
||||
df['mfi'] = compute_mfi(df)
|
||||
df['atr'] = compute_atr(df)
|
||||
df['sma_5'] = df['close'].rolling(window=5, min_periods=5).mean()
|
||||
df['sma_10'] = df['close'].rolling(window=10, min_periods=10).mean()
|
||||
df.dropna(inplace=True)
|
||||
|
||||
return df
|
||||
|
||||
|
||||
@@ -1,16 +1,11 @@
|
||||
"""
|
||||
src/main.py
|
||||
|
||||
Main entry point for the FuturesTradingAI application.
|
||||
This script parses command‑line arguments, sets up logging, loads configurations,
|
||||
initializes data processing, model training, and can start the live trading loop or backtesting.
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import logging
|
||||
import threading
|
||||
|
||||
from tensorflow.keras.models import load_model
|
||||
import joblib
|
||||
|
||||
from src.config import SAMPLE_DATA_PATH, OUTPUT_DIR, MODEL_DIR, LOG_DIR, MONITOR_CONFIG
|
||||
from src.utils.logger import setup_logging
|
||||
from src.data.loader import load_data
|
||||
@@ -22,83 +17,93 @@ from src.models.hierarchical import HierarchicalTrader
|
||||
from src.trading.env import FuturesTradingEnv
|
||||
from src.utils.resource_monitor import start_resource_monitor
|
||||
|
||||
|
||||
def parse_args():
|
||||
"""
|
||||
Parse command‑line arguments.
|
||||
"""
|
||||
parser = argparse.ArgumentParser(
|
||||
description="FuturesTradingAI - Hierarchical Learning for Live /MES Futures Trading"
|
||||
)
|
||||
parser.add_argument("--data", type=str, default=SAMPLE_DATA_PATH, help="Path to input CSV data file")
|
||||
parser.add_argument(
|
||||
"--mode", type=str, choices=["train", "backtest", "live"], default="train",
|
||||
help="Mode to run: train for model training, backtest for historical simulation, live for live trading"
|
||||
"--data", type=str, default=SAMPLE_DATA_PATH,
|
||||
help="Path to input CSV or JSON data file"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--mode", type=str,
|
||||
choices=["train", "backtest", "live"],
|
||||
default="train",
|
||||
help="Mode to run: 'train' for model training, 'backtest' for historical simulation, 'live' for live trading"
|
||||
)
|
||||
return parser.parse_args()
|
||||
|
||||
|
||||
def main():
|
||||
# Parse command‑line arguments
|
||||
args = parse_args()
|
||||
|
||||
# Ensure necessary output directories exist
|
||||
os.makedirs(OUTPUT_DIR, exist_ok=True)
|
||||
os.makedirs(MODEL_DIR, exist_ok=True)
|
||||
os.makedirs(LOG_DIR, exist_ok=True)
|
||||
|
||||
# Setup logging configuration
|
||||
|
||||
setup_logging(LOG_DIR)
|
||||
logger = logging.getLogger(__name__)
|
||||
logger.info("Starting FuturesTradingAI application...")
|
||||
|
||||
# Optionally start system resource monitoring in a separate thread
|
||||
monitor_thread = threading.Thread(target=start_resource_monitor, args=(MONITOR_CONFIG['interval'],), daemon=True)
|
||||
|
||||
# start resource monitor
|
||||
monitor_thread = threading.Thread(
|
||||
target=start_resource_monitor,
|
||||
args=(MONITOR_CONFIG['interval'],),
|
||||
daemon=True
|
||||
)
|
||||
monitor_thread.start()
|
||||
|
||||
# Load historical market data
|
||||
|
||||
# load & prepare data
|
||||
logger.info(f"Loading data from {args.data}...")
|
||||
df = load_data(args.data)
|
||||
|
||||
# Calculate technical indicators (RSI, MACD, OBV, ADX, Bollinger Bands, MFI, ATR, etc.)
|
||||
logger.info("Calculating technical indicators on dataset...")
|
||||
logger.info("Calculating technical indicators...")
|
||||
df = calculate_all_indicators(df)
|
||||
|
||||
# Advanced data preprocessing and feature engineering
|
||||
logger.info("Preprocessing data...")
|
||||
df_processed = preprocess_data(df)
|
||||
|
||||
# Depending on mode, run training, backtesting or live trading
|
||||
df_processed.columns = df_processed.columns.str.lower()
|
||||
|
||||
if args.mode == "train":
|
||||
# Train LSTM forecaster
|
||||
logger.info("Initializing LSTM forecaster...")
|
||||
lstm_forecaster = LSTMForecaster(data=df_processed)
|
||||
lstm_forecaster.train()
|
||||
|
||||
# Train PPO trading agent using custom environment
|
||||
|
||||
# Train PPO trading agent
|
||||
logger.info("Initializing PPO trader...")
|
||||
ppo_trader = PPOTrader(data=df_processed, lstm_model=lstm_forecaster.model)
|
||||
ppo_trader.train()
|
||||
|
||||
|
||||
# Save models
|
||||
lstm_forecaster.save(MODEL_DIR)
|
||||
ppo_trader.save(MODEL_DIR)
|
||||
|
||||
|
||||
elif args.mode == "backtest":
|
||||
# Perform backtesting using hierarchical integration
|
||||
logger.info("Running backtesting simulation...")
|
||||
hierarchical_trader = HierarchicalTrader(data=df_processed)
|
||||
results = hierarchical_trader.backtest()
|
||||
logger.info("Backtest completed. Results:")
|
||||
logger.info(results)
|
||||
|
||||
logger.info("Running backtest...")
|
||||
lstm_path = os.path.join(MODEL_DIR, 'lstm_forecaster.h5')
|
||||
feat_p = os.path.join(MODEL_DIR, 'scaler_features.pkl')
|
||||
targ_p = os.path.join(MODEL_DIR, 'scaler_target.pkl')
|
||||
logger.info(f"Loading LSTM model from {lstm_path}")
|
||||
lstm = LSTMForecaster(data=df_processed)
|
||||
lstm.model = load_model(lstm_path, compile=False)
|
||||
lstm.scaler_features = joblib.load(feat_p)
|
||||
lstm.scaler_target = joblib.load(targ_p)
|
||||
|
||||
logger.info("Loading PPO trader model...")
|
||||
ppo = PPOTrader(data=df_processed, lstm_model=lstm)
|
||||
ppo.load(os.path.join(MODEL_DIR, 'ppo_trader.zip'))
|
||||
|
||||
hier = HierarchicalTrader(data=df_processed, lstm_model=lstm, ppo_model=ppo.model)
|
||||
results = hier.backtest()
|
||||
logger.info(f"Backtest results: {results}")
|
||||
|
||||
elif args.mode == "live":
|
||||
# Initiate live trading simulation
|
||||
logger.info("Starting live trading simulation...")
|
||||
env = FuturesTradingEnv(data=df_processed)
|
||||
hierarchical_trader = HierarchicalTrader(data=df_processed, env=env)
|
||||
hierarchical_trader.live_trading()
|
||||
|
||||
logger.info("FuturesTradingAI application finished.")
|
||||
live_trader = HierarchicalTrader(data=df_processed, env=env)
|
||||
live_trader.live_trading()
|
||||
|
||||
if __name__ == "__main__":
|
||||
logger.info("Application finished.")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
||||
|
||||
0
src/MidasHL/src/models/__init__.py
Normal file
0
src/MidasHL/src/models/__init__.py
Normal file
BIN
src/MidasHL/src/models/__pycache__/__init__.cpython-311.pyc
Normal file
BIN
src/MidasHL/src/models/__pycache__/__init__.cpython-311.pyc
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,145 +1,90 @@
|
||||
"""
|
||||
src/models/hierarchical.py
|
||||
|
||||
This module integrates the LSTM forecaster and the PPO trading agent to form a hierarchical decision‑making system.
|
||||
It fuses short‑term price forecasts with trading signals and enforces risk management constraints before executing trades.
|
||||
"""
|
||||
# src/models/hierarchical.py
|
||||
|
||||
import logging
|
||||
import numpy as np
|
||||
|
||||
class HierarchicalTrader:
|
||||
"""
|
||||
HierarchicalTrader integrates the outputs from the LSTM forecaster and PPO agent,
|
||||
applies risk management filters, and simulates trade execution.
|
||||
HierarchicalTrader integrates LSTM forecasts with PPO signals,
|
||||
applies risk management, and simulates or executes trades.
|
||||
"""
|
||||
def __init__(self, data, lstm_model=None, ppo_model=None, env=None, risk_reward_threshold=2.0):
|
||||
"""
|
||||
Initialize HierarchicalTrader.
|
||||
|
||||
Parameters:
|
||||
- data (pandas.DataFrame): Preprocessed market data.
|
||||
- lstm_model: Pre‑trained LSTM model for forecasting.
|
||||
- ppo_model: Trained PPO model for trading decisions.
|
||||
- env: Trading environment.
|
||||
- risk_reward_threshold (float): Minimum risk/reward ratio required to execute trades.
|
||||
"""
|
||||
self.logger = logging.getLogger(__name__)
|
||||
self.data = data
|
||||
self.lstm_model = lstm_model
|
||||
self.ppo_model = ppo_model
|
||||
self.env = env
|
||||
self.risk_reward_threshold = risk_reward_threshold
|
||||
|
||||
|
||||
def assess_risk_reward(self, current_price, forecast, atr, current_position):
|
||||
"""
|
||||
Assess risk/reward ratio based on current price, forecast, ATR, and position.
|
||||
|
||||
Parameters:
|
||||
- current_price (float): Current market price.
|
||||
- forecast (float): Forecasted price change (as a ratio).
|
||||
- atr (float): Current ATR value.
|
||||
- current_position (int): Number of contracts held.
|
||||
|
||||
Returns:
|
||||
- risk_reward (float): Calculated risk/reward ratio.
|
||||
"""
|
||||
expected_price = current_price * (1 + forecast)
|
||||
reward = abs(expected_price - current_price)
|
||||
risk = atr
|
||||
risk_reward = reward / (risk + 1e-9)
|
||||
return risk_reward
|
||||
|
||||
return reward / (risk + 1e-9)
|
||||
|
||||
def generate_trade_signal(self, observation):
|
||||
"""
|
||||
Generate a trade signal by combining PPO agent output and LSTM forecast.
|
||||
Applies risk/reward filtering.
|
||||
|
||||
Parameters:
|
||||
- observation: Current state from the trading environment.
|
||||
|
||||
Returns:
|
||||
- signal (int): Trade signal (e.g., number of contracts to buy/sell), or 0 for no action.
|
||||
"""
|
||||
# Assume observation consists of technical indicators, normalized position, and forecast (last element)
|
||||
current_forecast = observation[-1]
|
||||
current_position = observation[-2]
|
||||
|
||||
# Ensure correct dtype (float32) and shape ([1, obs_dim])
|
||||
obs = np.array(observation, dtype=np.float32).reshape(1, -1)
|
||||
|
||||
if self.ppo_model is None:
|
||||
self.logger.error("PPO model not provided for hierarchical trading.")
|
||||
return 0
|
||||
|
||||
action, _ = self.ppo_model.predict(observation, deterministic=True)
|
||||
trade_signal = int(action) if isinstance(action, (int, np.integer)) else int(round(float(action)))
|
||||
|
||||
# For simplicity, we simulate current price and ATR extraction; in practice, these come from the environment.
|
||||
current_price = 1.0 # Placeholder
|
||||
atr = 0.01 # Placeholder
|
||||
|
||||
|
||||
action, _ = self.ppo_model.predict(obs, deterministic=True)
|
||||
# Unwrap action array if needed
|
||||
trade_signal = int(action[0]) if hasattr(action, '__len__') else int(action)
|
||||
|
||||
# Extract forecast and position
|
||||
current_forecast = float(obs[0, -1])
|
||||
current_position = float(obs[0, -2])
|
||||
|
||||
# Get live price and ATR from env or fallback
|
||||
if self.env is not None:
|
||||
idx = self.env.current_step
|
||||
current_price = float(self.data.at[idx, 'close'])
|
||||
atr = float(self.data.at[idx, 'atr']) if 'atr' in self.data.columns else 0.01
|
||||
else:
|
||||
current_price, atr = 1.0, 0.01
|
||||
|
||||
rr_ratio = self.assess_risk_reward(current_price, current_forecast, atr, current_position)
|
||||
self.logger.info(f"Calculated risk/reward ratio: {rr_ratio:.2f}")
|
||||
|
||||
|
||||
if rr_ratio < self.risk_reward_threshold:
|
||||
self.logger.info("Risk/Reward ratio below threshold. No trade executed.")
|
||||
return 0
|
||||
|
||||
|
||||
self.logger.info(f"Trade signal generated: {trade_signal}")
|
||||
return trade_signal
|
||||
|
||||
|
||||
def _create_observation(self, row):
|
||||
# Drop time, date, and target 'close'
|
||||
drop_cols = [c for c in row.index if c.lower() in ('time', 'date', 'close')]
|
||||
tech = row.drop(labels=drop_cols).values.astype(np.float32)
|
||||
pos = np.array([0.0], dtype=np.float32)
|
||||
forecast = np.array([0.001], dtype=np.float32)
|
||||
return np.concatenate([tech, pos, forecast])
|
||||
|
||||
def backtest(self):
|
||||
"""
|
||||
Perform backtesting simulation over historical data using hierarchical decision making.
|
||||
|
||||
Returns:
|
||||
- dict: Backtesting results (e.g., total PnL, win rate).
|
||||
"""
|
||||
self.logger.info("Starting backtest simulation...")
|
||||
total_reward = 0.0
|
||||
num_trades = 0
|
||||
for idx, row in self.data.iterrows():
|
||||
observation = self._create_observation(row)
|
||||
signal = self.generate_trade_signal(observation)
|
||||
reward = signal * 0.001 # Simplified reward calculation
|
||||
total_reward, num_trades = 0.0, 0
|
||||
for _, row in self.data.iterrows():
|
||||
obs = self._create_observation(row)
|
||||
signal = self.generate_trade_signal(obs)
|
||||
reward = signal * 0.001
|
||||
total_reward += reward
|
||||
if signal != 0:
|
||||
num_trades += 1
|
||||
results = {
|
||||
return {
|
||||
'total_reward': total_reward,
|
||||
'num_trades': num_trades,
|
||||
'average_reward': total_reward / (num_trades + 1e-9)
|
||||
}
|
||||
self.logger.info("Backtest simulation completed.")
|
||||
return results
|
||||
|
||||
def _create_observation(self, row):
|
||||
"""
|
||||
Create a synthetic observation vector from a data row.
|
||||
In a full implementation, this should mirror the environment's observation space.
|
||||
|
||||
Parameters:
|
||||
- row (pandas.Series): A row from the historical dataset.
|
||||
|
||||
Returns:
|
||||
- numpy.array: Observation vector.
|
||||
"""
|
||||
tech_indicators = row.drop(labels=['time', 'close']).values
|
||||
normalized_position = np.array([0.0])
|
||||
forecast = np.array([0.001]) # Placeholder forecast value
|
||||
|
||||
observation = np.concatenate([tech_indicators, normalized_position, forecast])
|
||||
return observation
|
||||
|
||||
|
||||
def live_trading(self):
|
||||
"""
|
||||
Simulate live trading by continuously generating trade signals.
|
||||
This function is a placeholder for integrating with live market data and execution systems.
|
||||
"""
|
||||
self.logger.info("Starting live trading simulation...")
|
||||
import time
|
||||
while True:
|
||||
observation = self._create_observation(self.data.iloc[-1])
|
||||
signal = self.generate_trade_signal(observation)
|
||||
obs = self._create_observation(self.data.iloc[-1])
|
||||
signal = self.generate_trade_signal(obs)
|
||||
self.logger.info(f"Live trade signal: {signal}")
|
||||
# In production, signal triggers execution via the execution module.
|
||||
time.sleep(5) # Simulate 5‑minute reevaluation in a live setting.
|
||||
|
||||
time.sleep(5)
|
||||
|
||||
@@ -19,45 +19,42 @@ from sklearn.preprocessing import MinMaxScaler
|
||||
import optuna
|
||||
|
||||
class LSTMForecaster:
|
||||
"""
|
||||
LSTMForecaster builds, trains, and evaluates an LSTM model for price forecasting.
|
||||
"""
|
||||
def __init__(self, data, window_size=15, model_save_path=None, hyperparams=None):
|
||||
"""
|
||||
Initialize the LSTMForecaster.
|
||||
|
||||
Parameters:
|
||||
- data (pandas.DataFrame): Preprocessed market data with technical indicators.
|
||||
- window_size (int): The number of time steps in the input sequence.
|
||||
- model_save_path (str): Directory path where the model will be saved.
|
||||
- hyperparams (dict): Dictionary of hyperparameters (optional).
|
||||
"""
|
||||
self.logger = logging.getLogger(__name__)
|
||||
|
||||
# 1) Normalize column names to lowercase (just in case)
|
||||
data.columns = data.columns.str.lower()
|
||||
# -> ['time','open','high','low','close','volume', ... other indicators ...]
|
||||
|
||||
self.data = data.copy()
|
||||
self.window_size = window_size
|
||||
self.model_save_path = model_save_path if model_save_path else os.getcwd()
|
||||
self.model_save_path = model_save_path or os.getcwd()
|
||||
self.hyperparams = hyperparams
|
||||
|
||||
# Define target column and feature columns. Here we assume 'close' is the target.
|
||||
|
||||
# 2) Define target and feature columns
|
||||
self.target_column = 'close'
|
||||
self.feature_columns = [col for col in data.columns if col not in [self.target_column, 'time']]
|
||||
|
||||
# Initialize scalers for features and target
|
||||
# drop both 'time' and 'close' from features
|
||||
self.feature_columns = [
|
||||
col for col in self.data.columns
|
||||
if col not in [self.target_column, 'time']
|
||||
]
|
||||
|
||||
# 3) Scalers
|
||||
self.scaler_features = MinMaxScaler()
|
||||
self.scaler_target = MinMaxScaler()
|
||||
|
||||
# Prepare training sequences
|
||||
self.scaler_target = MinMaxScaler()
|
||||
|
||||
# 4) Create sequences
|
||||
self.X, self.y = self._create_sequences()
|
||||
|
||||
# Build model based on hyperparameters or default settings
|
||||
|
||||
# 5) Build & compile
|
||||
if self.hyperparams is None:
|
||||
self.hyperparams = {
|
||||
'num_layers': 2,
|
||||
'units': 64,
|
||||
'dropout_rate': 0.2,
|
||||
'num_layers': 2,
|
||||
'units': 64,
|
||||
'dropout_rate': 0.2,
|
||||
'learning_rate': 1e-3,
|
||||
'optimizer': 'Adam',
|
||||
'l2_reg': 1e-4
|
||||
'optimizer': 'Adam',
|
||||
'l2_reg': 1e-4
|
||||
}
|
||||
self.model = self._build_model()
|
||||
|
||||
|
||||
163
src/MidasHL/src/models/old_hierarchial.py
Normal file
163
src/MidasHL/src/models/old_hierarchial.py
Normal file
@@ -0,0 +1,163 @@
|
||||
"""
|
||||
src/models/hierarchical.py
|
||||
|
||||
This module integrates the LSTM forecaster and the PPO trading agent to form a hierarchical decision‑making system.
|
||||
It fuses short‑term price forecasts with trading signals and enforces risk management constraints before executing trades.
|
||||
"""
|
||||
|
||||
import logging
|
||||
import numpy as np
|
||||
|
||||
class HierarchicalTrader:
|
||||
"""
|
||||
HierarchicalTrader integrates the outputs from the LSTM forecaster and PPO agent,
|
||||
applies risk management filters, and simulates trade execution.
|
||||
"""
|
||||
def __init__(self, data, lstm_model=None, ppo_model=None, env=None, risk_reward_threshold=2.0):
|
||||
"""
|
||||
Initialize HierarchicalTrader.
|
||||
|
||||
Parameters:
|
||||
- data (pandas.DataFrame): Preprocessed market data.
|
||||
- lstm_model: Pre‑trained LSTM model for forecasting.
|
||||
- ppo_model: Trained PPO model for trading decisions.
|
||||
- env: Trading environment.
|
||||
- risk_reward_threshold (float): Minimum risk/reward ratio required to execute trades.
|
||||
"""
|
||||
self.logger = logging.getLogger(__name__)
|
||||
self.data = data
|
||||
self.lstm_model = lstm_model
|
||||
self.ppo_model = ppo_model
|
||||
self.env = env
|
||||
self.risk_reward_threshold = risk_reward_threshold
|
||||
|
||||
def assess_risk_reward(self, current_price, forecast, atr, current_position):
|
||||
"""
|
||||
Assess risk/reward ratio based on current price, forecast, ATR, and position.
|
||||
|
||||
Parameters:
|
||||
- current_price (float): Current market price.
|
||||
- forecast (float): Forecasted price change (as a ratio).
|
||||
- atr (float): Current ATR value.
|
||||
- current_position (int): Number of contracts held.
|
||||
|
||||
Returns:
|
||||
- risk_reward (float): Calculated risk/reward ratio.
|
||||
"""
|
||||
expected_price = current_price * (1 + forecast)
|
||||
reward = abs(expected_price - current_price)
|
||||
risk = atr
|
||||
risk_reward = reward / (risk + 1e-9)
|
||||
return risk_reward
|
||||
|
||||
def generate_trade_signal(self, observation):
|
||||
"""
|
||||
Generate a trade signal by combining PPO agent output and LSTM forecast.
|
||||
Applies risk/reward filtering.
|
||||
|
||||
Parameters:
|
||||
- observation: Current state from the trading environment.
|
||||
|
||||
Returns:
|
||||
- signal (int): Trade signal (e.g., number of contracts to buy/sell), or 0 for no action.
|
||||
"""
|
||||
# Assume observation consists of technical indicators, normalized position, and forecast (last element)
|
||||
current_forecast = observation[-1]
|
||||
current_position = observation[-2]
|
||||
|
||||
if self.ppo_model is None:
|
||||
self.logger.error("PPO model not provided for hierarchical trading.")
|
||||
return 0
|
||||
|
||||
action, _ = self.ppo_model.predict(observation, deterministic=True)
|
||||
trade_signal = int(action) if isinstance(action, (int, np.integer)) else int(round(float(action)))
|
||||
|
||||
# For simplicity, we simulate current price and ATR extraction; in practice, these come from the environment.
|
||||
current_price = 1.0 # Placeholder
|
||||
atr = 0.01 # Placeholder
|
||||
|
||||
rr_ratio = self.assess_risk_reward(current_price, current_forecast, atr, current_position)
|
||||
self.logger.info(f"Calculated risk/reward ratio: {rr_ratio:.2f}")
|
||||
|
||||
if rr_ratio < self.risk_reward_threshold:
|
||||
self.logger.info("Risk/Reward ratio below threshold. No trade executed.")
|
||||
return 0
|
||||
|
||||
self.logger.info(f"Trade signal generated: {trade_signal}")
|
||||
return trade_signal
|
||||
|
||||
def backtest(self):
|
||||
"""
|
||||
Perform backtesting simulation over historical data using hierarchical decision making.
|
||||
|
||||
Returns:
|
||||
- dict: Backtesting results (e.g., total PnL, win rate).
|
||||
"""
|
||||
self.logger.info("Starting backtest simulation...")
|
||||
total_reward = 0.0
|
||||
num_trades = 0
|
||||
for idx, row in self.data.iterrows():
|
||||
observation = self._create_observation(row)
|
||||
signal = self.generate_trade_signal(observation)
|
||||
reward = signal * 0.001 # Simplified reward calculation
|
||||
total_reward += reward
|
||||
if signal != 0:
|
||||
num_trades += 1
|
||||
results = {
|
||||
'total_reward': total_reward,
|
||||
'num_trades': num_trades,
|
||||
'average_reward': total_reward / (num_trades + 1e-9)
|
||||
}
|
||||
self.logger.info("Backtest simulation completed.")
|
||||
return results
|
||||
|
||||
#### Changes ####
|
||||
def _create_observation(self, row):
|
||||
# drop any timestamp/date column plus the target 'close'
|
||||
drop_cols = [c for c in row.index if c.lower() in ('time', 'date', 'close')]
|
||||
tech_indicators = row.drop(labels=drop_cols).values
|
||||
|
||||
# position (if you later include it in the row, pop it here)
|
||||
normalized_position = np.array([0.0])
|
||||
|
||||
# if you ever add a real forecast column, you can pull that instead
|
||||
# for now we keep your placeholder
|
||||
forecast = np.array([0.001])
|
||||
|
||||
# final observation vector
|
||||
return np.concatenate([tech_indicators, normalized_position, forecast])
|
||||
|
||||
'''
|
||||
def _create_observation(self, row):
|
||||
"""
|
||||
Create a synthetic observation vector from a data row.
|
||||
In a full implementation, this should mirror the environment's observation space.
|
||||
|
||||
Parameters:
|
||||
- row (pandas.Series): A row from the historical dataset.
|
||||
|
||||
Returns:
|
||||
- numpy.array: Observation vector.
|
||||
"""
|
||||
tech_indicators = row.drop(labels=['time', 'close']).values
|
||||
normalized_position = np.array([0.0])
|
||||
forecast = np.array([0.001]) # Placeholder forecast value
|
||||
|
||||
observation = np.concatenate([tech_indicators, normalized_position, forecast])
|
||||
return observation
|
||||
'''
|
||||
|
||||
def live_trading(self):
|
||||
"""
|
||||
Simulate live trading by continuously generating trade signals.
|
||||
This function is a placeholder for integrating with live market data and execution systems.
|
||||
"""
|
||||
self.logger.info("Starting live trading simulation...")
|
||||
import time
|
||||
while True:
|
||||
observation = self._create_observation(self.data.iloc[-1])
|
||||
signal = self.generate_trade_signal(observation)
|
||||
self.logger.info(f"Live trade signal: {signal}")
|
||||
# In production, signal triggers execution via the execution module.
|
||||
time.sleep(5) # Simulate 5‑minute reevaluation in a live setting.
|
||||
|
||||
110
src/MidasHL/src/old_main.py
Normal file
110
src/MidasHL/src/old_main.py
Normal file
@@ -0,0 +1,110 @@
|
||||
"""
|
||||
src/main.py
|
||||
|
||||
Main entry point for the FuturesTradingAI application.
|
||||
This script parses command‑line arguments, sets up logging, loads configurations,
|
||||
initializes data processing, model training, and can start the live trading loop or backtesting.
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import logging
|
||||
import threading
|
||||
|
||||
from src.config import SAMPLE_DATA_PATH, OUTPUT_DIR, MODEL_DIR, LOG_DIR, MONITOR_CONFIG
|
||||
from src.utils.logger import setup_logging
|
||||
from src.data.loader import load_data
|
||||
from src.data.technical_indicators import calculate_all_indicators
|
||||
from src.data.preprocessing import preprocess_data
|
||||
from src.models.lstm_forecaster import LSTMForecaster
|
||||
from src.models.ppo_trader import PPOTrader
|
||||
from src.models.hierarchical import HierarchicalTrader
|
||||
from src.trading.env import FuturesTradingEnv
|
||||
from src.utils.resource_monitor import start_resource_monitor
|
||||
|
||||
def parse_args():
|
||||
"""
|
||||
Parse command‑line arguments.
|
||||
"""
|
||||
parser = argparse.ArgumentParser(
|
||||
description="FuturesTradingAI - Hierarchical Learning for Live /MES Futures Trading"
|
||||
)
|
||||
parser.add_argument("--data", type=str, default=SAMPLE_DATA_PATH, help="Path to input CSV data file")
|
||||
parser.add_argument(
|
||||
"--mode", type=str, choices=["train", "backtest", "live"], default="train",
|
||||
help="Mode to run: train for model training, backtest for historical simulation, live for live trading"
|
||||
)
|
||||
return parser.parse_args()
|
||||
|
||||
def main():
|
||||
# Parse command‑line arguments
|
||||
args = parse_args()
|
||||
|
||||
# Ensure necessary output directories exist
|
||||
os.makedirs(OUTPUT_DIR, exist_ok=True)
|
||||
os.makedirs(MODEL_DIR, exist_ok=True)
|
||||
os.makedirs(LOG_DIR, exist_ok=True)
|
||||
|
||||
# Setup logging configuration
|
||||
setup_logging(LOG_DIR)
|
||||
logger = logging.getLogger(__name__)
|
||||
logger.info("Starting FuturesTradingAI application...")
|
||||
|
||||
# Optionally start system resource monitoring in a separate thread
|
||||
monitor_thread = threading.Thread(target=start_resource_monitor, args=(MONITOR_CONFIG['interval'],), daemon=True)
|
||||
monitor_thread.start()
|
||||
|
||||
# Load historical market data
|
||||
logger.info(f"Loading data from {args.data}...")
|
||||
df = load_data(args.data)
|
||||
|
||||
# Calculate technical indicators (RSI, MACD, OBV, ADX, Bollinger Bands, MFI, ATR, etc.)
|
||||
logger.info("Calculating technical indicators on dataset...")
|
||||
df = calculate_all_indicators(df)
|
||||
|
||||
# Advanced data preprocessing and feature engineering
|
||||
logger.info("Preprocessing data...")
|
||||
df_processed = preprocess_data(df)
|
||||
|
||||
#### Changes ####
|
||||
# normalize columns for HierarchicalTrader
|
||||
df_processed.columns = df_processed.columns.str.lower()
|
||||
if 'date' in df_processed.columns:
|
||||
df_processed = df_processed.rename(columns={'date': 'time'})
|
||||
|
||||
# Depending on mode, run training, backtesting or live trading
|
||||
if args.mode == "train":
|
||||
# Train LSTM forecaster
|
||||
logger.info("Initializing LSTM forecaster...")
|
||||
lstm_forecaster = LSTMForecaster(data=df_processed)
|
||||
lstm_forecaster.train()
|
||||
|
||||
# Train PPO trading agent using custom environment
|
||||
logger.info("Initializing PPO trader...")
|
||||
ppo_trader = PPOTrader(data=df_processed, lstm_model=lstm_forecaster.model)
|
||||
ppo_trader.train()
|
||||
|
||||
# Save models
|
||||
lstm_forecaster.save(MODEL_DIR)
|
||||
ppo_trader.save(MODEL_DIR)
|
||||
|
||||
elif args.mode == "backtest":
|
||||
# Perform backtesting using hierarchical integration
|
||||
logger.info("Running backtesting simulation...")
|
||||
hierarchical_trader = HierarchicalTrader(data=df_processed)
|
||||
results = hierarchical_trader.backtest()
|
||||
logger.info("Backtest completed. Results:")
|
||||
logger.info(results)
|
||||
|
||||
elif args.mode == "live":
|
||||
# Initiate live trading simulation
|
||||
logger.info("Starting live trading simulation...")
|
||||
env = FuturesTradingEnv(data=df_processed)
|
||||
hierarchical_trader = HierarchicalTrader(data=df_processed, env=env)
|
||||
hierarchical_trader.live_trading()
|
||||
|
||||
logger.info("FuturesTradingAI application finished.")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
||||
0
src/MidasHL/src/trading/__init__.py
Normal file
0
src/MidasHL/src/trading/__init__.py
Normal file
BIN
src/MidasHL/src/trading/__pycache__/__init__.cpython-311.pyc
Normal file
BIN
src/MidasHL/src/trading/__pycache__/__init__.cpython-311.pyc
Normal file
Binary file not shown.
Binary file not shown.
@@ -1,163 +1,91 @@
|
||||
"""
|
||||
src/trading/env.py
|
||||
|
||||
This module defines a custom OpenAI Gym environment for /MES futures trading on a 5‑minute timeframe.
|
||||
The environment includes logic for:
|
||||
- Tracking positions (long/short)
|
||||
- Evaluating positions every 5 minutes
|
||||
- Implementing ATR‑based trailing stops for risk management
|
||||
- Allowing a single contract initially with hooks for multi‑contract trading in the future
|
||||
"""
|
||||
|
||||
import gym
|
||||
from gym import spaces
|
||||
import numpy as np
|
||||
import pandas as pd
|
||||
import logging
|
||||
import threading
|
||||
|
||||
class FuturesTradingEnv(gym.Env):
|
||||
"""
|
||||
Custom Gym environment for futures trading.
|
||||
"""
|
||||
metadata = {'render.modes': ['human']}
|
||||
|
||||
|
||||
def __init__(self, data, lstm_model=None, config=None):
|
||||
"""
|
||||
Initialize the trading environment.
|
||||
|
||||
Parameters:
|
||||
- data (pandas.DataFrame): Preprocessed market data.
|
||||
- lstm_model: Pre‑trained LSTM model for price forecasting (optional).
|
||||
- config (dict): Configuration parameters for the environment.
|
||||
"""
|
||||
super(FuturesTradingEnv, self).__init__()
|
||||
super().__init__()
|
||||
self.logger = logging.getLogger(__name__)
|
||||
self.data = data.reset_index(drop=True)
|
||||
self.lstm_model = lstm_model
|
||||
self.config = config if config is not None else {}
|
||||
|
||||
# Define action space: discrete orders ranging from -max_contracts to +max_contracts.
|
||||
self.config = config or {}
|
||||
|
||||
# action space
|
||||
self.max_contracts = self.config.get('max_contracts', 1)
|
||||
self.action_space = spaces.Discrete(2 * self.max_contracts + 1)
|
||||
|
||||
# Define observation space: technical indicators plus current position and forecast.
|
||||
self.tech_indicator_cols = [col for col in self.data.columns if col not in ['time', 'close']]
|
||||
obs_dim = len(self.tech_indicator_cols) + 2 # +1 for normalized position, +1 for forecast.
|
||||
|
||||
# observation space: drop time and close
|
||||
self.tech_indicator_cols = [c for c in self.data.columns if c not in ['time', 'close']]
|
||||
obs_dim = len(self.tech_indicator_cols) + 2
|
||||
self.observation_space = spaces.Box(low=-np.inf, high=np.inf, shape=(obs_dim,), dtype=np.float32)
|
||||
|
||||
# Trading variables
|
||||
|
||||
# trading vars
|
||||
self.current_step = 0
|
||||
self.contracts_held = 0
|
||||
self.entry_price = None
|
||||
|
||||
# ATR‑based trailing stop parameters
|
||||
self.trailing_stop = None
|
||||
|
||||
# ATR stop params
|
||||
self.atr_period = self.config.get('atr_period', 14)
|
||||
self.trailing_stop_multiplier = self.config.get('trailing_stop_multiplier', 1.5)
|
||||
self.trailing_stop = None
|
||||
|
||||
# Lock for thread‑safe LSTM predictions
|
||||
self.lstm_lock = threading.Lock()
|
||||
|
||||
|
||||
def _get_observation(self):
|
||||
"""
|
||||
Construct the observation vector from the current market data.
|
||||
|
||||
Returns:
|
||||
- observation (numpy.array): Observation vector for the current step.
|
||||
"""
|
||||
row = self.data.iloc[self.current_step]
|
||||
tech_indicators = row[self.tech_indicator_cols].values.astype(np.float32)
|
||||
norm_position = np.array([self.contracts_held / self.max_contracts], dtype=np.float32)
|
||||
|
||||
tech = row[self.tech_indicator_cols].values.astype(np.float32)
|
||||
pos = np.array([self.contracts_held / self.max_contracts], dtype=np.float32)
|
||||
if self.lstm_model and self.current_step >= self.config.get('window_size', 15):
|
||||
# For proper forecasting, construct an input sequence; here we use a placeholder.
|
||||
forecast = np.array([0.001], dtype=np.float32)
|
||||
else:
|
||||
forecast = np.array([0.0], dtype=np.float32)
|
||||
|
||||
observation = np.concatenate([tech_indicators, norm_position, forecast])
|
||||
return observation
|
||||
|
||||
return np.concatenate([tech, pos, forecast])
|
||||
|
||||
def reset(self):
|
||||
"""
|
||||
Reset the environment to an initial state.
|
||||
|
||||
Returns:
|
||||
- observation (numpy.array): The initial observation.
|
||||
"""
|
||||
self.current_step = 0
|
||||
self.contracts_held = 0
|
||||
self.entry_price = None
|
||||
self.trailing_stop = None
|
||||
self.current_step, self.contracts_held = 0, 0
|
||||
self.entry_price, self.trailing_stop = None, None
|
||||
return self._get_observation()
|
||||
|
||||
|
||||
def step(self, action):
|
||||
"""
|
||||
Execute one time step in the environment.
|
||||
|
||||
Parameters:
|
||||
- action (int): Action taken by the agent (discrete order adjustment).
|
||||
|
||||
Returns:
|
||||
- observation (numpy.array): Next state observation.
|
||||
- reward (float): Reward obtained from the action.
|
||||
- done (bool): Whether the episode has ended.
|
||||
- info (dict): Additional environment info.
|
||||
"""
|
||||
trade_adjustment = action - self.max_contracts
|
||||
current_price = self.data.iloc[self.current_step]['close']
|
||||
|
||||
transaction_cost = self.config.get('transaction_cost', 0.001) * abs(trade_adjustment) * current_price
|
||||
|
||||
trade_adj = action - self.max_contracts
|
||||
current_price = self.data.at[self.current_step, 'close']
|
||||
cost = self.config.get('transaction_cost', 0.001) * abs(trade_adj) * current_price
|
||||
reward = 0.0
|
||||
if trade_adjustment != 0:
|
||||
if trade_adj != 0:
|
||||
if self.contracts_held == 0:
|
||||
self.contracts_held = trade_adjustment
|
||||
self.contracts_held = trade_adj
|
||||
self.entry_price = current_price
|
||||
atr = self.data.iloc[self.current_step].get('ATR', 0.01)
|
||||
self.trailing_stop = current_price - self.trailing_stop_multiplier * atr if trade_adjustment > 0 else current_price + self.trailing_stop_multiplier * atr
|
||||
atr = self.data.at[self.current_step, 'atr']
|
||||
self.trailing_stop = (current_price - self.trailing_stop_multiplier * atr
|
||||
if trade_adj > 0 else current_price + self.trailing_stop_multiplier * atr)
|
||||
else:
|
||||
prev_position = self.contracts_held
|
||||
self.contracts_held += trade_adjustment
|
||||
prev = self.contracts_held
|
||||
self.contracts_held += trade_adj
|
||||
if self.contracts_held != 0:
|
||||
self.entry_price = (self.entry_price * prev_position + current_price * trade_adjustment) / self.contracts_held
|
||||
self.entry_price = (self.entry_price * prev + current_price * trade_adj) / self.contracts_held
|
||||
else:
|
||||
self.entry_price = None
|
||||
reward -= transaction_cost
|
||||
reward -= cost
|
||||
else:
|
||||
if self.contracts_held != 0 and self.entry_price is not None:
|
||||
reward = (current_price - self.entry_price) * self.contracts_held
|
||||
|
||||
# ATR‑based trailing stop logic:
|
||||
|
||||
# trailing stop
|
||||
if self.trailing_stop is not None:
|
||||
if self.contracts_held > 0 and current_price < self.trailing_stop:
|
||||
self.logger.info("ATR trailing stop triggered for long position.")
|
||||
reward += (current_price - self.entry_price) * self.contracts_held
|
||||
self.contracts_held = 0
|
||||
self.entry_price = None
|
||||
self.trailing_stop = None
|
||||
self.contracts_held = 0; self.entry_price = None; self.trailing_stop = None
|
||||
elif self.contracts_held < 0 and current_price > self.trailing_stop:
|
||||
self.logger.info("ATR trailing stop triggered for short position.")
|
||||
reward += (self.entry_price - current_price) * abs(self.contracts_held)
|
||||
self.contracts_held = 0
|
||||
self.entry_price = None
|
||||
self.trailing_stop = None
|
||||
|
||||
self.contracts_held = 0; self.entry_price = None; self.trailing_stop = None
|
||||
|
||||
self.current_step += 1
|
||||
done = self.current_step >= len(self.data) - 1
|
||||
observation = self._get_observation()
|
||||
|
||||
info = {
|
||||
'contracts_held': self.contracts_held,
|
||||
'entry_price': self.entry_price
|
||||
}
|
||||
return observation, reward, done, info
|
||||
|
||||
def render(self, mode='human'):
|
||||
"""
|
||||
Render the current state.
|
||||
"""
|
||||
current_price = self.data.iloc[self.current_step]['close']
|
||||
print(f"Step: {self.current_step}, Price: {current_price:.4f}, Contracts Held: {self.contracts_held}, Entry Price: {self.entry_price}")
|
||||
obs = self._get_observation()
|
||||
info = {'contracts_held': self.contracts_held, 'entry_price': self.entry_price}
|
||||
return obs, reward, done, info
|
||||
|
||||
def render(self, mode='human'):
|
||||
price = self.data.at[self.current_step, 'close']
|
||||
print(f"Step {self.current_step}, Price {price:.4f}, Held {self.contracts_held}")
|
||||
|
||||
@@ -41,12 +41,12 @@ def get_live_market_data():
|
||||
"""
|
||||
logger = logging.getLogger(__name__)
|
||||
live_data = {
|
||||
'time': None,
|
||||
'open': None,
|
||||
'high': None,
|
||||
'low': None,
|
||||
'close': 1.0, # Dummy value for testing
|
||||
'volume': None
|
||||
'Date': None,
|
||||
'Open': None,
|
||||
'High': None,
|
||||
'Low': None,
|
||||
'Close': 1.0, # Dummy value for testing
|
||||
'Volume': None
|
||||
}
|
||||
logger.info("Retrieved live market data (placeholder).")
|
||||
return live_data
|
||||
|
||||
163
src/MidasHL/src/trading/old_env.py
Normal file
163
src/MidasHL/src/trading/old_env.py
Normal file
@@ -0,0 +1,163 @@
|
||||
"""
|
||||
src/trading/env.py
|
||||
|
||||
This module defines a custom OpenAI Gym environment for /MES futures trading on a 5‑minute timeframe.
|
||||
The environment includes logic for:
|
||||
- Tracking positions (long/short)
|
||||
- Evaluating positions every 5 minutes
|
||||
- Implementing ATR‑based trailing stops for risk management
|
||||
- Allowing a single contract initially with hooks for multi‑contract trading in the future
|
||||
"""
|
||||
|
||||
import gym
|
||||
from gym import spaces
|
||||
import numpy as np
|
||||
import pandas as pd
|
||||
import logging
|
||||
import threading
|
||||
|
||||
class FuturesTradingEnv(gym.Env):
|
||||
"""
|
||||
Custom Gym environment for futures trading.
|
||||
"""
|
||||
metadata = {'render.modes': ['human']}
|
||||
|
||||
def __init__(self, data, lstm_model=None, config=None):
|
||||
"""
|
||||
Initialize the trading environment.
|
||||
|
||||
Parameters:
|
||||
- data (pandas.DataFrame): Preprocessed market data.
|
||||
- lstm_model: Pre‑trained LSTM model for price forecasting (optional).
|
||||
- config (dict): Configuration parameters for the environment.
|
||||
"""
|
||||
super(FuturesTradingEnv, self).__init__()
|
||||
self.logger = logging.getLogger(__name__)
|
||||
self.data = data.reset_index(drop=True)
|
||||
self.lstm_model = lstm_model
|
||||
self.config = config if config is not None else {}
|
||||
|
||||
# Define action space: discrete orders ranging from -max_contracts to +max_contracts.
|
||||
self.max_contracts = self.config.get('max_contracts', 1)
|
||||
self.action_space = spaces.Discrete(2 * self.max_contracts + 1)
|
||||
|
||||
# Define observation space: technical indicators plus current position and forecast.
|
||||
self.tech_indicator_cols = [col for col in self.data.columns if col not in ['Date', 'Close']]
|
||||
obs_dim = len(self.tech_indicator_cols) + 2 # +1 for normalized position, +1 for forecast.
|
||||
self.observation_space = spaces.Box(low=-np.inf, high=np.inf, shape=(obs_dim,), dtype=np.float32)
|
||||
|
||||
# Trading variables
|
||||
self.current_step = 0
|
||||
self.contracts_held = 0
|
||||
self.entry_price = None
|
||||
|
||||
# ATR‑based trailing stop parameters
|
||||
self.atr_period = self.config.get('atr_period', 14)
|
||||
self.trailing_stop_multiplier = self.config.get('trailing_stop_multiplier', 1.5)
|
||||
self.trailing_stop = None
|
||||
|
||||
# Lock for thread‑safe LSTM predictions
|
||||
self.lstm_lock = threading.Lock()
|
||||
|
||||
def _get_observation(self):
|
||||
"""
|
||||
Construct the observation vector from the current market data.
|
||||
|
||||
Returns:
|
||||
- observation (numpy.array): Observation vector for the current step.
|
||||
"""
|
||||
row = self.data.iloc[self.current_step]
|
||||
tech_indicators = row[self.tech_indicator_cols].values.astype(np.float32)
|
||||
norm_position = np.array([self.contracts_held / self.max_contracts], dtype=np.float32)
|
||||
|
||||
if self.lstm_model and self.current_step >= self.config.get('window_size', 15):
|
||||
# For proper forecasting, construct an input sequence; here we use a placeholder.
|
||||
forecast = np.array([0.001], dtype=np.float32)
|
||||
else:
|
||||
forecast = np.array([0.0], dtype=np.float32)
|
||||
|
||||
observation = np.concatenate([tech_indicators, norm_position, forecast])
|
||||
return observation
|
||||
|
||||
def reset(self):
|
||||
"""
|
||||
Reset the environment to an initial state.
|
||||
|
||||
Returns:
|
||||
- observation (numpy.array): The initial observation.
|
||||
"""
|
||||
self.current_step = 0
|
||||
self.contracts_held = 0
|
||||
self.entry_price = None
|
||||
self.trailing_stop = None
|
||||
return self._get_observation()
|
||||
|
||||
def step(self, action):
|
||||
"""
|
||||
Execute one time step in the environment.
|
||||
|
||||
Parameters:
|
||||
- action (int): Action taken by the agent (discrete order adjustment).
|
||||
|
||||
Returns:
|
||||
- observation (numpy.array): Next state observation.
|
||||
- reward (float): Reward obtained from the action.
|
||||
- done (bool): Whether the episode has ended.
|
||||
- info (dict): Additional environment info.
|
||||
"""
|
||||
trade_adjustment = action - self.max_contracts
|
||||
current_price = self.data.iloc[self.current_step]['Close']
|
||||
|
||||
transaction_cost = self.config.get('transaction_cost', 0.001) * abs(trade_adjustment) * current_price
|
||||
|
||||
reward = 0.0
|
||||
if trade_adjustment != 0:
|
||||
if self.contracts_held == 0:
|
||||
self.contracts_held = trade_adjustment
|
||||
self.entry_price = current_price
|
||||
atr = self.data.iloc[self.current_step].get('ATR', 0.01)
|
||||
self.trailing_stop = current_price - self.trailing_stop_multiplier * atr if trade_adjustment > 0 else current_price + self.trailing_stop_multiplier * atr
|
||||
else:
|
||||
prev_position = self.contracts_held
|
||||
self.contracts_held += trade_adjustment
|
||||
if self.contracts_held != 0:
|
||||
self.entry_price = (self.entry_price * prev_position + current_price * trade_adjustment) / self.contracts_held
|
||||
else:
|
||||
self.entry_price = None
|
||||
reward -= transaction_cost
|
||||
else:
|
||||
if self.contracts_held != 0 and self.entry_price is not None:
|
||||
reward = (current_price - self.entry_price) * self.contracts_held
|
||||
|
||||
# ATR‑based trailing stop logic:
|
||||
if self.trailing_stop is not None:
|
||||
if self.contracts_held > 0 and current_price < self.trailing_stop:
|
||||
self.logger.info("ATR trailing stop triggered for long position.")
|
||||
reward += (current_price - self.entry_price) * self.contracts_held
|
||||
self.contracts_held = 0
|
||||
self.entry_price = None
|
||||
self.trailing_stop = None
|
||||
elif self.contracts_held < 0 and current_price > self.trailing_stop:
|
||||
self.logger.info("ATR trailing stop triggered for short position.")
|
||||
reward += (self.entry_price - current_price) * abs(self.contracts_held)
|
||||
self.contracts_held = 0
|
||||
self.entry_price = None
|
||||
self.trailing_stop = None
|
||||
|
||||
self.current_step += 1
|
||||
done = self.current_step >= len(self.data) - 1
|
||||
observation = self._get_observation()
|
||||
|
||||
info = {
|
||||
'contracts_held': self.contracts_held,
|
||||
'entry_price': self.entry_price
|
||||
}
|
||||
return observation, reward, done, info
|
||||
|
||||
def render(self, mode='human'):
|
||||
"""
|
||||
Render the current state.
|
||||
"""
|
||||
current_price = self.data.iloc[self.current_step]['Close']
|
||||
print(f"Step: {self.current_step}, Price: {current_price:.4f}, Contracts Held: {self.contracts_held}, Entry Price: {self.entry_price}")
|
||||
|
||||
Binary file not shown.
Binary file not shown.
39
src/MidasHL/t
Normal file
39
src/MidasHL/t
Normal file
@@ -0,0 +1,39 @@
|
||||
---------------------------------
|
||||
------------------------------------------
|
||||
| time/ | |
|
||||
| fps | 469 |
|
||||
| iterations | 49 |
|
||||
| time_elapsed | 213 |
|
||||
| total_timesteps | 100352 |
|
||||
| train/ | |
|
||||
| approx_kl | 0.0016052579 |
|
||||
| clip_fraction | 0 |
|
||||
| clip_range | 0.2 |
|
||||
| entropy_loss | -1.09 |
|
||||
| explained_variance | 0 |
|
||||
| learning_rate | 0.0003 |
|
||||
| loss | 3.19e+05 |
|
||||
| n_updates | 480 |
|
||||
| policy_gradient_loss | -0.00846 |
|
||||
| value_loss | 6.55e+05 |
|
||||
------------------------------------------
|
||||
2025-04-13 00:42:59,396 - src.models.ppo_trader - INFO - PPO training completed.
|
||||
2025-04-13 00:42:59,398 - absl - WARNING - You are saving your model as an HDF5 file via `model.save()` or `keras.saving.save_model(model)`. This file format is considered legacy. We recommend using instead the native Keras format, e.g. `model.save('my_model.keras')` or `keras.saving.save_model(model, 'my_model.keras')`.
|
||||
2025-04-13 00:42:59,479 - src.models.lstm_forecaster - INFO - Model and scalers saved to /home/midas/codeWS/Projects/MidasTechnologiesINC/MidasEngine/src/MidasHL/output/models
|
||||
2025-04-13 00:42:59,494 - src.models.ppo_trader - INFO - PPO model saved to /home/midas/codeWS/Projects/MidasTechnologiesINC/MidasEngine/src/MidasHL/output/models/ppo_trader.zip
|
||||
2025-04-13 00:42:59,494 - __main__ - INFO - FuturesTradingAI application finished.
|
||||
midas:~/codeWS/Projects/MidasTechnologiesINC/MidasEngine/src/MidasHL$ ls
|
||||
FuturesTradingAI.egg-info build dist examples output requirements.txt setup.py src t tests venv
|
||||
midas:~/codeWS/Projects/MidasTechnologiesINC/MidasEngine/src/MidasHL$ python -m src.main --mode backtest
|
||||
|
||||
2025-04-13 01:11:16.950650: E external/local_xla/xla/stream_executor/cuda/cuda_fft.cc:477] Unable to register cuFFT factory: Attempting to register factory for plugin cuFFT when one has already been registered
|
||||
WARNING: All log messages before absl::InitializeLog() is called are written to STDERR
|
||||
E0000 00:00:1744506676.974089 1409604 cuda_dnn.cc:8310] Unable to register cuDNN factory: Attempting to register factory for plugin cuDNN when one has already been registered
|
||||
E0000 00:00:1744506676.981420 1409604 cuda_blas.cc:1418] Unable to register cuBLAS factory: Attempting to register factory for plugin cuBLAS when one has already been registered
|
||||
2025-04-13 01:11:17.005681: I tensorflow/core/platform/cpu_feature_guard.cc:210] This TensorFlow binary is optimized to use available CPU instructions in performance-critical operations.
|
||||
To enable the following instructions: AVX2 FMA, in other operations, rebuild TensorFlow with the appropriate compiler flags.
|
||||
2025-04-13 01:11:23,004 - __main__ - INFO - Starting FuturesTradingAI application...
|
||||
2025-04-13 01:11:23,005 - __main__ - INFO - Loading data from /home/midas/codeWS/Projects/MidasTechnologiesINC/MidasEngine/src/MidasHL/data/sample_data.csv...
|
||||
2025-04-13 01:11:23,005 - root - INFO - Loading data from: /home/midas/codeWS/Projects/MidasTechnologiesINC/MidasEngine/src/MidasHL/data/sample_data.csv
|
||||
2025-04-13 01:11:23,005 - root - ERROR - Data file not found: /home/midas/codeWS/Projects/MidasTechnologiesINC/MidasEngine/src/MidasHL/data/sample_data.csv
|
||||
|
||||
Reference in New Issue
Block a user