top of page
  • Nikhil Adithyan

Implementing a Forex Hedging Strategy with Python

A step-by-step guide to creating a risk-averse portfolio


Implementing a Forex Hedging Strategy with Python

Today, we’re delving into the practical side of Forex trading, aiming to create a solid hedging strategy. To navigate this financial landscape effectively, we’ll be relying on the TraderMade Forex API, a user-friendly tool that grants us easy access to a diverse range of market data.


This API becomes our window into the dynamic world of currency pairs, enabling us to visualize trends, analyze price movements, and ultimately craft a robust hedging approach. Join us as we explore the synergy between forex trading, hedging strategies, and the invaluable insights provided by TraderMade Forex API endpoints.


Importing the Data

To kick off our processes, we’ll initiate data extraction through TraderMade Forex API endpoints. Given the inherent volatility of the forex market, we’ll avoid extensive timeframes like a year or two. Our approach is to start with more granular data — specifically, Daily data for initial testing, followed by hourly data for subsequent analysis. This allows us to capture nuances and make informed decisions without losing sight of crucial details.


Here, I’m making use of the TradeMade Python SDK, a remarkably helpful tool that not only eases the data extraction process but also makes it exceptionally user-friendly for a seamless experience in our operations.


Now, let’s start by importing the necessary libraries required:



import tradermade as tm
import pandas as pd
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt

Next, our objective is to systematically extract the closing prices of the G10 USD-quoted pairs, facilitating a comprehensive analysis of correlations among these major currency pairs. Data for AUDUSD, CADUSD, EURUSD, JPYUSD, NZDUSD, NOKUSD, GBPUSD, SEKUSD, and CHFUSD for both 1-month on a daily basis and 1-day on an hourly basis time frames will be extracted.


tm.set_rest_api_key("YOUR API KEY") # Setting up the REST API token (Replace YOUR API KEY with your secret API key)

df_month = tm.timeseries(currency='AUDUSD,CADUSD,EURUSD,JPYUSD,NZDUSD,NOKUSD,GBPUSD,SEKUSD,CHFUSD',start="2023-11-10",end="2023-12-10",interval="daily",fields=["close"])
df_day = tm.timeseries(currency='AUDUSD,CADUSD,EURUSD,JPYUSD,NZDUSD,NOKUSD,GBPUSD,SEKUSD,CHFUSD',start="2023-12-13-00:00",end="2023-12-14-00:00",interval="hourly",fields=["close"])

To initiate data extraction, begin by configuring the REST API token (Replace YOUR API KEY with your secret API key). Utilizing the time series data endpoints, input the desired currencies, start and end date and time, preferred interval (daily, hourly, minute), and the selected field (open, high, low, close). Subsequently, storing the monthly and weekly datasets in distinct data frames named df_month and df_day. The resulting data extracted will appear as follows:


Month data:


Image by Author

Day Data:


Image by Author


Understanding Hedging in Forex Trading

In Forex Trading, hedging is a tactic to safeguard your position in a currency pair from unexpected shifts. It’s a short-term move often used when there’s concern about news or an event causing turbulence in currency markets.


When it comes to hedging forex pairs, there are three main strategies followed:


1. Direct hedging Strategy:


A direct hedging strategy in Forex involves simultaneously initiating both a buy and sell position for the same currency pair, providing a means to mitigate potential risks by offsetting market exposure. This approach allows traders to navigate market fluctuations more effectively through a balanced position in the selected currency pair.


2. Correlation hedging strategy:


Utilizing the correlation between currency pairs is a widely adopted Forex hedging strategy, allowing traders to navigate market volatility by simultaneously trading highly positively or negatively correlated pairs for effective risk mitigation.


3. Options Hedging Strategy:


Engaging in options trading serves as an alternative method to hedge trading risks, offering a less intricate approach compared to concurrently managing long and short positions in specific currency pairs. Options, as contractual instruments, grant traders the right, without obligation, to buy or sell currency at a predetermined rate on or before a specified future date, typically characterized by expiration dates.


