def comput_idicators(df, trading_days, required, save_file, save_address, whole=1): # TODO:net_value has some problem. # columns needed col = ['index_price', 'Interest_rate', 'nav', 'rebalancing', 'stoploss'] df_valid = df.ix[:, col] start_balance = df.index[df['rebalancing'] == 1][0] df_valid = df_valid[df_valid.index >= start_balance] # daily return df_valid['return'] = np.log(df['nav']) - np.log(df['nav'].shift(1)) # benchmark_net_value df_valid[ 'benchmark'] = df_valid['index_price'] / df_valid['index_price'].ix[0] # benchmark_return df_valid['benchmark_return'] = (df_valid['benchmark']- df_valid['benchmark'].shift(1))/\ df_valid['benchmark'].shift(1) # Annualized return df_valid['Annu_return'] = pd.expanding_mean( df_valid['return']) * trading_days # Volatility df_valid.loc[:, 'algo_volatility'] = pd.expanding_std( df_valid['return']) * np.sqrt(trading_days) df_valid.loc[:, 'xret'] = df_valid[ 'return'] - df_valid['Interest_rate'] / trading_days / 100 df_valid.loc[:, 'ex_return'] = df_valid['return'] - df_valid[ 'benchmark_return'] def ratio(x): return np.nanmean(x) / np.nanstd(x) # sharpe ratio df_valid.loc[:, 'sharpe'] = pd.expanding_apply(df_valid['xret'], ratio)\ * np.sqrt(trading_days) # information ratio df_valid.loc[:, 'IR'] = pd.expanding_apply(df_valid['ex_return'], ratio)\ * np.sqrt(trading_days) # Sortino ratio def modify_ratio(x, re): re /= trading_days ret = np.nanmean(x) - re st_d = np.nansum(np.square(x[x < re] - re)) / x[x < re].size return ret / np.sqrt(st_d) df_valid.loc[:, 'sortino'] = pd.expanding_apply( df_valid['return'], modify_ratio, args=(required, )) * np.sqrt(trading_days) # Transfer infs to NA df_valid.loc[np.isinf(df_valid.loc[:, 'sharpe']), 'sharpe'] = np.nan df_valid.loc[np.isinf(df_valid.loc[:, 'IR']), 'IR'] = np.nan # hit_rate wins = np.where(df_valid['return'] >= df_valid['benchmark_return'], 1.0, 0.0) df_valid.loc[:, 'hit_rate'] = wins.cumsum() / pd.expanding_apply(wins, len) # 95% VaR df_valid['VaR'] = -pd.expanding_quantile(df_valid['return'], 0.05)*\ np.sqrt(trading_days) # 95% CVaR df_valid['CVaR'] = -pd.expanding_apply(df_valid['return'], lambda x: x[x < np.nanpercentile(x, 5)].mean())\ * np.sqrt(trading_days) if whole == 1: # max_drawdown def exp_diff(x, type): if type == 'dollar': xret = pd.expanding_apply(x, lambda xx: (xx[-1] - xx.max())) else: xret = pd.expanding_apply( x, lambda xx: (xx[-1] - xx.max()) / xx.max()) return xret # dollar # xret = exp_diff(df_valid['cum_profit'],'dollar') # df_valid['max_drawdown_profit'] = abs(pd.expanding_min(xret)) # percentage xret = exp_diff(df_valid['nav'], 'percentage') df_valid['max_drawdown_ret'] = abs(pd.expanding_min(xret)) # max_drawdown_duration: # drawdown_enddate is the first time for restoring the max def drawdown_end(x, type): xret = exp_diff(x, type) minloc = xret[xret == xret.min()].index[0] x_sub = xret[xret.index > minloc] # if never recovering,then return nan try: return x_sub[x_sub == 0].index[0] except: return np.nan def drawdown_start(x, type): xret = exp_diff(x, type) minloc = xret[xret == xret.min()].index[0] x_sub = xret[xret.index < minloc] try: return x_sub[x_sub == 0].index[-1] except: return np.nan df_valid['max_drawdown_start'] = pd.Series() df_valid['max_drawdown_end'] = pd.Series() df_valid['max_drawdown_start'].ix[-1] = drawdown_start( df_valid['nav'], 'percentage') df_valid['max_drawdown_end'].ix[-1] = drawdown_end( df_valid['nav'], 'percentage') df_valid.to_csv(save_address) # =====result visualization===== plt.figure(1) if whole == 1: plt.subplot(224) plt.plot(df_valid['nav'], label='strategy') plt.plot(df_valid['benchmark'], label='S&P500') plt.xlabel('Date') plt.legend(loc=0, shadow=True) plt.ylabel('Nav') plt.title('Nav of ' + save_file + ' & SP500') # plt.subplot(223) # plt.plot(df_valid['cum_profit'],label = 'strategy') # plt.xlabel('Date') # plt.ylabel('Cum_profit') # plt.title('Cum_profit of ' + save_file) plt.subplot(221) plt.plot(df_valid['return'], label='strategy') plt.xlabel('Date') plt.ylabel('Daily_return') plt.title('Daily Return of ' + save_file) plt.subplot(222) x_return = df_valid[df_valid['return'].notna()].loc[:, 'return'] y_return = df_valid[ df_valid['benchmark_return'].notna()].loc[:, 'benchmark_return'] mu = x_return.mean() sigma = x_return.std() mybins = np.linspace(mu - 3 * sigma, mu + 3 * sigma, 100) count_x, _, _ = plt.hist(x_return, mybins, normed=1, alpha=0.5, label='strategy') count_y, _, _ = plt.hist(y_return, mybins, normed=1, alpha=0.5, label='S&P500') plt.ylabel('density') plt.xlabel('daily_return') plt.title('Histogram of Daily Return for ' + save_file + ' & SP500') plt.grid(True) # add normal distribution line y = mlab.normpdf(mybins, mu, sigma) plt.plot(mybins, y, 'r--', linewidth=1, label='Normal of strategy') plt.legend(loc=0, shadow=True) # plt.tight_layout() plt.show() return df_valid
def VaR(symbol='AAPL', notl=None, conf=0.95, dist=None, _d1=None, _d2=None, volwindow=50, varwindow=250): # Retrieve the data from Internet # Choose a time period d1 = _d1 if _d1 else datetime.datetime(2001, 1, 1) d2 = _d2 if _d2 else datetime.datetime(2012, 1, 1) #get the tickers price = DataReader(symbol, "yahoo", d1, d2)['Adj Close'] price = price.asfreq('B').fillna(method='pad') ret = price.pct_change() #choose the quantile quantile = 1 - conf import pdb pdb.set_trace() #simple VaR using all the data # VaR on average accross all the data unnormedquantile = pd.expanding_quantile(ret, quantile) # similar one using a rolling window # VaR only calculated over the varwindow, rolling unnormedquantileR = pd.rolling_quantile(ret, varwindow, quantile) #we can also normalize the returns by the vol vol = pd.rolling_std(ret, volwindow) * np.sqrt(256) unitvol = ret / vol #and get the expanding or rolling quantiles # Same calcs as above except normalized so show VaR in # standard deviations instead of expected returns Var = pd.expanding_quantile(unitvol, quantile) VarR = pd.rolling_quantile(unitvol, varwindow, quantile) normedquantile = Var * vol normedquantileR = VarR * vol ret2 = ret.shift(-1) courbe = pd.DataFrame({ 'returns': ret2, 'quantiles': unnormedquantile, 'Rolling quantiles': unnormedquantileR, 'Normed quantiles': normedquantile, 'Rolling Normed quantiles': normedquantileR, }) courbe['nqBreak'] = np.sign(ret2 - normedquantile) / (-2) + 0.5 courbe['nqBreakR'] = np.sign(ret2 - normedquantileR) / (-2) + 0.5 courbe['UnqBreak'] = np.sign(ret2 - unnormedquantile) / (-2) + 0.5 courbe['UnqBreakR'] = np.sign(ret2 - unnormedquantileR) / (-2) + 0.5 nbdays = price.count() print('Number of returns worse than the VaR') print('Ideal Var : ', (quantile) * nbdays) print('Simple VaR : ', np.sum(courbe['UnqBreak'])) print('Normalized VaR : ', np.sum(courbe['nqBreak'])) print('---------------------------') print('Ideal Rolling Var : ', (quantile) * (nbdays - varwindow)) print('Rolling VaR : ', np.sum(courbe['UnqBreakR'])) print('Rolling Normalized VaR : ', np.sum(courbe['nqBreakR']))
#get the tickers stock = "PETR4.SA" price = DataReader(stock, "yahoo", d1, d2)['Adj Close'] price = price.asfreq('B').fillna(method='pad') ret = price.pct_change() #choose the quantile quantile = 0.05 #the vol window volwindow = 50 #and the Var window for rolling varwindow = 250 #simple VaR using all the data unnormedquantile = pd.expanding_quantile(ret, quantile) #similar one using a rolling window unnormedquantileR = pd.rolling_quantile(ret, varwindow, quantile) #we can also normalize the returns by the vol vol = pd.rolling_std(ret, volwindow) * np.sqrt(256) unitvol = ret / vol #and get the expanding or rolling quantiles Var = pd.expanding_quantile(unitvol, quantile) VarR = pd.rolling_quantile(unitvol, varwindow, quantile) normedquantile = Var * vol normedquantileR = VarR * vol