Skip to content

A new approach to Forex trading using PPO with Gym. The strategy incorporates multiple FX pairs into a single environment, enabling simultaneous decision-making, pair selection, and hedging opportunities. The environment is designed for weekly-based Forex trading, focusing on optimizing Sharpe ratios, win rates, and overall portfolio management.

License

Notifications You must be signed in to change notification settings

cove9988/tradesformer

Repository files navigation

Below is a detailed implementation of a hybrid Forex trading application that combines Proximal Policy Optimization (PPO) reinforcement learning with transformer-based models. This approach leverages the strengths of both RL and transformers to potentially enhance trading performance.

Table of Contents Introduction Project Setup Dependencies Data Collection and Preprocessing Data Download Data Preprocessing Building the Transformer Model Custom Time-Series Transformer Modifying the PPO Agent Custom Policy with Transformer Creating the Custom Gym Environment Environment Adjustments Training the Hybrid Agent Evaluation Conclusion References Introduction In this implementation, we'll: sample Combine PPO RL with a Transformer Model: Integrate a transformer into the PPO agent's policy network to process sequential market data. Develop a Custom Gym Environment: Simulate the Forex trading environment with appropriate state representation and reward structure. Train and Evaluate the Agent: Train the hybrid agent and assess its performance. Project Setup Dependencies Install the necessary Python libraries:

bash Copy code pip install numpy pandas matplotlib scikit-learn torch gym stable-baselines3 yfinance ta numpy, pandas: Data manipulation. matplotlib: Data visualization. scikit-learn: Preprocessing and evaluation metrics. torch: Deep learning framework. gym: Reinforcement learning environment. stable-baselines3: PPO implementation. yfinance: Market data retrieval. ta: Technical analysis indicators. Data Collection and Preprocessing Data Download We'll use yfinance to download historical Forex data.

python Copy code import yfinance as yf import pandas as pd

Define the currency pair and period

symbol = 'EURUSD=X' # EUR/USD exchange rate start_date = '2022-01-01' end_date = '2023-01-01' interval = '5m' # 5-minute intervals

Download data

data = yf.download(symbol, start=start_date, end=end_date, interval=interval) data = data.dropna() Data Preprocessing Adding Technical Indicators We can enhance the data by adding technical indicators using the ta library.

python Copy code from ta.volatility import BollingerBands from ta.trend import MACD, SMAIndicator from ta.momentum import RSIIndicator

Calculate indicators

data['SMA'] = SMAIndicator(data['Close'], window=14).sma_indicator() data['MACD'] = MACD(data['Close']).macd() data['RSI'] = RSIIndicator(data['Close'], window=14).rsi()

Bollinger Bands

bb_indicator = BollingerBands(data['Close']) data['BB_High'] = bb_indicator.bollinger_hband() data['BB_Low'] = bb_indicator.bollinger_lband()

Drop NaN values

data = data.dropna() Feature Engineering Normalize and prepare the data.

python Copy code from sklearn.preprocessing import MinMaxScaler

Select features

features = ['Open', 'High', 'Low', 'Close', 'Volume', 'SMA', 'MACD', 'RSI', 'BB_High', 'BB_Low'] scaler = MinMaxScaler() data[features] = scaler.fit_transform(data[features])

Reset index

data = data.reset_index() Sequence Preparation Prepare sequences for the transformer.

python Copy code import numpy as np

sequence_length = 12 # Number of past observations to consider

def create_sequences(df, seq_length): sequences = [] for i in range(len(df) - seq_length): seq = df.iloc[i:i+seq_length][features].values sequences.append(seq) return np.array(sequences)

sequences = create_sequences(data, sequence_length) Building the Transformer Model Custom Time-Series Transformer We will create a transformer model tailored for time-series data.

python Copy code import torch import torch.nn as nn

class TimeSeriesTransformer(nn.Module): def init(self, feature_size, num_heads, num_layers, dropout=0.1): super(TimeSeriesTransformer, self).init() self.model_type = 'Transformer' self.positional_encoding = nn.Parameter(torch.zeros(1, sequence_length, feature_size)) encoder_layer = nn.TransformerEncoderLayer(d_model=feature_size, nhead=num_heads, dropout=dropout) self.transformer_encoder = nn.TransformerEncoder(encoder_layer, num_layers=num_layers) self.decoder = nn.Linear(feature_size, feature_size) self.feature_size = feature_size

def forward(self, src):
    src = src + self.positional_encoding
    output = self.transformer_encoder(src)
    output = self.decoder(output)
    return output[:, -1, :]  # Return the last time step's output

Explanation: The transformer processes sequences of market data. We add positional encoding to retain temporal information. The decoder outputs a representation for the last time step. Modifying the PPO Agent Custom Policy with Transformer We need to create a custom policy network that incorporates the transformer model.

python Copy code from stable_baselines3.common.torch_layers import BaseFeaturesExtractor from stable_baselines3 import PPO import gym import torch.nn.functional as F

class CustomCombinedExtractor(BaseFeaturesExtractor): def init(self, observation_space: gym.spaces.Box, feature_size=64): super(CustomCombinedExtractor, self).init(observation_space, features_dim=feature_size) self.sequence_length = sequence_length num_features = observation_space.shape[1] self.transformer = TimeSeriesTransformer( feature_size=num_features, num_heads=4, num_layers=2 )

def forward(self, observations):
    # observations shape: (batch_size, seq_length, num_features)
    x = self.transformer(observations)
    return x

Update policy kwargs to use the custom extractor