Here, we’re diving into the Correlation hedging strategy. The approach involves selecting the optimal basket (commonly used to denote pairs of currency pairs) by assessing the correlation between them. Our focus is on identifying pairs that exhibit a notably positive correlation — where movements positively impact each other — hence opening opposite positions for the currency pairs in the basket. Subsequently, employing the hedging ratio, we’ll analyze the most effective way to construct our hedging portfolio.


You might be wondering about the concept of the hedging ratio. Let me break it down for you.


Hedging Ratio

The hedge ratio is essentially the proportion or comparative value of a hedge in relation to the overall position. It serves as a crucial risk management metric, providing insights into the potential risk associated with movements in the hedging instrument.


Hedge ratio formula

Another significant factor in hedging is the optimal hedge ratio, also known as the minimum variance hedge ratio. This ratio plays a crucial role in investment risk management, indicating the percentage of a hedging instrument — be it an asset or liability — that an investor should use for effective hedging. The optimal hedge ratio is particularly relevant in cross-hedging scenarios, where there might not be a perfect match between the hedging instrument and the asset being hedged. It helps minimize variance and optimize risk management strategies in the dynamic landscape of financial markets.


Optimal hedge ratio formula

Where:


ρ = The correlation coefficient of the changes in the spot and futures prices


σs = Standard deviation of changes in the spot price ‘s’


σp = Standard deviation of changes in the futures price ‘f’


Expanding on this concept to suit our needs, we apply a formula for the hedging factor in a pair of currency pairs X and Y:


Hedging ratio correlation formula

This formula helps us determine the hedging factor, offering insights into the relationship between the two currency pairs and aiding in the construction of an effective hedging portfolio.


Identifying Correlated Pairs

Now, in the process of selecting our optimal basket of currency pairs, we’ll start by creating a correlation heatmap. This visual representation allows us to identify pairs with the most negative correlation, laying the foundation for our hedging strategy.


Correlation heatmap for Month Data


correlation_matrix_month = df_month.corr()

# Create a heatmap using seaborn
plt.figure(figsize=(12, 10))
sns.heatmap(correlation_matrix_month, annot=True, cmap='coolwarm', fmt=".2f", linewidths=.5)
plt.title('Correlation Matrix of Forex Codes')
plt.show()
Correlation heatmap for Month Data


Correlation heatmap for Day Data



correlation_matrix_day = df_day.corr()

# Create the day Data heatmap using seaborn
plt.figure(figsize=(12, 10))
sns.heatmap(correlation_matrix_day, annot=True, cmap='coolwarm', fmt=".2f", linewidths=.5)
plt.title('Correlation Matrix of Forex Codes')
plt.show()

Correlation heatmap for Day Data

Looking at the data, we’ve identified two separate groups of currency pairs — one for daily data for a month and another for hourly data. This highlights the inherent volatility of the forex market, where the relationships between currency pairs constantly shift, impacting our hedging strategies in different ways.


Now let's identify the most positively correlated pairs for month and day data:


For Monthly data:



stacked_corr = correlation_matrix_month.stack()
filtered_corr = stacked_corr[stacked_corr < 1]
sorted_corr = filtered_corr.sort_values(ascending=False)
sorted_corr

Image by Author

Hence through Monthly Data analysis, we choose NZDUSD and CHFUSD as our basket with a correlation equal to 0.97 (most positively correlated basket)


For Day data:



stacked_corr_day = correlation_matrix_day.stack()
filtered_corr_day = stacked_corr_day[stacked_corr_day < 1]
sorted_corr_day = filtered_corr_day.sort_values(ascending=False)
sorted_corr_day

Image by Author

Hence through Day Data analysis, we choose SEKUSD and EURUSD as our basket with a correlation equal to 0.99 (most positively correlated basket)


Visualizations

