def my_portfolio(start="2018-7-10", end="2018-10-16"): dates = pd.date_range(start, end) symbols = [ 'PHC', 'MBB', 'GEX', 'MBS', 'NDN', 'PNJ', 'STB', 'PVD', 'VRC', 'VIX' ] # symbols = ['PHC','MBB','GEX', 'MBS'] df_data = get_data(symbols, dates, benchmark='^VNINDEX') # get data for each symbol fill_missing_values(df_data) plot_normalized_data(df_data, title=" Daily porfolio value with VNINDEX ", xlabel="Date", ylabel=" Normalized price ")
def rebalancing_porfolio(symbols=None, bench='^VNINDEX'): start0 = "2015-1-2" end0 = "2017-1-2" allocations, cr, adr, sddr, sr = optimize_portfolio(sd=start0, ed=end0, syms=symbols, benchmark=bench, gen_plot=True) print("Optimize start Date:", start0) print("Optimize end Date:", end0) print("Optimize volatility (stdev of daily returns):", sddr) print("Optimize average Daily Return:", adr) print("Optimize cumulative Return:", cr) print(" -----------------------------------------------------") start_date_list = ["2017-1-3", "2017-7-3"] end_date_list = ["2017-7-2", "2018-4-1"] for start, end in zip(start_date_list, end_date_list): cr, adr, sddr, sr = compute_portfolio(sd=start, ed=end, syms=symbols, allocs=allocations, benchmark=bench, gen_plot=True) print("Start Date:", start) print("End Date:", end) print("Volatility (stdev of daily returns):", sddr) print("Average Daily Return:", adr) print("Cumulative Return:", cr) print(" -----------------------------------------------------") allocations, cr, adr, sddr, sr = optimize_portfolio(sd=start, ed=end, syms=symbols, benchmark=bench, gen_plot=False) print("Optimize volatility (stdev of daily returns):", sddr) print("Optimize average Daily Return:", adr) print("Optimize cumulative Return:", cr) print(" -----------------------------------------------------") # Out of sample testing optimisation algorithm end_date = "2018-9-27" start_date = "2018-4-2" cr, adr, sddr, sr = compute_portfolio(sd=start_date, ed=end_date, syms=symbols, allocs=allocations, benchmark=bench, gen_plot=True) print( "....................... Out of sample performance .................") print("Start Date:", start_date) print("End Date:", end_date) print("Volatility (stdev of daily returns):", sddr) print("Average Daily Return:", adr) print("Cumulative Return:", cr) # Assess the portfolio investment = 60E6 df_result = pd.DataFrame(index=symbols) df_result['Opt allocs'] = allocations df_result['Cash'] = allocations * investment dates = pd.date_range(start_date, end_date) # date range as index df_data = get_data(symbols, dates, benchmark=bench) # get data for each symbol df_high = get_data(symbols, dates, benchmark=bench, colname='<High>') df_low = get_data(symbols, dates, benchmark=bench, colname='<Low>') max_high = pd.Series(df_high.max(), name='MaxHigh') min_low = pd.Series(df_low.min(), name='MinLow') cpm = pd.Series(max_high / min_low, name='CPM') volatility = df_data[symbols].pct_change().std() # Fill missing values df_result['Close'] = df_data[symbols].iloc[-1, :].values df_result['CPM'] = cpm[symbols] df_result['Shares'] = round( df_result['Cash'] / df_result['Close'].values / 1000, 0) df_result['Volatility'] = volatility alpha_beta = analysis_alpha_beta(df_data, symbols, market=bench) df_result['Alpha'] = alpha_beta['Alpha'] df_result['Beta'] = alpha_beta['Beta'] relative_strength = 40*df_data[symbols].pct_change(periods = 63).fillna(0) \ + 20*df_data[symbols].pct_change(periods = 126).fillna(0) \ + 20*df_data[symbols].pct_change(periods = 189).fillna(0) \ + 20*df_data[symbols].pct_change(periods = 252).fillna(0) df_result['RSW'] = relative_strength.iloc[-1, :].values return df_result
def passive_strategy(start_date, end_date, market="^VNINDEX", symbols=None): if symbols == None: symbols = getliststocks(typestock=market) dates = pd.date_range(start_date, end_date) # date range as index df_data = get_data(symbols, dates, benchmark=market) # get data for each symbol df_volume = get_data(symbols, dates, benchmark=market, colname='<Volume>') # get data for each symbol df_high = get_data(symbols, dates, benchmark=market, colname='<High>') df_low = get_data(symbols, dates, benchmark=market, colname='<Low>') # covariance = numpy.cov(asset , SPY)[0][1] # variance = numpy.var(asset) # # beta = covariance / variance df_volume = df_volume.fillna(0) df_value = (df_volume * df_data).fillna(0) valueM30 = df_value.rolling(window=30).mean() vol_mean = pd.Series(df_volume.mean(), name='Volume') max_high = pd.Series(df_high.max(), name='MaxHigh') min_low = pd.Series(df_low.min(), name='MinLow') cpm = pd.Series(max_high / min_low, name='CPM') value_mean = pd.Series(df_value.mean(), name='ValueMean') # Fill missing values fill_missing_values(df_data) # Assess the portfolio allocations, cr, adr, sddr, sr = optimize_portfolio(sd=start_date, ed=end_date, syms=symbols, benchmark=market, gen_plot=True) # Print statistics print("Start Date:", start_date) print("End Date:", end_date) print("Symbols:", symbols) print("Optimal allocations:", allocations) print("Sharpe Ratio:", sr) print("Volatility (stdev of daily returns):", sddr) print("Average Daily Return:", adr) print("Cumulative Return:", cr) investment = 50000000 df_result = pd.DataFrame(index=symbols) df_result['Opt allocs'] = allocations df_result['Cash'] = allocations * investment df_result['Close'] = df_data[symbols].iloc[-1, :].values df_result['PCT_Change'] = 100 * (df_data[symbols].iloc[-1, :].values - df_data[symbols].iloc[0, :].values ) / df_data[symbols].iloc[0, :].values df_result['Volume'] = df_volume[symbols].iloc[-1, :].values df_result['VolumeMean'] = vol_mean[symbols] df_result['Value'] = df_result['Close'] * df_result['Volume'] df_result['ValueMean'] = value_mean[symbols] df_result['ValueMA30'] = valueM30[symbols].iloc[-1, :].values # df_result['MaxH'] = max_high # df_result['MinL'] = min_low df_result['CPM'] = cpm[symbols] df_result['Shares'] = round( df_result['Cash'] / df_result['Close'].values / 1000, 0) df_result['Volatility'] = df_data[symbols].pct_change().std() df_result['PCT_Change0D'] = df_data[symbols].pct_change().iloc[ -1, :].values * 100 df_result['PCT_Change1D'] = df_data[symbols].pct_change().iloc[ -2, :].values * 100 df_result['PCT_Change2D'] = df_data[symbols].pct_change().iloc[ -3, :].values * 100 alpha_beta = analysis_alpha_beta(df_data, symbols, market) df_result['Alpha'] = alpha_beta['Alpha'] df_result['Beta'] = alpha_beta['Beta'] relative_strength = 40*df_data[symbols].pct_change(periods = 63).fillna(0) \ + 20*df_data[symbols].pct_change(periods = 126).fillna(0) \ + 20*df_data[symbols].pct_change(periods = 189).fillna(0) \ + 20*df_data[symbols].pct_change(periods = 252).fillna(0) relative_strength1M = 100 * df_data[symbols].pct_change( periods=21).fillna(0) relative_strength2M = 100 * df_data[symbols].pct_change( periods=42).fillna(0) df_result['RSW'] = relative_strength.iloc[-1, :].values df_result['RSW1M'] = relative_strength1M.iloc[-1, :].values df_result['RSW2M'] = relative_strength2M.iloc[-1, :].values marketVNI = df_data[symbols].pct_change() advances = marketVNI[marketVNI > 0] declines = marketVNI[marketVNI <= 0] dec = advances.isnull().sum(axis=1) adv = declines.isnull().sum(axis=1) df_market = pd.DataFrame(index=marketVNI.index) df_market[market + 'Volume'] = df_volume[market] df_market[market + 'PCT_Volume'] = df_volume[market].pct_change() * 100 df_market[market + 'PCT_Index'] = df_data[market].pct_change() * 100 # df_market['Adv'] = adv # df_market['Dec'] = dec df_market[market + 'Adv_Dec'] = adv - dec df_market[market + 'Dec/Adv'] = dec / adv strength = pd.Series(index=marketVNI.index) strength[(df_market[market + 'Adv_Dec'] > 0) & (df_market[market + 'PCT_Index'] > 0)] = 1 strength[(df_market[market + 'Adv_Dec'] < 0) & (df_market[market + 'PCT_Index'] < 0)] = -1 strength[(df_market[market + 'Adv_Dec'] < 0) & (df_market[market + 'PCT_Index'] > 0)] = 0 df_market[market + 'Strength'] = strength # np.where((df_data[symbols].pct_change() > 0), 1, -1) return df_result, df_data, df_market
def passive_strategy(start_date, end_date, market=None, symbols=None, realtime=True, source='yahoo'): if symbols == None: symbols = getliststocks(typestock=market) if realtime: end_date = datetime.datetime.today() dates = pd.date_range(start_date, end_date) # date range as index df_data = get_data(symbols, dates, benchmark=market, colname='Adj Close', realtime=realtime, source=source) # get data for each symbol # Fill missing values fill_missing_values(df_data) df_volume = get_data(symbols, dates, benchmark=market, colname='Volume', realtime=realtime, source=source) # get data for each symbol df_rsi = get_RSI(symbols, df_data) df_volume = df_volume.fillna(0) df_result = pd.DataFrame(index=symbols) df_result['Ticker'] = symbols df_result['Close'] = df_data[symbols].iloc[-1, :].values df_result['PCT_C'] = 100 * (df_data[symbols].iloc[-1, :].values - df_data[symbols].iloc[0, :].values ) / df_data[symbols].iloc[0, :].values df_result['Volume'] = df_volume[symbols].iloc[ -1, :].values + df_volume[symbols].iloc[-2, :].values df_result['Value'] = df_result['Close'] * df_result['Volume'] df_result['Volatility'] = df_data[symbols].pct_change().std() df_result['PCT_3D'] = df_data[symbols].pct_change().iloc[ -4, :].values * 100 df_result['PCT_2D'] = df_data[symbols].pct_change().iloc[ -3, :].values * 100 df_result['PCT_1D'] = df_data[symbols].pct_change().iloc[ -2, :].values * 100 df_result['PCT_0D'] = df_data[symbols].pct_change().iloc[ -1, :].values * 100 relative_strength = 40*df_data[symbols].pct_change(periods = 63).fillna(0) \ + 20*df_data[symbols].pct_change(periods = 126).fillna(0) \ + 20*df_data[symbols].pct_change(periods = 189).fillna(0) \ + 20*df_data[symbols].pct_change(periods = 252).fillna(0) relative_strength1M = 100 * df_data[symbols].pct_change( periods=21).fillna(0) relative_strength2M = 100 * df_data[symbols].pct_change( periods=42).fillna(0) df_result['RSW'] = relative_strength.iloc[-1, :].values df_result['RSW1M'] = relative_strength1M.iloc[-1, :].values df_result['RSW2M'] = relative_strength2M.iloc[-1, :].values df_result['RSI'] = df_rsi[symbols].iloc[-1, :].values return df_result, df_data
def compute_portvals_margin_vn(start, end, orders, start_val=100000, commission=0.0015, tax=0.001, impact=0.0, market="^VNINDEX"): """Compute daily portfolio value given a dataframe of orders. Parameters ---------- start_date: first date to track end_date: last date to track df: read orders from dataframe start_val: total starting cash available Returns ------- portvals: portfolio value for each trading day from start_date to end_date (inclusive) """ # if isinstance(df, pd.DataFrame): if isinstance(orders, str): df = pd.read_csv(orders, index_col='Date', parse_dates=True) else: df = orders # Get the first date and last date after reading file start_date = df.iloc[0].name end_date = df.iloc[-1].name print(" Start trading date :", start_date) print(" End trading date :", end_date) dates = pd.date_range(start, end) if (dates[0] > start_date) or (end_date > dates[-1]): raise ValueError( " Error on start date and end date. Must be in larger period as in order file! Check again!" ) # symbols = [] # for i, row in df.iterrows(): # if row['Symbol'] not in symbols: # symbols.append(row['Symbol']) symbols = list(df['Symbol'].unique()) #ndarray to list of symbols in order prices_symbol = get_data(symbols, pd.date_range(start, end), benchmark=market) for symbol in symbols: prices_symbol[symbol + ' Shares'] = pd.Series( 0, index=prices_symbol.index) prices_symbol['Port Val'] = pd.Series(start_val, index=prices_symbol.index) prices_symbol['Cash'] = pd.Series(start_val, index=prices_symbol.index) # return prices_symbol for i, row in df.iterrows(): symbol = row['Symbol'] if row['Order'] == 'BUY': # print(symbol) cash_out = (prices_symbol.loc[i, symbol] * (1 + impact) * row['Shares']) current_cash = prices_symbol.loc[i, 'Cash'] # print(current_cash) if (2 * current_cash < cash_out): print("Over leverage (margin) 50%. Cannot BUY all shares. ") pass else: if (current_cash < cash_out): print(" Using leverage margin 50%") prices_symbol.loc[i:, symbol + ' Shares'] = prices_symbol.loc[ i:, symbol + ' Shares'] + row['Shares'] prices_symbol.loc[i:, 'Cash'] -= cash_out prices_symbol.loc[i:, 'Cash'] -= commission * cash_out if row['Order'] == 'SELL': current_shares = prices_symbol.loc[i, symbol + ' Shares'] if (row['Shares'] > current_shares): print(" Not enough shares to SELL!", current_shares, row['Shares']) pass else: prices_symbol.loc[i:, symbol + ' Shares'] = prices_symbol.loc[ i:, symbol + ' Shares'] - row['Shares'] prices_symbol.loc[i:, 'Cash'] += cash_out prices_symbol.loc[i:, 'Cash'] -= (commission + tax) * cash_out for i, row in prices_symbol.iterrows(): shares_val = 0 for symbol in symbols: shares_val += prices_symbol.loc[i, symbol + ' Shares'] * row[symbol] # print(" Shares values :", shares_val) prices_symbol.loc[i, 'Port Val'] = prices_symbol.loc[i, 'Cash'] + shares_val return prices_symbol
def testcode(): end_date = "2018-2-21" start_date = "2017-2-2" dates = pd.date_range(start_date, end_date) symbols = ['SHB'] investment = 1000000 ticker = 'SHB' data = get_data(symbols, dates, benchmark="^HASTC") # data = defineData(start_date, end_date, symbols) # return data plot_normalized_data(data) # get AAPL between the in-sample dates set as default data = get_data_trading(ticker, start_date, end_date) holdTime = 21 # in days smaWindow = 50 smaIndicator = getSmaIndicator(data, smaWindow=smaWindow) smaThreshold = 0.012 #0.012 # optimized value on manual trading strategy 1 # generate a buy signal (1) if price falls significantly below sma # generate a sell signal (-1) if prices rises significantly above sma smaSignal = 1 * (smaIndicator < -smaThreshold) + \ -1 * (smaIndicator > smaThreshold) momWindow = 10 momIndicator = getMomIndicator(data, momWindow=momWindow) momThreshold = 0.06 #0.055 # optimized value on manual trading strategy 1 # generate a buy/sell signal if momentum is greatly positive/negative momSignal = -1 * (momIndicator < -momThreshold) + \ 1 * (momIndicator > momThreshold) bbWindow = 10 #48 NOT OPTIMIZED bbIndicator = getBbIndicator(data, bbWindow=bbWindow) bbThreshold = 0 #0.2 NOT OPTIMIZED # generate a buy/sell signal if indicator is below/above the lower/upper BB # and the indicator is rising/falling significantly bbSignal = -1 * ((bbIndicator > 1) & \ (standardize(data['Close']).diff(1) < -bbThreshold)) + \ 1 * ((bbIndicator < -1) & \ (standardize(data['Close']).diff(1) > bbThreshold)) crossWindow = 18 crossIndicator = getCrossIndicator(data, crossWindow=crossWindow) crossThreshold = 0.08 #0.08 # optimized value on manual trading strategy 1 # generate a buy/sell signal if indicator is close to 0.5/-0.5 crossSignal = 1 * ( (crossIndicator - 0.5).abs() < crossThreshold) + \ -1 * ( (crossIndicator + 0.5).abs() < crossThreshold ) # Combine individual signals. bbSignal is neglected here since including it # with the other signals did not result in label-free trading using strategy 1 signal = 1 * ( (smaSignal == 1) & (momSignal ==1 ) & (crossSignal == 1) ) \ + -1 * ( (smaSignal == -1) & (momSignal == -1) & (crossSignal == -1) ) order = tradingStrategy(signal, holdTime) df_orders = createOrderDf(order) prices_symbol = compute_portvals_margin_vn(start_date, end_date, df_orders, start_val=investment, market="^HASTC") # return order portVals = prices_symbol['Port Val'] # print('Cumulative return [%]: ', round(cumReturn * 100, 4) ) order_opt = bestPossibleStrategy(data) df_orders_opt = createOrderDf(order_opt) prices_symbol_opt = compute_portvals_margin_vn(start_date, end_date, df_orders_opt, start_val = investment, \ market = "^HASTC") portVals_opt = prices_symbol_opt['Port Val'] fig = plt.figure(figsize=(10, 10)) ax1 = fig.add_subplot(3, 1, 1) # ax1 = plt.subplot(311) plt.plot(data['Close'] / data['Close'].iloc[0], label='benchmark (market)', color='k') plt.plot(portVals / portVals[0], label='rule-based') plt.plot(portVals_opt / portVals_opt[0], label='optimal') # plt.xticks(rotation=30) plotVline(order) plt.title('rule-based with sma + mom + crossover indicators') lg = plt.legend(loc='best') lg.draw_frame(False) plt.ylabel('normalized') # ax2 = plt.subplot(312) ax2 = fig.add_subplot(3, 1, 2) plt.plot(smaSignal / 2, label='sma') plt.plot(momSignal / 1.3, '.', label='mom') plt.plot(crossSignal / 1.1, '.', label='crossover') plt.plot(signal, label='overall signal') # plt.xticks(rotation=30) plt.ylabel('indicator signals [a.u.]') lg = plt.legend(loc='center right') lg.draw_frame(False) # plt.subplot(313) ax3 = fig.add_subplot(3, 1, 3) plt.scatter(momIndicator[signal==0], crossIndicator[signal==0], \ color = 'k', label = 'hold') plt.scatter(momIndicator[signal==1], crossIndicator[signal==1], \ color = 'g', label = 'buy') plt.scatter(momIndicator[signal==-1], crossIndicator[signal==-1], \ color = 'r', label = 'sell') lg = plt.legend(loc='best') lg.draw_frame(True) plt.xlabel('Momentum Indicator') plt.ylabel('Crossover Indicator') plt.subplots_adjust(hspace=0) # plt.setp([a.get_xticklabels() for a in plt.axes[:-1]], visible=False) return portVals_opt