<SYSTEM_TASK:>
Given the following text description, write Python code to implement the functionality described below step by step
<END_TASK>
<USER_TASK:>
Description:
 Dynamic hedge
It's somewhat hard to find data about historical prices of options, so I will proceed differently as promissed. I will work on the following problem
Step1:  For the interest rate to be used, observing the charts of LIBOR rates, I will pick a linear model, starting from 2.5% at Jan-1-2005, going to 6% at Dec-31-2007 and decaying to 0.5% until Dec-31-2007 and staying there.
Step2:  That's all. Now I will measure volatility on the last running two weeks and decide if I will hedge that risk. Else return to the initial position. Options are bought or sold at the Black-Scholes price using the current rate and the running volatility. This mean that the first month I will keep the original portfolio, until I have enough (?) info about the market.
I will calculate the returns beforehand, so that I do not need to deal with pandas Series. It must be pointed that on prices there are a split on the stocks at April 2 2014, so I need to repair this split. Also, I will define the formulas for the Delta (of the BSM model), the option pricing, the annual volatility.
On this simulation I will use only put options bought at the suggested price by the BSM model, as I assume that high volatility can lead to losses and want to hedge that high volatility times. I will not worry if volatility is low and expect that the stock make gains.
Step3:  I will define two functions, one to open a hedge position, selling if necessary some stock in order to affor the position. The other function will close the position, buying all possible stock with the earnings, if any. A transaction cost is included. It must account of both opening and closing the position (so, if your brokers charges you \$50, the commission is \$100)
Step4:  Now I will proceed to explain how this trading algorithm will work
<ASSISTANT_TASK:>
Python Code:
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
%matplotlib inline
data = pd.read_csv("../data/GOOG.csv").ix[:,["Date", "Open"]]
data.sort_values(by="Date", inplace=True)
data.reset_index(inplace=True)
Explanation: Dynamic hedge
It's somewhat hard to find data about historical prices of options, so I will proceed differently as promissed. I will work on the following problem:
I have a portfolio of 1000 GOOG stocks on Jannuary 1 2005. I want to hedge the portfolio whenever the running volatility is bigger than 40%, otherwise I will let it growth.
Not having historical prices on options I will use the theoretical Black-Scholes-Merton (BSM) price for options. This is problematic in some ways. First, the volatility I'm using at some time may not be the implied volatility used at that time for the real options sold and this means that I'm ignoring volatility smiles. Then there is the fact I need the free-risk interest rates and I don't have them, so I will build a model for it just to account for the changes after the financial crisis of the 2008.
End of explanation
rate = np.zeros_like(data.Date)
n = 0
m = 0
for d in data.Date:
    if d < "2007-12-31":
        rate[m] = 2.5 + n*3.5/734.0
    if d == "2007-12-31":
        rate[m] = 6.0
        n = 0
    if "2008-12-31" > d > "2007-12-31":
        rate[m] = 6.0 - 5.5*n/256
    if d >= "2008-12-31":
        rate[m] = 0.5
    m +=1
    n +=1
    
rate = rate/100
Explanation: For the interest rate to be used, observing the charts of LIBOR rates, I will pick a linear model, starting from 2.5% at Jan-1-2005, going to 6% at Dec-31-2007 and decaying to 0.5% until Dec-31-2007 and staying there.
End of explanation
from scipy.stats import norm
def volatility(v):
    return np.sqrt(260)*np.std(v)
def eu_put_option(S, K, r, s, t):
    d1 = (np.log(S/K) + t*(r + s*s/2))/np.sqrt(s*s*t)
    d2 = (np.log(S/K) + t*(r - s*s/2))/np.sqrt(s*s*t)
    return K*np.exp(-r*t)*norm.cdf(-d2) - S*norm.cdf(-d1)
    
def eu_put_option_delta(S, K, r, s, t):
    return norm.cdf((np.log(S/K) + t*(r + s*s/2))/np.sqrt(s*s*t)) - 1
    
def repair_split(df, info):   # info is a list of tuples [(date, split-ratio)]
    temp = df.Open.values.copy()
    for i in info:
        date, ratio = i
        mask = np.array(df.Date >= date)
        temp[mask] = temp[mask]*ratio
    return temp