Now that we have identified our basket of currency pairs for both daily and hourly data, let’s enhance our understanding by creating visualizations.


Now, to visualize the daily return values, we need to calculate the daily returns for each individual currency pair as follows:



# Daily Returns for Month Data

df_month_CHFUSD = tm.timeseries(currency='CHFUSD', start="2023-11-10", end="2023-12-10", interval="daily", fields=["open", "high", "low", "close"])  # Fetching Month Data for CHFUSD
df_month_CHFUSD['Daily_Return'] = ((df_month_CHFUSD['close'] - df_month_CHFUSD['open']) / df_month_CHFUSD['open']) * 100  # Creating Daily Return Value for CHFUSD
df_month_NZDUSD = tm.timeseries(currency='NZDUSD', start="2023-11-10", end="2023-12-10", interval="daily", fields=["open", "high", "low", "close"])  # Fetching Month Data for NZDUSD
df_month_NZDUSD['Daily_Return'] = ((df_month_NZDUSD['close'] - df_month_NZDUSD['open']) / df_month_NZDUSD['open']) * 100  # Creating Daily Return Value for NZDUSD

# Daily Returns for Day Data

df_day_SEKUSD = tm.timeseries(currency='SEKUSD', start="2023-12-13-00:00", end="2023-12-14-00:00", interval="hourly", fields=["open", "high", "low", "close"])  # Fetching day Data for SEKUSD
df_day_SEKUSD['Daily_Return'] = ((df_day_SEKUSD['close'] - df_day_SEKUSD['open']) / df_day_SEKUSD['open']) * 100  # Creating hourly Return Value for SEKUSD
df_day_EURUSD = tm.timeseries(currency='EURUSD', start="2023-12-13-00:00", end="2023-12-14-00:00", interval="hourly", fields=["open", "high", "low", "close"])  # Fetching day Data for EURUSD
df_day_EURUSD['Daily_Return'] = ((df_day_EURUSD['close'] - df_day_EURUSD['open']) / df_day_EURUSD['open']) * 100  # Creating hourly Return Value for EURUSD
df_day_CHFUSD = tm.timeseries(currency='CHFUSD', start="2023-12-13-00:00", end="2023-12-14-00:00", interval="hourly", fields=["open", "high", "low", "close"])  # Fetching day Data for CHFUSD
df_day_CHFUSD['Daily_Return'] = ((df_day_CHFUSD['close'] - df_day_CHFUSD['open']) / df_day_CHFUSD['open']) * 100  # Creating hourly Return Value for CHFUSD
df_day_NZDUSD = tm.timeseries(currency='NZDUSD', start="2023-12-13-00:00", end="2023-12-14-00:00", interval="hourly", fields=["open", "high", "low", "close"])  # Fetching day Data for NZDUSD
df_day_NZDUSD['Daily_Return'] = ((df_day_NZDUSD['close'] - df_day_NZDUSD['open']) / df_day_NZDUSD['open']) * 100  # Creating hourly Return Value for NZDUSD

1. Comparison of Daily Returns of CHFUSD & NZDUSD on a monthly timeframe



plt.figure(figsize=(10, 6))
plt.style.use('ggplot')

plt.plot(df_month_CHFUSD['date'], df_month_CHFUSD['Daily_Return'], label='CHFUSD', marker='o')
plt.plot(df_month_CHFUSD['date'], df_month_NZDUSD['Daily_Return'], label='NZDUSD', marker='o')

plt.title('CHFUSD/NZDUSD Returns Comparison')
plt.xlabel('Date')
plt.ylabel('Returns')
plt.legend()
plt.xticks(rotation = 50)
plt.grid(True)
plt.show()

1. Comparison of Daily Returns of CHFUSD & NZDUSD on a monthly timeframe

Examining the visual representation, a clear pattern emerges: when one currency pair experiences an upward movement, the other tends to move in the opposite direction, underscoring our negative correlation. This observable inverse relationship is crucial for our hedging strategy, as movements in one pair act as a counterbalance to the other within our selected basket. Similarly, let’s visualize the data for the 1-day timeframe.


