<jupyter_start><jupyter_text>Hedge Funds and Alternative Investments— Problem Set 10 — _In problems 10.1-10.7, you backtest the currency carry trade using the data provided in the Excelspreadsheet for this problem set._  10.1 Investment currencies and funding currencies* For each month of the sample, rank the countries based on their interest rate. Computeeach country’s average rank (1=lowest interest rate, etc.). &nbsp; &nbsp; &nbsp; a. Which country has the lowest average rank, i.e., most often “funding currency” with the lowest interest rate? &nbsp; &nbsp; &nbsp; b. Which country is the second to most often funding currency (second lowest average rank)? &nbsp; &nbsp; &nbsp; c. Which country is most often “investment currency,” i.e. highest average rank? &nbsp; &nbsp; &nbsp; d. Which country is second to most often investment currency? &nbsp; &nbsp; &nbsp; e. Plot here the rank of the US over time.<jupyter_code>import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
file = "PS_10_Global_Macro.xlsx"
xrets = pd.read_excel(file, sheet_name="excess_returns", parse_dates=["date"], index_col="date")
xrets.head()<jupyter_output><empty_output><jupyter_text>The DataFrame contains the excess return of an investment of 1 USD in foreign currency over the US risk free rate (not annualized) for a 1-month investment period ENDING on date.<jupyter_code>rates = pd.read_excel(file, sheet_name="interest_rates", parse_dates=["date"], index_col="date")
rates.head()<jupyter_output><empty_output><jupyter_text>The DataFrame contains the annualized interest rate as of date.<jupyter_code>rates.plot()
plt.title("Interest rates over time")
plt.show()
tc = pd.read_excel(file, sheet_name="transaction_costs").iloc[0,:]<jupyter_output><empty_output><jupyter_text>The Series contains proportional transaction costs for each currency.<jupyter_code>tc.plot.bar()
plt.title("Proportional transaction costs")
plt.show()<jupyter_output><empty_output><jupyter_text>Computing ranks can be done easily using Pandas "rank" method: https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.rank.html The "method" argument is relevant if groups of records have the same value (there is no right or wrong regarding this choice - you can just stick to the default).<jupyter_code>ranks = rates.rank(axis=1, method="min")
round(ranks.mean().sort_values(), 2)<jupyter_output><empty_output><jupyter_text>__Results:__    Japan has the lowest average rank (i.e. it is most often a funding currency)    Switzerland has the second lowest average rank    New Zealand is most often investment currency, i.e highest average rank    Australia is second to most often investment currency Plot here the rank of the US over time:<jupyter_code>ranks.loc[:,"US"].plot()
plt.ylabel("Rank")
plt.title("Rank of the US over time")
plt.show()<jupyter_output><empty_output><jupyter_text>As you can see, the rank of the US does not fluctuate strongly over time. Changes occur rather slowly, causing relatively little turnover.  10.2 Carry positions* Create positions for each currency, either 1 USD (long), -1 USD (short), or 0 (flat). Do this bygoing short the three currencies with the lowest interest rate, and long the three withthe highest interest rate.What is the average position in New Zealand dollars?<jupyter_code># create boolean mask
low = ranks < 4
medium = (ranks > 3) & (ranks < 7)
high = ranks > 6
# copy DataFrame and then overwrite values
positions = ranks.copy()
positions[low] = -1
positions[medium] = 0
positions[high] = 1
positions.mean().sort_values().plot.bar()
plt.ylabel("Average position in USD")
plt.show()
print("Average position in New Zealand:", positions.loc[:,"New Zealand"].mean())<jupyter_output>Average position in New Zealand: 0.7607655502392344<jupyter_text>10.3 Carry trade return* Compute the excess return on each position, and add these up to get the excess return of the entire portfolio in any month. Make sure to get the timing right. (Hint: use SKEW and KURT, and annualize as in notes.) &nbsp; &nbsp; &nbsp; a. What is the annualized average excess return of the portfolio? &nbsp; &nbsp; &nbsp; b. What is the annualized standard deviation? &nbsp; &nbsp; &nbsp; c. What is the annualized SR? &nbsp; &nbsp; &nbsp; d. What is the skewness of monthly returns? &nbsp; &nbsp; &nbsp; e. What is the (excess) kurtosis of monthly return? &nbsp; &nbsp; &nbsp; f. Comment on these numbers.<jupyter_code>def performance_statistics(rets):
    
    # compute summary statistics
    stats = pd.Series([rets.mean() * 12,                              # annualized average return
                       rets.std() * np.sqrt(12),                      # annualized standard deviation
                       rets.mean() / rets.std() * np.sqrt(12),        # annualized sharpe ratio
                       rets.skew(),                                   # skewness of returns
                       rets.kurt()],                                  # kurtosis of returns
                      index=["Avg ret", "Std", "SR", "Skew", "Kurt"])
    
    # format in percent
    for stat in ["Avg ret", "Std"]: stats.loc[stat] = "{0:.2f}%".format(stats.loc[stat] * 100)
    
    # round to two decimals
    for stat in ["SR", "Skew", "Kurt"]: stats.loc[stat] = round(stats.loc[stat], 2)

    return stats<jupyter_output><empty_output><jupyter_text>**Important:** use the position at the RIGHT time, that is, position based on interest-rate known **BEFORE** the return period starts<jupyter_code>carry_xrets = positions.shift() * xrets
carry_xrets.head()
portfolio_xrets = carry_xrets.sum(axis=1, min_count=1)
# print performance statistics for the carry portfolio
performance_statistics(portfolio_xrets)<jupyter_output><empty_output><jupyter_text>__Comments:__    This simple strategy achieved high returns and Sharpe Ratio    Skewness and kurtosis indicate significant crash risk  10.4 Transaction costs* For each currency, compute the trade each month, that is, the change in position. (Position this month minus last month.) Assuming that the transaction costs are proportional as given in the sheet, compute the transaction costs for each currency. Add up the transaction costs to get the total transaction costs. Subtract total transaction costs from the portfolio’s excess return to get the return net of trading costs.&nbsp; &nbsp; &nbsp; a. What is the annualized average net return of the portfolio? &nbsp; &nbsp; &nbsp; b. What is the annualized net SR? &nbsp; &nbsp; &nbsp; c. Why is the effect of transaction costs so modest in this case? &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Do you think that this is typical of all trading strategies? &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Under which circumstances might a global macro trader incur larger transaction costs in connection with the currency carry trade? Positions after one month are the invested amounts times their return:<jupyter_code>us_rate = (rates.loc[:,"US"] / 12)
rets = xrets.add(us_rate.shift(), axis=0)
positions_dev = positions.shift() * (1 + rets)
positions_dev = positions_dev.fillna(0)
positions_dev<jupyter_output><empty_output><jupyter_text>To compute trade sizes, compare positions after one month with the new positions given by the carry strategy:<jupyter_code>trade_sizes = (positions_dev - positions).abs()
trade_sizes<jupyter_output><empty_output><jupyter_text>Transaction costs are proportional to the change in position. Total costs at each point in time are the sum of costs occuring for each trade:<jupyter_code>total_costs = (trade_sizes.shift() * tc).sum(axis=1)
avg_costs = total_costs.mean() * 12
print("Average annual transaction costs:", "{0:.2f}%".format(avg_costs * 100))
portfolio_xrets_net_tc = portfolio_xrets - total_costs
performance_statistics(portfolio_xrets_net_tc.iloc[1:])<jupyter_output><empty_output><jupyter_text>Transaction costs are so modest because...     ... currency markets are very liquid.      ... carry trade has low turnover (interest rates are very persistent).    High transaction costs might occur...     ... during a liquidity crisis (pressure to unwind positions).      ... when trading illiquid currencies.  10.5 High water mark* Compute the portfolio’s total return including the US risk free rate, but net of transaction costs (i.e. add the annual US interest rate divided by 12 to the portfolio’s return). Next, compute the cumulative return, assuming you start with 1 USD, and then keep reinvesting all profits/losses. Further, compute the high water mark as the maximum cumulative return from the first date to the current date. Make a plot with both the cumulative return and the high water mark.<jupyter_code># return of portfolio, incl. US riskfree, net of TC
portfolio_rets_net_tc = portfolio_xrets_net_tc + us_rate.shift()
# cumulative return of portfolio, net of TC
cum_rets_net_tc = (1 + portfolio_rets_net_tc).cumprod()
# high water mark
hwm = cum_rets_net_tc.expanding().max()
# make a plot
cum_rets_net_tc.plot(logy=True, figsize=(10, 5), label="Cumulative return of portfolio, net of TC")
hwm.plot(label="High water mark")
plt.legend()
plt.show()<jupyter_output><empty_output><jupyter_text>10.6 Drawdown* Compute and plot the drawdown, $ DD_t = \frac{\text{HWM}_t − P_t}{\text{HWM}_t} $, where $P$ is the cumulative return and $\text{HWM}$ is the high water mark.<jupyter_code># compute the drawdown
dd = (hwm - cum_rets_net_tc) / hwm
# make a plot
dd.plot()
plt.ylabel("Drawdown")
plt.show()<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.09710787418197171, 'fraction_numerical': 0.01013299556681444, 'mean_word_length': 4.6770521270221685, 'pattern_counts': {'":': 0, '<': 58, '<?xml version=': 0, '>': 58, 'https://': 1, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 3, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '14', 'dir': 'jupyter-structured-clean-dedup', 'id': '265186', 'license': 'MIT', 'n_tokens_mistral': 2875, 'n_tokens_neox': 2718, 'n_words': 1084, 'path': 'Carry.ipynb', 'repo_name': 'matsveikachatkou/hedge_fund_strategies', 'size': '9474'}