def backtest_obv_strategy(args): # If no symbols were passed in # Retrieve top active stocks from Yahoo Finance try: symbols = args[1].split(',') except IndexError: print('No symbol(s) provided. Retrieving top 10 from Yahoo Finance...') symbols = get_10_best_active_stocks() portfolio_amount = portfolio_input('Enter cash amount to give each stock: ') try: splices = args[2].split(',') except IndexError: splices = ['year1month1'] interval = '5min' results = {} print('\nBACKTESTING CONFIRMATION:') print('----------------------------------') print(f'Cash: $%.2f' % float(portfolio_amount)) print(f"Stocks: {', '.join(symbols)}") print(f"Splices: {', '.join(splices)}") print(f'Interval: {interval}') print('----------------------------------') confirmation = input('Continue? (Y/n): ') if confirmation.lower() != 'y': return for splice in splices: results[splice] = {} total_cash = 0 for symbol in symbols: print('===================================') historic_data = get_stock_data(symbol, interval, splice) if type(historic_data) is not pd.DataFrame: print(f'Error: {symbol} not found.\n') continue print(f'Trading {symbol} using {interval} intervals...') cash = float(portfolio_amount) results[splice][symbol] = {} Transactions = {} transaction_holder = {} position = None stop_loss_price = None initial_loss_percentage = 0.98 trailing_loss_percentage = 0.96 for i in range(0, len(historic_data.index)): datetime = historic_data.index[i] interval_date, interval_time = str(datetime).split(' ') if interval_date not in Transactions.keys(): Transactions[interval_date] = [] if is_market_open(historic_data.index[i]): close_price = historic_data['close'][datetime] obv = historic_data['OBV'][datetime] obv_ema = historic_data['OBV_EMA'][datetime] if not position and obv > obv_ema: shares = math.floor(cash / close_price) transaction_holder = { 'Buy': close_price, 'Buy Time': interval_time, 'Quantity': shares } position = close_price stop_loss_price = close_price * initial_loss_percentage # print(f'Buy triggered by: {obv} > {obv_ema}') # print(f'Buy {shares} shares on {interval_date} at {interval_time}: $%.2f' % close_price) # print('Set stop loss to $%.2f' % stop_loss_price) # If at least 2 indicators from the last 3 intervals tell it to sell elif position and obv < obv_ema: transaction_holder['Sell'] = close_price transaction_holder['Sell Time'] = interval_time Transactions[interval_date].append(transaction_holder) # print(f'Sell triggered by: {obv} < {obv_ema}') # print(f'Sell on {interval_date} at {interval_time}: $%.2f' % close_price) net_profit = (close_price * transaction_holder['Quantity']) - (transaction_holder['Buy'] * transaction_holder['Quantity']) percentage = ((close_price - transaction_holder['Buy']) / transaction_holder['Buy']) * 100 # print('Profit/Loss: ${0} ({1}%)\n'.format(('%.2f' % net_profit), ('%.2f' % percentage))) position = None transaction_holder = {} # Sell if its holding and the price has dropped to our stop loss elif position and close_price <= stop_loss_price: transaction_holder['Sell'] = close_price transaction_holder['Sell Time'] = interval_time Transactions[interval_date].append(transaction_holder) # print('Sell triggered by stop loss $%.2f' % stop_loss_price) # print(f'SL Sell on {interval_date} at {interval_time}: $%.2f' % close_price) net_profit = (close_price * transaction_holder['Quantity']) - (transaction_holder['Buy'] * transaction_holder['Quantity']) percentage = ((close_price - transaction_holder['Buy']) / transaction_holder['Buy']) * 100 # print('Profit/Loss: ${0} ({1}%)\n'.format(('%.2f' % net_profit), ('%.2f' % percentage))) position = None transaction_holder = {} # Update trailing stop loss if price is rising elif position and close_price > position and (close_price * trailing_loss_percentage) > stop_loss_price: position = close_price stop_loss_price = close_price * trailing_loss_percentage # print('Updated trailing stop loss to $%.2f' % stop_loss_price) # If the market's about to close, sell remaining positions if position and interval_time == '15:59:00': transaction_holder['Sell'] = close_price transaction_holder['Sell Time'] = interval_time Transactions[interval_date].append(transaction_holder) # print('Sell triggered by market closing') # print(f'MC Sell on {interval_date} at {interval_time}: $%.2f' % close_price) net_profit = (close_price * transaction_holder['Quantity']) - (transaction_holder['Buy'] * transaction_holder['Quantity']) percentage = ((close_price - transaction_holder['Buy']) / transaction_holder['Buy']) * 100 # print('Profit/Loss: ${0} ({1}%)\n'.format(('%.2f' % net_profit), ('%.2f' % percentage))) position = None transaction_holder = {} # Check for end of day elif interval_time == '16:00:00': # Calculate total results for the day day_profits = 0 if len(Transactions[interval_date]) > 0: for transaction in Transactions[interval_date]: num_shares = transaction['Quantity'] buy = transaction['Buy'] sell = transaction['Sell'] day_profits += (sell * num_shares) - (buy * num_shares) updated_cash = cash + day_profits profit_percent = ((updated_cash - cash) / cash) * 100 results[splice][symbol][interval_date] = profit_percent cash = updated_cash # Display day result print('{0}: {1}% (${2}), balance: ${3}'.format(interval_date, ('%.2f' % profit_percent), ('%.2f' % day_profits), '%.2f' % cash)) total_cash += cash print() # plot.figure(figsize=(15, 6)) # plot.bar(results[splice][symbol].keys(), results[splice][symbol].values()) # plot.title(f'{symbol} Results') # plot.xlabel('Date') # plot.xticks(rotation = 60) # plot.ylabel('Net % Gain') # plot.show() # input('hit Enter to test next symbol') # END SYMBOLS LOOP # Calculate total percentages for all days in splice cash = float(portfolio_amount) splice_percents = [] for symbol in results[splice].keys(): splice_percent = 0 for date in results[splice][symbol].keys(): splice_percent += results[splice][symbol][date] cash *= 1 + (splice_percent / 100) splice_percents.append(splice_percent) # plot.figure(figsize=(15, 6)) # plot.bar(results[splice].keys(), splice_percents) # plot.title(f'Backtesting Results') # plot.xlabel('Symbol') # plot.xticks(rotation = 45) # plot.ylabel('Net % Gain') # plot.show() print(f'{splice} SUMMARY:') original_cash = float(portfolio_amount) * len(results[splice].keys()) print('${0} --> ${1}'.format('%.2f' % original_cash, '%.2f' % total_cash)) print('{}% return'.format('%.2f' % ((total_cash - original_cash) / original_cash * 100)))
for symbol_string in symbol_strings: batch_api_url = f"https://sandbox.iexapis.com/stable/stock/market/batch/?symbols={symbol_string}&types=quote&token={IEX_CLOUD_API_TOKEN}" data = requests.get(batch_api_url).json() for symbol in symbol_string.split(','): final_dataframe = final_dataframe.append(pd.Series([ symbol, data[symbol]['quote']['latestPrice'], data[symbol]['quote']['peRatio'], 'N/A' ], index=columns), ignore_index=True) # Select 50 best value stocks final_dataframe.sort_values('Price-to-Earnings Ratio', inplace=True) final_dataframe = final_dataframe[ final_dataframe['Price-to-Earnings Ratio'] >= 0] final_dataframe = final_dataframe[:50] final_dataframe.reset_index(drop=True, inplace=True) ######################################################################## ################# Calculate the amount of shares to buy ################ ######################################################################## portfolio_size = portfolio_input() position_size = float(portfolio_size) / len(final_dataframe.index) for i in final_dataframe.index: final_dataframe.loc[i, 'Number of Shares to Buy'] = math.floor( position_size / final_dataframe.loc[i, 'Price']) print(final_dataframe)
holdings[symbol] = transaction results[symbol] = total_profits # END SYMBOL LOOP # Display results print(f'\nTOTAL GAINS ON {trading_day}:') updated_portfolio = portfolio for symbol in results.keys(): updated_portfolio += results[symbol] print(f'{symbol}: $%.2f' % results[symbol]) print() print('On {0}, I turned ${1} into ${2}'.format( trading_day, ('%.2f' % portfolio), ('%.2f' % updated_portfolio))) if len(holdings.keys()) > 0: print("I'm still holding:") for symbol in holdings.keys(): print(f'{symbol}: $%.2f' % (holdings[symbol]['Quantity'] * holdings[symbol]['Buy'])) plot.figure(figsize=(15, 6)) plot.bar(results.keys(), results.values()) plot.title(f'Results from {trading_day}') plot.xlabel('Symbols') plot.ylabel('Net Gain/Loss ($)') plot.show() obv_strategy(sys.argv, portfolio_input())