2. Comparison of Hourly Returns of SEKUSD & EURUSD on a 1-day timeframe



plt.figure(figsize=(10, 6))
plt.style.use('ggplot')

plt.plot(df_day_SEKUSD['date'], df_day_SEKUSD['Daily_Return'], label='SEKUSD', marker='o')
plt.plot(df_day_SEKUSD['date'], df_day_EURUSD['Daily_Return'], label='EURUSD', marker='o')

plt.title('SEKUSD/EURUSD Returns Comparison')
plt.xlabel('Hour')
plt.ylabel('Returns')
plt.legend()
plt.xticks(rotation = 50)
plt.grid(True)
plt.show()

2. Comparison of Hourly Returns of SEKUSD & EURUSD on a 1-day timeframe

3. Comparison of Hourly Returns of CHFUSD & NZDUSD on a 1-day timeframe



plt.figure(figsize=(10, 6))
plt.style.use('ggplot')

plt.plot(df_day_CHFUSD['date'], df_day_CHFUSD['Daily_Return'], label='CHFUSD', marker='o')
plt.plot(df_day_CHFUSD['date'], df_day_NZDUSD['Daily_Return'], label='NZDUSD', marker='o')

plt.title('CHFUSD/NZDUSD Returns Comparison')
plt.xlabel('Hour')
plt.ylabel('Returns')
plt.legend()  
plt.xticks(rotation = 50) 
plt.grid(True)
plt.show()

3. Comparison of Hourly Returns of CHFUSD & NZDUSD on a 1-day timeframe

Comparing the visualizations of the hourly data for CHFUSD & NZDUSD and SEKUSD & EURUSD, it’s apparent that they share a high degree of similarity. However, based on the correlation data, a more significant positive correlation is between SEKUSD & EURUSD at the hourly level. Therefore, we will opt for SEKUSD & EURUSD for our hourly analysis.


Utilizing Hedge Ratios for Constructing Effective Hedge Profiles

In the initiation of forming hedging profiles, a pivotal metric comes into play — the hedge ratio. This metric not only illuminates the trend that the hedge is following but also provides a critical ratio guiding our investment decisions. The hedge ratio acts as a quantitative indicator, offering insights into the optimal allocation for effective risk management. By understanding and leveraging this metric, traders can make informed decisions on how to allocate their investments in alignment with market trends and potential risks.


Now, to compute hedge ratios, we’ll need to calculate both the correlation and standard deviation. Let’s streamline the process by combining these calculations into a single function, as outlined below:


Hedge Ratio Function



def calculate_hedging_ratio(df1, df2):
    
    # Merge the two DataFrames on the 'date' column
    merged_df = pd.merge(df1[['date', 'Daily_Return']], df2[['date', 'Daily_Return']], on='date', suffixes=('_1', '_2'))

    # Calculate the correlation coefficient between the returns of the two currency pairs
    correlation = merged_df['Daily_Return_1'].corr(merged_df['Daily_Return_2'])

    # Calculate the hedging ratio
    hedging_ratio = - correlation * (df1['Daily_Return'].std() /    df2['Daily_Return'].std())
    
    print(f"Correlation between the two currency pairs: {correlation}")
    print(f"Hedging Ratio: {hedging_ratio}")

# Calling the function to get the results

calculate_hedging_ratio(df_month_CHFUSD,df_month_NZDUSD) # for daily data
calculate_hedging_ratio(df_day_SEKUSD,df_day_EURUSD) # for hourly data

The results obtained for the ‘calculate_hedging_ratio’ function are as follows:


1. Hourly data:


Image by Author

2. Daily data:


Image by Author

Now that we have the hedging ratio values, let’s begin creating hedging profiles.


The initial phase in creating a hedging profile entails the assignment of weights to each individual currency pair within a basket based on the corresponding hedging ratio