policy_kwargs = dict( features_extractor_class=CustomCombinedExtractor, features_extractor_kwargs=dict(feature_size=len(features)), net_arch=[dict(pi=[64, 64], vf=[64, 64])], activation_fn=nn.ReLU ) Explanation: The CustomCombinedExtractor extracts features using the transformer model. The output is fed into the policy (pi) and value function (vf) networks. Creating the Custom Gym Environment Environment Adjustments We'll adjust the environment to work with sequences and provide data suitable for the transformer.

python Copy code class ForexTradingEnv(gym.Env): metadata = {'render.modes': ['human']}

def __init__(self, data, sequence_length):
    super(ForexTradingEnv, self).__init__()
    self.data = data
    self.sequence_length = sequence_length
    self.max_steps = len(self.data) - self.sequence_length - 1
    self.current_step = 0

    self.initial_balance = 10000.0
    self.balance = self.initial_balance
    self.net_worth = self.initial_balance
    self.positions = 0.0
    self.total_profit = 0.0

    # Define action and observation space
    # Actions: 0 = Hold, 1 = Buy, 2 = Sell
    self.action_space = spaces.Discrete(3)

    # Observation space: sequence_length x number of features
    obs_shape = (self.sequence_length, len(features))
    self.observation_space = spaces.Box(low=-np.inf, high=np.inf, shape=obs_shape, dtype=np.float32)

def reset(self):
    self.balance = self.initial_balance
    self.net_worth = self.initial_balance
    self.positions = 0.0
    self.total_profit = 0.0

    self.current_step = np.random.randint(self.sequence_length, self.max_steps)
    return self._next_observation()

def _next_observation(self):
    obs = self.data.iloc[self.current_step - self.sequence_length:self.current_step][features].values
    return obs

def step(self, action):
    done = False
    reward = 0

    current_price = self.data.iloc[self.current_step]['Close']

    # Execute action
    if action == 1:  # Buy
        if self.balance > 0:
            self.positions = self.balance / current_price
            self.balance = 0
    elif action == 2:  # Sell
        if self.positions > 0:
            self.balance = self.positions * current_price
            self.positions = 0

    # Update net worth
    self.net_worth = self.balance + self.positions * current_price

    # Calculate reward as the change in net worth
    reward = self.net_worth - self.initial_balance

    # Move to the next time step
    self.current_step += 1

    if self.current_step >= self.max_steps:
        done = True

    obs = self._next_observation()
    info = {'net_worth': self.net_worth}

    return obs, reward, done, info

def render(self, mode='human'):
    profit = self.net_worth - self.initial_balance
    print(f'Step: {self.current_step}')
    print(f'Balance: {self.balance:.2f}')
    print(f'Positions: {self.positions:.4f}')
    print(f'Net Worth: {self.net_worth:.2f}')
    print(f'Profit: {profit:.2f}')

Explanation: The environment now provides sequences of observations suitable for the transformer. The agent receives a sequence of past observations and decides to hold, buy, or sell. The reward is the change in net worth. Training the Hybrid Agent python Copy code import gym from stable_baselines3.common.vec_env import DummyVecEnv

Prepare the environment

env = DummyVecEnv([lambda: ForexTradingEnv(data, sequence_length)])

Initialize the PPO agent

model = PPO('MlpPolicy', env, verbose=1, policy_kwargs=policy_kwargs, tensorboard_log='./ppo_forex_tensorboard/')

Train the agent

total_timesteps = 100000 # Adjust as needed model.learn(total_timesteps=total_timesteps)

Save the model

model.save('ppo_forex_transformer') Notes: Adjust total_timesteps based on your computational resources. TensorBoard logging can help monitor training progress. Evaluation python Copy code

Load the trained model

model = PPO.load('ppo_forex_transformer')

Evaluate the agent

env = ForexTradingEnv(data, sequence_length) obs = env.reset() done = False

while not done: action, _states = model.predict(obs) obs, reward, done, info = env.step(action) env.render() Visualization: You can collect performance metrics and plot net worth over time. Implement more sophisticated evaluation by running the agent over multiple episodes and aggregating results. Conclusion In this implementation, we've created a hybrid Forex trading agent that combines PPO reinforcement learning with a transformer model:

Transformer Integration: The transformer processes sequences of market data to extract temporal features. Custom Policy Network: The policy network incorporates the transformer's output to make trading decisions. Environment Adjustments: The environment provides sequential observations compatible with the transformer's input requirements. Potential Enhancements:

Hyperparameter Tuning: Experiment with different transformer configurations (number of layers, heads, etc.). Feature Engineering: Include additional features such as economic indicators or sentiment analysis. Risk Management: Incorporate transaction costs, slippage, and risk constraints into the environment and agent. References Vaswani, A., et al. (2017). Attention is all you need. Link OpenAI Baselines: GitHub Repository Stable Baselines3 Documentation: Link PyTorch Documentation: Link TA-Lib Technical Analysis Library: Link# tradesformer A new approach to Forex trading using PPO with Gym. The strategy incorporates multiple FX pairs into a single environment, enabling simultaneous decision-making, pair selection, and hedging opportunities. The environment is designed for weekly-based Forex trading, focusing on optimizing Sharpe ratios, win rates, and overall portfolio management.

About

A new approach to Forex trading using PPO with Gym. The strategy incorporates multiple FX pairs into a single environment, enabling simultaneous decision-making, pair selection, and hedging opportunities. The environment is designed for weekly-based Forex trading, focusing on optimizing Sharpe ratios, win rates, and overall portfolio management.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages