def main(): # Get the Google data from Yahoo Finance from 2014-01-01 to 2018-01-01 goog_data_raw = get_google_data() goog_data = goog_data_raw.tail(620) # Use close price for this analysis close = goog_data['Close'] # Calculate Bollinger Bands: default time period = 20; standard deviation # factor = 2 bbands_df = bollinger_bands(close) # Prevent truncating display of DataFrame pd.set_option('display.width', None) print(bbands_df) # Extract data to plot close_price = close mband = bbands_df['MBBand'] uband = bbands_df['UBBand'] lband = bbands_df['LBBand'] # Plot the data fig = plt.figure() ax1 = fig.add_subplot(111, ylabel='Google price in $') close_price.plot(ax=ax1, color='c', lw=2.0, legend=True) mband.plot(ax=ax1, color='b', lw=2.0, legend=True) uband.plot(ax=ax1, color='g', lw=2.0, legend=True) lband.plot(ax=ax1, color='r', lw=2.0, legend=True) plt.grid() plt.show()
def main(): # Get the Google data from Yahoo Finance from 2014-01-01 to 2018-01-01 goog_data_raw = get_google_data() goog_data = goog_data_raw.tail(620) # Use close price for this analysis close = goog_data['Close'] # Calculate momentum of close price using default time period = 20 mom_list = momentum(close) mom_df = pd.DataFrame(close) mom_df = mom_df.assign(mom=pd.Series(mom_list, index=close.index)) print(mom_df) # Extract data to plot close_price = close mom = mom_df['mom'] # Plot the data fig = plt.figure() ax1 = fig.add_subplot(211, ylabel='Google price in $') close_price.plot(ax=ax1, color='g', lw=2.0, legend=True) ax2 = fig.add_subplot(212, ylabel='Momentum in $') mom.plot(ax=ax2, color='b', lw=2.0, legend=True) ax1.grid() ax2.grid() plt.show()
def main(): # Get the Google data from Yahoo Finance from 2014-01-01 to 2018-01-01 goog_data_raw = get_google_data() goog_data = goog_data_raw.tail(620) # Use close price for this analysis close = goog_data['Close'] # Calculate Relative Strength Index using default time period = 20 rsi_df = relative_strength_index(close) # Prevent truncating display of DataFrame pd.set_option('display.width', None) print(rsi_df) # Extract data to plot close_price = close rs_gain = rsi_df['RS_avg_gain'] rs_loss = rsi_df['RS_avg_loss'] rsi = rsi_df['RSI'] # Plot the data fig = plt.figure() ax1 = fig.add_subplot(311, ylabel='Google price in $') close_price.plot(ax=ax1, color='k', lw=2.0, legend=True) ax2 = fig.add_subplot(312, ylabel='RS') rs_gain.plot(ax=ax2, color='g', lw=2.0, legend=True) rs_loss.plot(ax=ax2, color='r', lw=2.0, legend=True) ax3 = fig.add_subplot(313, ylabel='RSI') rsi.plot(ax=ax3, color='b', lw=2.0, legend=True) ax1.grid() ax2.grid() ax3.grid() plt.show()
def main(): # Get the Google data from Yahoo Finance from 2014-01-01 to 2018-01-01 goog_data_raw = get_google_data() goog_data = goog_data_raw.tail(620) # Use close price for this analysis close = goog_data['Close'] apo_df = absolute_price_oscillator(close, time_period_fast=10, time_period_slow=40) close_price = close ema_fast = apo_df['ema_fast'] ema_slow = apo_df['ema_slow'] apo = apo_df['apo'] # Plot the close price, APO and fast and slow EMAs fig = plt.figure() ax1 = fig.add_subplot(211, ylabel='Google price in $') close_price.plot(ax=ax1, color='g', lw=2.0, legend=True) ema_fast.plot(ax=ax1, color='b', lw=2.0, legend=True) ema_slow.plot(ax=ax1, color='r', lw=2.0, legend=True) ax2 = fig.add_subplot(212, ylabel='APO') apo.plot(ax=ax2, color='k', lw=2.0, legend=True) ax1.grid() ax2.grid() plt.show()
def main(): # Get the Google data from Yahoo Finance from 2014-01-01 to 2018-01-01 goog_data_raw = get_google_data() # Use close price for this analysis close = goog_data_raw['Close'] # Calculate standard deviation of SMA using default time period 20 days signals.avg_sma_std_dev(close, tail=620) plt.show()
def main(): # Prevent truncating display of DataFrame pd.set_option('display.width', None) # Get daily trading data for 4 years SYMBOL = 'GOOG' goog_data = data.get_google_data(f'data/{SYMBOL}_data.pkl', start_date='2014-01-01', end_date='2018-01-01') # Use close price for this analysis close = goog_data.loc[:, 'Close'] # Constants defining strategy behaviour/thresholds # APO trading signal value above which to enter buy orders/long position apo_value_for_buy_entry = 10 # APO trading signal below above which to enter sell orders/short position apo_value_for_sell_entry = -10 # Minimum price change since last trade before considering trading again. # This is to prevent over trading at around same prices min_price_move_from_last_trade = 10 # Number of shares to buy/sell on every trade num_shares_per_trade = 10 # Minimum open/unrealised profit at which to close and lock profits min_profit_to_close = 10 * num_shares_per_trade # Exponential moving average time periods for APO calculation ema_time_period_fast = 10 ema_time_period_slow = 40 # Calculate trading strategy df = signals.basic_trend_following( close, ema_time_period_fast, ema_time_period_slow, apo_value_for_buy_entry=apo_value_for_buy_entry, apo_value_for_sell_entry=apo_value_for_sell_entry, min_price_move_from_last_trade=min_price_move_from_last_trade, num_shares_per_trade=num_shares_per_trade, min_profit_to_close=min_profit_to_close) # Visualise plotting.visualise(df, apo_value_for_buy_entry, apo_value_for_sell_entry, num_shares_per_trade) # Prepare DataFrame to save results to CSV goog_data = pd.concat([goog_data, df], axis=1) # Remove redundant close price column goog_data = goog_data.drop('ClosePrice', axis=1) goog_data.to_csv('ch05/basic_trend_following.csv') # Display plots and block plt.show()
def main(): # Prevent truncating display of DataFrame pd.set_option('display.width', None) goog_data = data.get_google_data('data/goog_data_large.pkl', start_date='2001-01-01', end_date='2018-01-01') # Features are open - close price and high - low price # Target is difference in daily close price goog_data, x, y = finml.create_regression_trading_condition(goog_data) # Split into train (80%) and test data sets x_train, x_test, y_train, y_test = finml.create_train_split_group(x, y) # Ridge regression model with regularisation parameter 0.1 ridge = linear_model.Ridge(alpha=10000) ridge.fit(x_train, y_train) print('Coefficients:\n', ridge.coef_) # Evaluate model on training data print(f'Mean squared error on training data: ' f'{mean_squared_error(y_train, ridge.predict(x_train))}') # Explained variance score: 1 is perfect prediction print(f'Variance score on training data: ' f'{r2_score(y_train, ridge.predict(x_train))}') # Evaluate model on test data print(f'Mean squared error on test data: ' f'{mean_squared_error(y_test, ridge.predict(x_test))}') # Explained variance score: 1 is perfect prediction print(f'Variance score on test data: ' f'{r2_score(y_test, ridge.predict(x_test))}') # LASSO regression model to predict prices and calculate strategy returns goog_data['Predicted_signal'] = ridge.predict(x) goog_data['GOOG_Returns'] = \ np.log(goog_data['Close'] / goog_data['Close'].shift(1)) print(goog_data) # Calculate cumulative returns for the test data (train data onwards) cum_goog_return = \ finml.calculate_return(goog_data, split_value=len(x_train), symbol='GOOG') cum_strategy_return = \ finml.calculate_strategy_return(goog_data, split_value=len(x_train)) finml.plot_chart(cum_goog_return, cum_strategy_return, symbol='GOOG') sharpe = finml.sharpe_ratio(cum_strategy_return, cum_goog_return) print(f'Sharpe ratio: {sharpe}') # Display plots and block plt.show()
def main(): # Prevent truncating display of DataFrame pd.set_option('display.width', None) goog_data = get_google_data('data/goog_data_large.pkl', start_date='2001-01-01', end_date='2018-01-01') # Features are open - close price and high - low price # Target is difference in daily close price goog_data, x, y = finml.create_regression_trading_condition(goog_data) # Visualise the data pd.plotting.scatter_matrix(goog_data[['Open-Close', 'High-Low', 'Target']], grid=True, diagonal='kde', alpha=0.5) # Display plots and block plt.show()
def main(): # Prevent truncating display of DataFrame pd.set_option('display.width', None) goog_data = data.get_google_data('data/goog_data_large.pkl', start_date='2001-01-01', end_date='2018-01-01') # Features are open - close price and high - low price # Target is based on difference in daily close price and is +1 if future # close price is higher than the current close price and -1 if the future # close price is lower than the current close price. goog_data, x, y = finml.create_classification_trading_condition(goog_data) # Split into train (80%) and test data sets x_train, x_test, y_train, y_test = finml.create_train_split_group(x, y) # KNN classification model using K=15 knn = KNeighborsClassifier(n_neighbors=15) y_train_array = y_train.to_numpy().ravel() knn.fit(x_train, y_train_array) accuracy_train = accuracy_score(y_train, knn.predict(x_train)) print('Training accuracy:', accuracy_train) accuracy_test = accuracy_score(y_test, knn.predict(x_test)) print('Test accuracy:', accuracy_test) # Predict whether the price goes up or down goog_data['Predicted_signal'] = knn.predict(x) goog_data['GOOG_Returns'] = \ np.log(goog_data['Close'] / goog_data['Close'].shift(1)) print(goog_data) # Calculate cumulative returns for the test data (train data onwards) cum_goog_return = \ finml.calculate_return(goog_data, split_value=len(x_train), symbol='GOOG') cum_strategy_return = \ finml.calculate_strategy_return(goog_data, split_value=len(x_train)) finml.plot_chart(cum_goog_return, cum_strategy_return, symbol='GOOG') sharpe = finml.sharpe_ratio(cum_strategy_return, cum_goog_return) print(f'Sharpe ratio: {sharpe}') # Display plots and block plt.show()
def main(): # Load Google financial data into a DataFrame goog_data = data.get_google_data(start_date='2001-01-01') # Run for loop backtester naive_backtester = ForLoopBackTester() for line in zip(goog_data.index, goog_data['Adj Close']): date = line[0] price = line[1] price_information = {'date': date, 'price': float(price)} is_tradable = naive_backtester.create_metrics(price_information) if is_tradable: naive_backtester.trade(price_information) # Plot output plt.plot(naive_backtester.list_total, label='Holdings+Cash') plt.title('For Loop Backtester') plt.grid() plt.legend() plt.show()
def main(): # Load Google financial data into a DataFrame goog_data = data.get_google_data(start_date='2001-01-01') # Run event driven backtester edbt = EventDrivenBackTester() for line in zip(goog_data.index, goog_data['Adj Close']): date = line[0] price = line[1] price_information = {'date': date, 'price': float(price)} # Create orders from price (ticker) information edbt.create_orders(price_information['price']) # Run main trading loop edbt.process_events() # Plot output plt.plot(edbt.trading_strategy.list_paper_total, label='Paper Trading Using Event Driven Backtester') plt.plot(edbt.trading_strategy.list_total, label='Trading Using Event Driven Backtester') plt.grid() plt.legend() plt.show()
def main(): # Get Google data from Yahoo from 2014-01-01 to 2018-01-01 goog_data_raw = get_google_data() goog_data = goog_data_raw.tail(620) # Use close price for this analysis close = goog_data['Close'] close_sma = simple_moving_average(close) goog_data = goog_data.assign( ClosePrice=pd.Series(close, index=goog_data.index)) goog_data = goog_data.assign( Simple20DayMovingAverage=pd.Series(close_sma, index=goog_data.index)) close_price = goog_data['ClosePrice'] sma = goog_data['Simple20DayMovingAverage'] # Plot the close price 20 day SMA fig = plt.figure() ax1 = fig.add_subplot(111, ylabel='Google price in $') close_price.plot(ax=ax1, color='g', lw=2.0, legend=True) sma.plot(ax=ax1, color='r', lw=2.0, legend=True) plt.grid() plt.show()
def main(): # Prevent truncating display of DataFrame pd.set_option('display.width', None) goog_data = data.get_google_data('data/goog_data.pkl', start_date='2001-01-01', end_date='2018-01-01') # Turtle trading strategy ts = signals.turtle_trading(goog_data, 50) print('Turtle trading strategy:') print(ts) # Plot the adjusted close price fig = plt.figure() ax1 = fig.add_subplot(111, ylabel='Google price in $') goog_data['Adj Close'].plot(ax=ax1, color='g', lw=0.5, label='Price') ts['high'].plot(ax=ax1, color='g', lw=0.5, label='Highs') ts['low'].plot(ax=ax1, color='r', lw=0.5, label='Lows') ts['avg'].plot(ax=ax1, color='b', lw=0.5, label='Average') # Plot buy signal ax1.plot(ts.loc[ts.orders == 1.0].index, goog_data['Adj Close'][ts.orders == 1.0], '^', markersize=7, color='k', label='Buy') # Plot sell signal ax1.plot(ts.loc[ts.orders == -1.0].index, goog_data['Adj Close'][ts.orders == -1.0], 'v', markersize=7, color='k', label='Sell') plt.legend() plt.title('Turtle Trading Strategy') plt.grid() plt.show()
def main(): # Prevent truncating display of DataFrame pd.set_option('display.width', None) goog_data = data.get_google_data('data/goog_data.pkl', start_date='2001-01-01', end_date='2018-01-01') # Dual moving average trading signal ts = signals.dual_moving_average(goog_data, 20, 100) print('Dual moving average trading signal:') print(ts) # Plot curve representing orders for dual moving average strategy using # close price. fig = plt.figure() ax1 = fig.add_subplot(111, ylabel='Google price in $') goog_data['Adj Close'].plot(ax=ax1, color='g', lw=0.5, label='Price') ts['short_mavg'].plot(ax=ax1, color='r', lw=2.0, label='Short mavg') ts['long_mavg'].plot(ax=ax1, color='b', lw=2.0, label='Long mavg') # Plot buy order ax1.plot(ts.loc[ts.orders == 1.0].index, goog_data['Adj Close'][ts.orders == 1.0], '^', markersize=7, color='k', label='Buy') # Plot sell order ax1.plot(ts.loc[ts.orders == -1.0].index, goog_data['Adj Close'][ts.orders == -1.0], 'v', markersize=7, color='k', label='Sell') plt.legend() plt.title('Dual Moving Average Trading Strategy') plt.grid() plt.show()
def main(): # Get the Google data from Yahoo Finance from 2014-01-01 to 2018-01-01 goog_data_raw = get_google_data() goog_data = goog_data_raw.tail(620) # Use close price for this analysis close = goog_data['Close'] # Calculate the MACD using default time periods: fast=10; slow=40; macd=20 macd_df = moving_average_conv_div(close) # Prevent truncating display of DataFrame pd.set_option('display.width', None) print(macd_df) # Extract data to plot close_price = close ema_f = macd_df['EMA_fast'] ema_s = macd_df['EMA_slow'] macd = macd_df['MACD'] ema_macd = macd_df['EMA_MACD'] macd_histogram = macd_df['MACD_histogram'] # Plot the data fig = plt.figure() ax1 = fig.add_subplot(311, ylabel='Google price in $') close_price.plot(ax=ax1, color='g', lw=2.0, legend=True) ema_f.plot(ax=ax1, color='b', lw=2.0, legend=True) ema_s.plot(ax=ax1, color='r', lw=2.0, legend=True) ax2 = fig.add_subplot(312, ylabel='MACD') macd.plot(ax=ax2, color='k', lw=2.0, legend=True) ema_macd.plot(ax=ax2, color='g', lw=2.0, legend=True) ax3 = fig.add_subplot(313, ylabel='MACD') macd_histogram.plot(ax=ax3, color='r', kind='bar', legend=True, use_index=False) ax1.grid() ax2.grid() plt.show()
def main(): # Prevent truncating display of DataFrame pd.set_option('display.width', None) goog_data = data.get_google_data('data/goog_data.pkl', start_date='2001-01-01', end_date='2018-01-01') # Naive momentum based trading strategy ts = signals.naive_momentum_trading(goog_data, 5) print('Naive momentum based trading strategy:') print(ts) # Plot the adjusted close price fig = plt.figure() ax1 = fig.add_subplot(111, ylabel='Google price in $') goog_data['Adj Close'].plot(ax=ax1, color='g', lw=0.5, label='Price') # Plot buy order ax1.plot(ts.loc[ts.orders == 1.0].index, goog_data['Adj Close'][ts.orders == 1], '^', markersize=7, color='k', label='Buy') # Plot sell order ax1.plot(ts.loc[ts.orders == -1.0].index, goog_data['Adj Close'][ts.orders == -1], 'v', markersize=7, color='k', label='Sell') plt.legend() plt.title('Naive Momentum Trading Strategy') plt.grid() plt.show()
def main(): # Get GOOG data from Yahoo Finance from 2001-01-01 to 2018-01-01 start_date = '2001-01-01' goog_data_file = 'data/goog_data_large.pkl' goog_data = get_google_data(goog_data_file, start_date=start_date) print(goog_data) # Calculate the average monthly percentage change of the daily adjusted # close price. goog_monthly_return = goog_data['Adj Close'].pct_change().groupby([ goog_data['Adj Close'].index.year, goog_data['Adj Close'].index.month ]).mean() goog_monthly_return_list = [] for i in range(len(goog_monthly_return)): goog_monthly_return_list.append({ 'month': goog_monthly_return.index[i][1], 'monthly_return': goog_monthly_return[i] }) goog_monthly_return_df = pd.DataFrame(goog_monthly_return_list, columns=['month', 'monthly_return']) print(goog_monthly_return_df) goog_monthly_return_df.boxplot(column='monthly_return', by='month') ax = plt.gca() labels = [ 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec' ] ax.set_xticklabels(labels) ax.set_ylabel('GOOG return') plt.title('GOOG Monthly Return 2001-2018') plt.suptitle('') # With trend plot_rolling_statistics_ts( goog_monthly_return, 'GOOG prices rolling mean and standard deviation', 'Monthly return') plot_rolling_statistics_ts( goog_data['Adj Close'], 'GOOG prices rolling mean and standard deviation', 'Daily prices', 365) # Without trend (stationary) plot_stationary_ts(goog_data['Adj Close'], 'GOOG prices without trend', 'Daily prices', window_size=365) # Augmented Dickey-Fuller test df = augmented_dickey_fuller(goog_data['Adj Close']) print('Augmented Dickey-Fuller test for adjusted close price:') print(df) df = augmented_dickey_fuller(goog_monthly_return) print('Augmented Dickey-Fuller test for monthly return:') print(df) # Forecast time series using Auto-Regression Integrated Moving Averages # (ARIMA) model plt.figure() plt.subplot(211) # Plot autocorrelation function (ACF) for monthly returns plot_acf(goog_monthly_return, ax=plt.gca(), lags=10) # Plot partial autocorrelation function (PACF) for monthly returns plt.subplot(212) plot_pacf(goog_monthly_return, ax=plt.gca(), lags=10) # The Autoregressive term AR(p) is the number of lags of dependent variable. # The lag value is p=1 when the PACF crosses the upper confidence interval # for the first time. # The Moving Average term MA(q) is the number of lags for errors in # prediction; error = (moving average) - (actual value) # The lag value is q=1 when the ACF plot crosses the upper confidence # interval for the first time. model = ARIMA(goog_monthly_return, order=(2, 0, 2)) fitted_results = model.fit() plt.figure() goog_monthly_return.plot(label='GOOG Monthly Return $', lw=0.5) fitted_results.fittedvalues.plot(label='Forecast', color='red') plt.grid() plt.legend() plt.show()
def main(): # Prevent truncating display of DataFrame pd.set_option('display.width', None) # Get daily trading data for 4 years SYMBOL = 'GOOG' goog_data = data.get_google_data(f'data/{SYMBOL}_data.pkl', start_date='2014-01-01', end_date='2018-01-01') # Use close price for this analysis close = goog_data.loc[:, 'Close'] # Preliminary analysis # Calculate and plot SMA to determine average SMA standard deviation # To avoid complications with stock split, we only take dates without # splits. Therefore only keep 620 days. sma_time_periods = 20 # look back period avg_std_dev = signals.avg_sma_std_dev(close, tail=620, sma_time_periods=sma_time_periods) print(f'\nAverage stdev of prices SMA over {sma_time_periods} day ' f'look back period: {avg_std_dev}') # Average standard deviation of prices SMA over look back period avg_std_dev = 15 print(f'\nApproximate average stdev of prices SMA over ' f'{sma_time_periods} day look back period: {avg_std_dev}') # Constants defining strategy behaviour/thresholds # APO trading signal value above which to enter buy orders/long position apo_value_for_buy_entry = 10 # APO trading signal value below which to enter sell orders/short position apo_value_for_sell_entry = -10 # Minimum price change since last trade before considering trading again. # This is to prevent over trading at around same prices min_price_move_from_last_trade = 10 # Number of shares to buy/sell on every trade num_shares_per_trade = 10 # Minimum open/unrealised profit at which to close and lock profits min_profit_to_close = 10 * num_shares_per_trade # Exponential moving average time periods for APO calculation ema_time_period_fast = 10 ema_time_period_slow = 40 # Calculate trading strategy print('\nTrading strategy:') df = signals.volatility_trend_following( close, sma_time_periods, avg_std_dev, ema_time_period_fast, ema_time_period_slow, apo_value_for_buy_entry, apo_value_for_sell_entry, min_price_move_from_last_trade, num_shares_per_trade, min_profit_to_close) # Visualise plotting.visualise(df, apo_value_for_buy_entry, apo_value_for_sell_entry, num_shares_per_trade) # Prepare DataFrame to save results to CSV goog_data = pd.concat([goog_data, df], axis=1) # Remove redundant close price column goog_data = goog_data.drop('ClosePrice', axis=1) goog_data.to_csv('ch05/volatility_trend_following.csv') # Display plots and block plt.show()
def main(): # Load Google finance data from Yahoo from 2014-01-01 to 2018-01-01 goog_data_raw = get_google_data() # To avoid complications with stock split, we only take dates without # splits. Therefore only keep 620 days. goog_data = goog_data_raw.tail(620) lows = goog_data['Low'] highs = goog_data['High'] # Plot the data fig = plt.figure() ax1 = fig.add_subplot(111, ylabel='Google price in $') highs.plot(ax=ax1, color='c', lw=2.0) lows.plot(ax=ax1, color='y', lw=2.0) # Plot resistance limit plt.hlines(highs.head(200).max(), lows.index.values[0], lows.index.values[-1], linewidth=2, color='g', label='Resistance') # Plot support limit plt.hlines(lows.head(200).min(), lows.index.values[0], lows.index.values[-1], linewidth=2, color='r', label='Support') plt.axvline(x=lows.index.values[200], linewidth=2, color='b', linestyle=':') plt.grid() plt.legend() # Support and Resistance Trading Strategy goog_data = goog_data_raw goog_data_signal = pd.DataFrame(index=goog_data.index) goog_data_signal['price'] = goog_data['Adj Close'] trading_support_resistance(goog_data_signal) fig = plt.figure() ax1 = fig.add_subplot(111, ylabel='Google price in $') # Plot support, resistance and price goog_data_signal['sup'].plot(ax=ax1, color='g', lw=2.0) goog_data_signal['res'].plot(ax=ax1, color='b', lw=2.0) goog_data_signal['price'].plot(ax=ax1, color='r', lw=2.0) ax1.plot(goog_data_signal.loc[goog_data_signal.positions == 1.0].index, goog_data_signal.price[goog_data_signal.positions == 1.0], '^', markersize=7, color='k', label='buy') ax1.plot(goog_data_signal.loc[goog_data_signal.positions == -1.0].index, goog_data_signal.price[goog_data_signal.positions == -1.0], 'v', markersize=7, color='k', label='sell') plt.legend() plt.grid() # Display plot and block plt.show()
def main(): # Prevent truncating display of DataFrame pd.set_option('display.width', None) # Get daily trading data for 4 years SYMBOL = 'GOOG' goog_data = data.get_google_data(f'data/{SYMBOL}_data.pkl', start_date='2014-01-01', end_date='2018-01-01') # Use close price for this analysis close = goog_data.loc[:, 'Close'] # Preliminary analysis # Calculate and plot SMA to determine average SMA standard deviation # To avoid complications with stock split, we only take dates without # splits. Therefore only keep 620 days. sma_time_periods = 20 # look back period avg_std_dev = signals.avg_sma_std_dev(close, tail=620, sma_time_periods=sma_time_periods) print(f'\nAverage stdev of prices SMA over {sma_time_periods} day ' f'look back period: {avg_std_dev}') # Average standard deviation of prices SMA over look back period avg_std_dev = 15 print(f'\nApproximate average stdev of prices SMA over ' f'{sma_time_periods} day look back period: {avg_std_dev}') # Constants defining strategy behaviour/thresholds # APO trading signal value below which to enter buy orders/long position apo_value_for_buy_entry = -10 # APO trading signal value above which to enter sell orders/short position apo_value_for_sell_entry = 10 # Minimum price change since last trade before considering trading again. # This is to prevent over trading at around same prices min_price_move_from_last_trade = 10 # Range of number of shares to buy/sell on every trade min_num_shares_per_trade = 1 max_num_shares_per_trade = 50 increment_num_shares_per_trade = 2 # Beginning number of shares to buy/sell on every trade num_shares_per_trade = min_num_shares_per_trade # Minimum open/unrealised profit at which to close and lock profits min_profit_to_close = 10 * num_shares_per_trade # Performance and risk limits risk_limit_weekly_stop_loss = -6000 increment_risk_limit_weekly_stop_loss = -12000 risk_limit_monthly_stop_loss = -15000 increment_risk_limit_monthly_stop_loss = -30000 risk_limit_max_positions = 5 increment_risk_limit_max_positions = 3 risk_limit_max_positions_holding_time_days = 120 * risk_limit_max_positions risk_limit_max_trade_size = 5 increment_risk_limit_max_trade_size = 2 # Exponential moving average time periods for APO calculation ema_time_period_fast = 10 ema_time_period_slow = 40 # Calculate trading strategy print('\nTrading strategy:') df = signals.volatility_mean_reversion_dynamic_risk( close, risk_limit_weekly_stop_loss, increment_risk_limit_weekly_stop_loss, risk_limit_monthly_stop_loss, increment_risk_limit_monthly_stop_loss, risk_limit_max_positions, increment_risk_limit_max_positions, risk_limit_max_positions_holding_time_days, risk_limit_max_trade_size, increment_risk_limit_max_trade_size, sma_time_periods, avg_std_dev, ema_time_period_fast, ema_time_period_slow, apo_value_for_buy_entry, apo_value_for_sell_entry, min_price_move_from_last_trade, min_num_shares_per_trade, max_num_shares_per_trade, increment_num_shares_per_trade, min_profit_to_close) # Visualise plotting.visualise(df, apo_value_for_buy_entry, apo_value_for_sell_entry, num_shares_per_trade) # Additional plots plt.figure() plt.title('Number of Shares and Maximum Trade Size') df['NumShares'].plot(color='b', lw=3.0) df['MaxTradeSize'].plot(color='g', lw=1.0) plt.legend() plt.grid() plt.figure() plt.title('Absolute and Maximum Positions') df['AbsPosition'].plot(color='b', lw=1.0) df['MaxPosition'].plot(color='g', lw=1.0) plt.legend() plt.grid() # Prepare DataFrame to save results to CSV goog_data = pd.concat([goog_data, df], axis=1) # Remove redundant close price column goog_data = goog_data.drop('ClosePrice', axis=1) goog_data.to_csv('ch06/volatility_mean_reversion_dynamic_risk.csv') # Display plots and block plt.show()
def main(): # Prevent truncating display of DataFrame pd.set_option('display.width', None) # Get GOOG data from Yahoo Finance from 2014-01-01 to 2018-01-01 goog_data = get_google_data() print('Raw GOOG data from Yahoo Finance:') print(goog_data) goog_data_signal = pd.DataFrame(index=goog_data.index) # Use the adjusted closing price of the stock which is closing price # adjusted for corporate actions. Takes into account stock splits and # dividends. goog_data_signal['price'] = goog_data['Adj Close'] # Signal based on price difference between consecutive days goog_data_signal['daily_difference'] = goog_data_signal['price'].diff() # Initialise signal column goog_data_signal['signal'] = 0.0 # Trading signal: If the daily price difference is positive (price has # increased) then set signal=1.0 (sell) else set signal=0.0 (buy) goog_data_signal['signal'][:] = \ np.where(goog_data_signal['daily_difference'][:] > 0, 1.0, 0.0) # Limit number of order by restricting to the number of positions on the # market to prevent constantly buying if the market keeps moving down, or # constantly selling when the market is moving up. Position is the # inventory of stocks or assets that we have on the market, e.g. if we # buy one Google share it means we have a position of one share on the # market. If we sell this share we will not have any positions on the # market. goog_data_signal['positions'] = goog_data_signal['signal'].diff() print('\nGoogle data signal:') print(goog_data_signal) # Plot the GOOG price fig = plt.figure() ax1 = fig.add_subplot(111, ylabel='Google price $') goog_data_signal['price'].plot(ax=ax1, color='r', lw=2.0) # Draw up arrow to indicate when we buy ax1.plot(goog_data_signal.loc[goog_data_signal.positions == 1.0].index, goog_data_signal.price[goog_data_signal.positions == 1.0], '^', markersize=5, color='m') # Draw a down arrow to indicate when we sell ax1.plot(goog_data_signal.loc[goog_data_signal.positions == -1.0].index, goog_data_signal.price[goog_data_signal.positions == -1.0], 'v', markersize=5, color='k') plt.grid() # Backtesting - relies on the assumption that the past predicts the future # Test the strategy with an initial capital over a given period of time. initial_capital = 1000.0 # Create DataFrame for the positions and the portfolio positions = pd.DataFrame(index=goog_data_signal.index).fillna(0.0) portfolio = pd.DataFrame(index=goog_data_signal.index).fillna(0.0) # Store GOOG positions positions['GOOG'] = goog_data_signal['signal'] # Store the amount of GOOG positions in $ for the portfolio portfolio['positions'] = \ positions.multiply(goog_data_signal['price'], axis=0) # Calculate the non-invested money (cash) portfolio['cash'] = \ initial_capital - (positions.diff().multiply(goog_data_signal['price'], axis=0)).cumsum() # Total investment is sum of positions in $ and cash portfolio['total'] = portfolio['positions'] + portfolio['cash'] portfolio.plot() # Plot portfolio total value fig = plt.figure() ax1 = fig.add_subplot(111, ylabel='Portfolio value in $') portfolio['total'].plot(ax=ax1, lw=2.0) ax1.plot(portfolio.loc[goog_data_signal.positions == 1.0].index, portfolio.total[goog_data_signal.positions == 1.0], '^', markersize=10, color='m') ax1.plot(portfolio.loc[goog_data_signal.positions == -1.0].index, portfolio.total[goog_data_signal.positions == -1.0], 'v', markersize=10, color='k') plt.grid() # Display plots and block plt.show()