Assigning Weights to individual currency pairs



# For Daily Data
hedging_ratio_CHFUSD_NZDUSD = 0.5203035958912856

# Calculate weights based on hedging ratio
weights_CHFUSD_NZDUSD = {'CHFUSD': 1 / (1 + abs(hedging_ratio_CHFUSD_NZDUSD)), 'NZDUSD': abs(hedging_ratio_CHFUSD_NZDUSD) / (1 + abs(hedging_ratio_CHFUSD_NZDUSD))}

# For Hourly Data
hedging_ratio_SEKUSD_EURUSD = 1.4597042985219284

# Calculate weights based on the hedging ratio
weights_SEKUSD_EURUSD = {'SEKUSD': 1 / (1 + abs(hedging_ratio_SEKUSD_EURUSD)), 'EURUSD': abs(hedging_ratio_SEKUSD_EURUSD) / (1 + abs(hedging_ratio_SEKUSD_EURUSD))}

Now, with the weights duly assigned, constructing a hedging profile becomes a straightforward process. The resulting profile would appear as follows:


Image by Author


Evaluation

We will assess the daily portfolio based on the data of the next day, while the hourly portfolio will be evaluated on the very next hour. To facilitate this, we will export new data using the historical data endpoints of the TraderMade Forex API, which provides a wealth of diverse historical data.


Importing New Day Data



# For Daily Data
df_next_day = tm.historical(currency='CHFUSD,NZDUSD', date="2023-12-11", interval="daily", fields=["open", "high", "low", "close"])  # Fetching new Day data
df_next_day['Daily_Return'] = ((df_next_day['close'] - df_next_day['open']) / df_next_day['open']) * 100  # Calculating Daily Return

# For Hourly Data
df_next_hour_SEKUSD = tm.timeseries(currency='SEKUSD', start="2023-12-14-00:05", end="2023-12-14-01:00", interval="hourly", fields=["open", "high", "low", "close"])  # Fetching Hourly Data for SEKUSD
df_next_hour_SEKUSD['Hourly_Return'] = ((df_next_hour_SEKUSD['close'] - df_next_hour_SEKUSD['open']) / df_next_hour_SEKUSD['open']) * 100  # Calculating Hourly Return for SEKUSD
df_next_hour_EURUSD = tm.timeseries(currency='EURUSD', start="2023-12-14-00:05", end="2023-12-14-01:00", interval="hourly", fields=["open", "high", "low", "close"])  # Fetching Hourly Data for EURUSD
df_next_hour_EURUSD['Hourly_Return'] = ((df_next_hour_EURUSD['close'] - df_next_hour_EURUSD['open']) / df_next_hour_EURUSD['open']) * 100  # Calculating Hourly Return for EURUSD

Now, let’s evaluate the portfolio return for the upcoming day/hour based on the previously formulated portfolio:



# Calculate next hour portfolio return
portfolio_return_next_hour = weights_SEKUSD_EURUSD['SEKUSD'] * df_next_hour_SEKUSD['Hourly_Return'].item() + weights_SEKUSD_EURUSD['EURUSD'] * df_next_hour_EURUSD['Hourly_Return'].item()

# Calculate next day portfolio return
portfolio_return_next_day = weights_CHFUSD_NZDUSD['CHFUSD'] * df_next_day.loc[df_next_day['instrument'] == 'CHFUSD', 'Daily_Return'].values[0] + weights_CHFUSD_NZDUSD['NZDUSD'] * df_next_day.loc[df_next_day['instrument'] == 'NZDUSD', 'Daily_Return'].values[0]

Subsequently, we assess the final output using a metric known as total return. The total return is a metric that reflects the overall percentage change in the value of an investment, encompassing both capital appreciation and income like dividends. A positive total return indicates a gain, while a negative one signals a loss. In addition, annualized returns provide a standardized measure on an annual basis, considering the compounding effect of gains or losses over time. These metrics are essential for assessing the comprehensive performance of a portfolio or investment strategy, offering insights into both short-term gains and long-term compounding effects.