stock_price = repair_split(data, [("2014-03-27", 2)])
rets = np.diff(np.log(stock_price))
Explanation: That's all. Now I will measure volatility on the last running two weeks and decide if I will hedge that risk. Else return to the initial position. Options are bought or sold at the Black-Scholes price using the current rate and the running volatility. This mean that the first month I will keep the original portfolio, until I have enough (?) info about the market.
I will calculate the returns beforehand, so that I do not need to deal with pandas Series. It must be pointed that on prices there are a split on the stocks at April 2 2014, so I need to repair this split. Also, I will define the formulas for the Delta (of the BSM model), the option pricing, the annual volatility.
On this simulation I will use only put options bought at the suggested price by the BSM model, as I assume that high volatility can lead to losses and want to hedge that high volatility times. I will not worry if volatility is low and expect that the stock make gains.
End of explanation
commission = 0
def rebalance(S, K, r, s, t, cap):
    option_price = eu_put_option(S, K, r, s, t)
    delta = eu_put_option_delta(S, K, r, s, t)
    # rebalance the portfolio, if not enough money, then sell stock to buy put options
    options = np.floor(cap/(option_price - delta*S))
    stock = np.floor(-delta*cap/(option_price - delta*S))
    money = cap - (options*option_price + stock*S)
    return (stock, options, money, option_price)
def close_position(S, K, nstock, nopt, mon):
    profit = nopt*max(0, K - S)
    money = mon + profit
    stock = nstock + np.floor(money/S)
    money -= (stock - nstock)*S
    money -= commission
    return (profit, stock, 0, money)
Explanation: I will define two functions, one to open a hedge position, selling if necessary some stock in order to affor the position. The other function will close the position, buying all possible stock with the earnings, if any. A transaction cost is included. It must account of both opening and closing the position (so, if your brokers charges you \$50, the commission is \$100)
End of explanation
capital = 200000  # just enough to buy the stocks
stock = 1000
money = capital - 1000*stock_price[0]  # this money will not take any interest
options = 0
strike = 0
option_price = 0
profit = 0
net_worth = []
vola = []
n_options = []
n_stock = []
n = 0
sell_options = 0
print("Not invested money: {0}".format(money))
for d in data.Date:
    capital = money + stock*stock_price[n]
    net_worth.append(capital)
    
    if n<60:
        n += 1
        continue
    # here begins the simulation
    vol = volatility(rets[n-15:n])
    vola.append(vol)
    
    if sell_options == 0 and options > 0:
        (profit, stock, options, money) = close_position(stock_price[n], strike, stock, options, money)
        print("\nSell options: {0}".format(data.Date[n]))
        print("    Profit: {0}".format(profit))
        print("    Stock price at {0}, strike at {1}".format(stock_price[n], strike))
        print("    Current balance: {0}".format(money + stock*stock_price[n]))
        
    if vol > 0.5 and options == 0:
        strike = stock_price[n] + 20
        (stock, options, money, option_price) = rebalance(stock_price[n], strike, rate[n], vol, 30/260.0, capital);
        
        print("\nBuy options: {0}".format(data.Date[n]))
        print("    Put option price (stock price at {0}, strike at {1}): {2}".format(stock_price[n], strike, option_price))
        print("    Position: {0} stock, {1} options, money: {2}".format(stock, options, money))
        print("    Current balance: {0}".format(money + stock*stock_price[n]))
        sell_options = 90
        
    if sell_options > 0:
        sell_options -= 1
        
    n_options.append(options)
    n_stock.append(stock)
    n += 1
plt.figure(figsize=(9,9))
plt.subplot(311)
plt.plot(1000*stock_price, label="GOOG")
plt.plot(net_worth, label="Portfolio")
plt.legend(loc=0)
plt.xlim(0,len(net_worth))
plt.subplot(312)
plt.plot(n_stock, label="Stock")
plt.legend(loc=0)
plt.subplot(313)
plt.plot(n_options, label="Put options")
plt.legend(loc=0)
plt.tight_layout()
Explanation: Now I will proceed to explain how this trading algorithm will work:
Buy all possible stock if the running volatility is low (last 30 working days)
If volatility is bigger than 50%, buy put european options to hedge possible losses
Options are bought at BSM price with the current volatility and risk-free rate
If not enough money to afford the position, rebalance by selling some stock
Execution time will be 90 "working days" to simplify the code
On execution, if options are on the money, make some action on the same step:
Sell stock at strike price
get money
buy again stock at market price
this way I get only the difference as money without touching my stocks
If volatility is still high don't rebalance options until they expire
If volatility is still high on expiration, buy options and rebalance again
The algorithm will begin with $200000, that are enough to buy 1000 (actualy a little more) stocks of GOOG (at that time).
I will count the balance only as the current money in hand and the price of stocks. The price of options don't count here as part of the portfolio price. This is because the money spent on buying options is lost, and will not return as they arent American and I don't intend to transfer them.
The simulation will begin with 60 days of heating to get enough data to calculate 15-days volatility.
End of explanation
<END_TASK>