Image by Author


def calculate_and_print_total_return(starting_portfolio_value, portfolio_return_next_day):
    ending_portfolio_value = starting_portfolio_value * (1 + portfolio_return_next_day / 100)
    total_return = (ending_portfolio_value - starting_portfolio_value) / starting_portfolio_value * 100
    print(f"Total Return: {total_return:.2f}%")

# Calling the 'calculate_and_print_total_return' function
calculate_and_print_total_return(1, portfolio_return_next_day)# For Daily Data 
calculate_and_print_total_return(1, portfolio_return_next_hour)# For Hourly Data
trading_days_in_year_daily = 252  # assuming 252 trading days in a year
trading_hours_per_day_hourly = 8  # Assuming 8 trading hours per day

# Calculate annualized total return for daily data
annualized_total_return_daily = ((1 + total_return_daily / 100) ** (trading_days_in_year_daily / 1)) - 1
print(f"Annualized Total Return (Daily Data): {annualized_total_return_daily * 100:.2f}%")

# Calculate annualized total return for hourly data
annualized_total_return_hourly = ((1 + total_return_hourly / 100) ** (trading_days_in_year_hourly * trading_hours_per_day_hourly / 1)) - 1
print(f"Annualized Total Return (Hourly Data): {annualized_total_return_hourly * 100:.2f}%")

After applying the total return function to both our portfolios, the resulting outcomes are as follows:


1. Profile based on daily Data:


Profile based on daily Data: Total Return

Profile based on daily Data: Annualized Total Return

2. Profile based on hourly Data:


Profile based on hourly Data: Total Return

Profile based on hourly Data: Annualized Total Return

In this analysis, the impact of data granularity on trading outcomes is evident. The portfolio based on daily data generated a profit of 0.19%, emphasizing the effectiveness of a strategic approach capturing longer-term trends. In contrast, the one formulated using hourly data yielded a smaller profit of 0.03%, reflecting the trade-off between accuracy and responsiveness in forex trading strategies. The Annualized Total Return for the daily data portfolio was 61.63%, while the hourly data portfolio showed a higher Annualized Total Return of 70.07%. This reinforces the importance of carefully balancing historical data noise and real-time responsiveness for optimal decision-making in forex trading.


NOTE:

This project utilizes basic and clear-cut definitions to showcase the application of various financial tools, including the hedging ratio. It is crafted for instructional purposes, placing emphasis on fundamental concepts. It is imperative to acknowledge that, in real-world scenarios, the inclusion of transaction costs can substantially impact overall profitability. The outcomes shared in this project are derived solely from the model and algorithm. Users are encouraged to customize and refine the methodology to align with their unique requirements and environmental factors. It’s essential to recognize that actual profits, accounting for transaction costs, may deviate from the simplified representations presented in this project. Furthermore, alternative and modified equations for the hedge ratio exist, and the one employed here is intentionally basic for clarity; users are encouraged to adapt it based on their specific context.


Conclusion

In conclusion, we devised a forex trading strategy employing two types of data — 1) daily and 2) hourly. This strategy involved calculating correlations to identify the optimal currency pair basket, followed by determining the hedging ratio. Utilizing the obtained hedging ratio, we constructed two portfolios and evaluated their performance.


The key takeaway from our analysis is the substantial impact of data granularity on trading outcomes, with the daily data approach yielding a higher profit (0.19%) compared to the hourly strategy (0.03%), emphasizing the importance of selecting an appropriate time frame for more effective decision-making in forex trading.


Throughout this process, the TraderMade Forex API proved instrumental, offering an easily accessible SDK and diverse datasets that significantly facilitated the workflow.


With that being said, you’ve reached the end of the article. Hope you learned something new and useful today. Thank you very much for your time.

bottom of page