class MoneyFlowIndex(IAlgorithm): def ws_open(self, ws): self.ws.on_open(ws) # Stream minute bars self.ws.stream_minute_bars(self.symbol) def ws_close(self, ws): self.ws.on_close(ws) # Delete csv file file_manager.delete_file('temp_files/{}.csv'.format(self.symbol)) # Close plot's process if alive if self.p is not None: self.p.terminate() self.p.join() def ws_message(self, ws, message): # Liquidate position if market is closing soon if self.__market.is_market_closing(): self.close_position_before_market_close() # Close graphs if self.p is not None: self.p.terminate() self.p.join() return # Convert retrieved data to python dict message = json.loads(message) self.ws.on_message(ws, message) # Get the required data: close price, high, low, volume, time bar_data = message['data'] close_price = round(bar_data['c'], 2) close_time = datetime.fromtimestamp(int(str( bar_data['e'])[:-3])).strftime("%H:%M") high_price = round(bar_data['h'], 2) low_price = round(bar_data['l'], 2) volume = bar_data['v'] print(self.df[-14:]) # Calc MFI mfi = self.calc_mfi(self.df[-14:]) # New Entry new_entry = { 'Date': close_time, 'Close': close_price, 'High': high_price, 'Low': low_price, 'Volume': volume, 'buy_signal': np.nan, 'sell_signal': np.nan, 'MFI': mfi } # Get buy or sell signal self.buy_sell(new_entry) # Add Entry to file new_entry_str = '{},{},{},{},{},{},{},{}'.format( close_time, close_price, new_entry['High'], new_entry['Low'], new_entry['Volume'], new_entry['buy_signal'], new_entry['sell_signal'], mfi) # Add entry to file file_manager.append_to_file('temp_files/{}.csv'.format(self.symbol), new_entry_str) # Add entry to dataframe self.df = self.df.append(new_entry, ignore_index=True) # Print retrieved data + MFI print('{}\t{}\tMFI: {}'.format(close_time, close_price, mfi)) def __init__(self, mode): # In case of any errors self.error = False # Display Header display_header() # Bot mode self.mode = mode # Constants self.PERIOD = 14 self.HIGH = 80 self.LOW = 20 self.MFI_MARGIN = 3 # Assign variables self.symbol = enter_data() if self.mode == 'active': # Setup Plot plt.style.use('seaborn') self.fig, (self.ax1, self.ax2) = plt.subplots(2, 1) # Account references self.__orders = Orders() self.__account = Account() self.__market = Market() # Dataframe to store data self.df = pd.DataFrame() # Qty to purchase self.QTY = 1000 # Tracks position status self.in_position = False # Keeps track of the buying price self.buy_price = 0 # Init websocket self.ws = WebSocket(self) # Setup the plot's process self.p = Process(target=self.plot_live_graph) elif self.mode == 'test': self.hist_df = pd.DataFrame() self.mfi = None def retrieve_data(self): print("[Requesting Data]") # Create a csv file csv_file = CSVReadWrite("temp_files/{}.csv".format(self.symbol), "Date,Close,High,Low,Volume") if self.mode == 'active': bars_dict = bars.get_historical_data(self.symbol, 100, '1Min') if bars_dict: csv_file.write_file(bars_dict, 't', 'c', 'h', 'l', 'v') self.df = pd.read_csv('temp_files/{}.csv'.format(self.symbol)) self.df = self.df.set_index( pd.DatetimeIndex(self.df['Date'].values).strftime("%H:%M")) self.df['buy_signal'] = np.nan self.df['sell_signal'] = np.nan elif self.mode == 'test': bars_dict = bars.get_historical_data(self.symbol, 500, 'day') if bars_dict: csv_file.write_file(bars_dict, 't', 'c', 'h', 'l', 'v') # Get the data self.hist_df = pd.read_csv("temp_files/{}.csv".format( self.symbol)) self.hist_df = self.hist_df.set_index( pd.DatetimeIndex( self.hist_df['Date'].values).strftime("%Y:%m:%d")) def calc_mfi(self, data): # Calc typical price typical_price = (data['High'] + data['Low'] + data['Close']) / 3 # Calc Raw Money flow raw_money_flow = typical_price * data['Volume'] # Store the flows positive_flows = [] negative_flows = [] # Calculate the (+) and (-) money flows for i in range(1, len(typical_price)): if typical_price[i] > typical_price[i - 1]: positive_flows.append(raw_money_flow[i - 1]) negative_flows.append(0) elif typical_price[i] < typical_price[i - 1]: positive_flows.append(0) negative_flows.append(raw_money_flow[i - 1]) else: positive_flows.append(0) negative_flows.append(0) # Sum them up positive_flows_sum = sum(positive_flows) negative_flows_sum = sum(negative_flows) # Money Flow Ratio mfr = positive_flows_sum / negative_flows_sum # Calculate the Money Flow Index money_flow_index = 100 - (100 / (1 + mfr)) return money_flow_index def pre_calculate(self, data): # Calc typical price typical_price = (data['High'] + data['Low'] + data['Close']) / 3 # Calc Raw Money Flows rmf = typical_price * data['Volume'] # Calc + and - flows positive_flows = [] negative_flows = [] for i in range(1, len(typical_price)): if typical_price[i] > typical_price[i - 1]: positive_flows.append(rmf[i - 1]) negative_flows.append(0) elif typical_price[i] < typical_price[i - 1]: positive_flows.append(0) negative_flows.append(rmf[i - 1]) else: positive_flows.append(0) negative_flows.append(0) # Calc the sums of money flows within the time period positive_mf_sum = [] negative_mf_sum = [] for i in range(self.PERIOD - 1, len(positive_flows)): positive_mf_sum.append( sum(positive_flows[i + 1 - self.PERIOD:i + 1])) for i in range(self.PERIOD - 1, len(negative_flows)): negative_mf_sum.append( sum(negative_flows[i + 1 - self.PERIOD:i + 1])) self.mfi = 100 * ( np.array(positive_mf_sum) / (np.array(negative_mf_sum) + np.array(positive_mf_sum))) data['MFI'] = np.nan data['MFI'][14:] = self.mfi data.to_csv(r'temp_files/{}.csv'.format(self.symbol), index=False) def buy_sell(self, data): if data['MFI'] > self.HIGH - self.MFI_MARGIN: # Sell if self.in_position: if self.buy_price <= data['Close']: # Submit order t = Thread(target=self.__orders.submit_order, args=[self.symbol, self.QTY, 'sell']) t.start() # Change position status self.in_position = False # Add sell signal data['sell_signal'] = data['Close'] # Reset buy price self.buy_price = 0 # Wait for order to finish t.join() else: print('We bought at a higher price. Can\'t sell now.') else: print('Sell signal generated. No asset to sell.') elif data['MFI'] < self.LOW + self.MFI_MARGIN: # Buy if not self.in_position: # Submit order t = Thread(target=self.__orders.submit_order, args=[self.symbol, self.QTY, 'buy']) t.start() # Change position status self.in_position = True # Set buying price self.buy_price = data['Close'] # Add buy signal data['buy_signal'] = data['Close'] # Wait for order to finish t.join() else: print('Buy signal generated. Already in position.') def close_position_before_market_close(self): # Close position print("Market closing soon.") # Liquidate self.liquidate_position() print("[EXITING]") def liquidate_position(self): has_position = self.__account.has_position(self.symbol) if has_position[0]: print("[Liquidating]") side = 'sell' qty = abs(int(float(has_position[1].qty))) t = Thread(target=self.__orders.submit_order, args=[self.symbol, qty, side]) t.start() t.join() def buy_sell_historical(self, data): # Store buy and sell signals buy_signal = [] sell_signal = [] for i in range(len(data['MFI'])): if data['MFI'][i] > self.HIGH - self.MFI_MARGIN: buy_signal.append(np.nan) sell_signal.append(data['Close'][i]) elif data['MFI'][i] < self.LOW + self.MFI_MARGIN: buy_signal.append(data['Close'][i]) sell_signal.append(np.nan) else: buy_signal.append(np.nan) sell_signal.append(np.nan) return buy_signal, sell_signal def plot_hist_graph(self, data): print('[Drawing Graph]') plt.style.use("fivethirtyeight") fig, (ax1, ax2) = plt.subplots(2, 1) fig.suptitle('Money Flow Index') # Remove x ticks ax1.xaxis.set_ticks([]) ax2.xaxis.set_ticks([]) # Set labels for axis ax1.set_ylabel('{} price in $ (USD)'.format(self.symbol)) ax2.set_ylabel('MFI Values') # Remove grids ax1.grid(False) ax2.grid(False) # Disable the top and right axis ax1.spines['top'].set_visible(False) ax1.spines['right'].set_visible(False) ax2.spines['top'].set_visible(False) ax2.spines['right'].set_visible(False) # Change the color of the left and bottom axis ax1.spines['bottom'].set_color('gray') ax1.spines['left'].set_color('gray') ax2.spines['bottom'].set_color('white') ax2.spines['left'].set_color('white') # Plot prices and MFI ax1.plot(data.index, data['Close'], color='black', label="Close Price", alpha=0.5, lw=2) ax2.plot(data.index, data['MFI'], label='MFI', lw=2) # Draw buy and sell signals ax1.scatter(data.index, data['Buy'], color="green", label="Buy Signal", marker="^", alpha=1) ax1.scatter(data.index, data['Sell'], color="red", label="Sell signal", marker="v", alpha=1) # Draw limit lines ax2.axhline(10, color='red', linestyle='--', linewidth=2) ax2.axhline(20, color='green', linestyle='--', linewidth=2) ax2.axhline(80, color='green', linestyle='--', linewidth=2) ax2.axhline(90, color='red', linestyle='--', linewidth=2) ax2.axhline(y=(self.LOW + self.MFI_MARGIN), color='brown', linestyle='--', linewidth=1) ax2.axhline(y=(self.HIGH - self.MFI_MARGIN), color='brown', linestyle='--', linewidth=1) # Show legend ax1.legend(loc='upper left') # Shot plot plt.show() def plot_live_graph(self): self.fig.suptitle('Price of {} over time'.format(self.symbol)) ani = animation.FuncAnimation(self.fig, self.animate_graph) plt.show() def animate_graph(self, i): # Read file file_df = pd.read_csv('temp_files/{}.csv'.format(self.symbol)) # Clear and plot self.ax1.clear() self.ax2.clear() self.ax1.plot(file_df['Date'], file_df['Close'], color='orange', lw=3, alpha=0.7) self.ax2.plot(file_df['Date'], file_df['MFI'], color='black', lw=3, alpha=1.0) # Draw buy and sell signals self.ax1.scatter(file_df['Date'], file_df['buy_signal'], color='green', alpha=1.0, marker='^') self.ax1.scatter(file_df['Date'], file_df['sell_signal'], color='red', alpha=1.0, marker='v') # Draw horizontal limit lines self.ax2.axhline(y=self.HIGH, color='red', linestyle='--') self.ax2.axhline(y=self.LOW, color='green', linestyle='--') self.ax2.axhline(y=(self.HIGH - self.MFI_MARGIN), color='brown', linestyle='--') self.ax2.axhline(y=(self.LOW + self.MFI_MARGIN), color='brown', linestyle='--') # Remove x ticks self.ax1.set_xticks([]) self.ax2.set_xticks([]) # Remove grids self.ax1.grid(False) self.ax2.grid(False) # Set labels self.ax1.set_ylabel("Price of {} in $".format(self.symbol)) self.ax2.set_xlabel("Time") self.ax2.set_ylabel('MFI Values') def execute(self): if self.error: return if self.mode == 'active': # Cancel existing orders self.__orders.cancel_opened_orders() # Liquidate position if it exists self.liquidate_position() # Wait for market to open t = Thread(target=self.__market.await_market_open) t.start() t.join() print("[Market Opened]") # Retrieve historical data about the asset self.retrieve_data() # Calculate parameters self.pre_calculate(self.df) # Run socket in a thread t_socket = Thread(target=self.ws.connect_socket) t_socket.start() # # Run the plot's process # self.p.start() # Wait for socket to finish t_socket.join() elif self.mode == 'test': # Retrieve historical data self.retrieve_data() # Calculate metrics self.pre_calculate(self.hist_df) # Get buy and sell signals self.hist_df = self.hist_df[self.PERIOD:] self.hist_df['MFI'] = self.mfi self.hist_df['Buy'] = self.buy_sell_historical(self.hist_df)[0] self.hist_df['Sell'] = self.buy_sell_historical(self.hist_df)[1] # Plot historical graph self.plot_hist_graph(self.hist_df) # Delete the file file_manager.delete_file('{}.csv'.format(self.symbol), True)
class BollingerBands(IAlgorithm): def ws_open(self, ws): self.ws.on_open(ws) # Stream minute bars self.ws.stream_trades(self.symbol) def ws_close(self, ws): self.ws.on_close(ws) # Delete csv file file_manager.delete_file('temp_files/{}.csv'.format(self.symbol)) # Terminate process if still running if self.p is not None: self.p.terminate() self.p.join() def ws_message(self, ws, message): # Liquidate position if self.__market.is_market_closing(): self.close_position_before_market_close() # Close graphs if self.p is not None: self.p.terminate() self.p.join() return # Convert data to python dict message = json.loads(message) self.ws.on_message(ws, message) # Get the required data: close price bar_data = message['data'] close_price = bar_data['p'] self.counter += 1 # Add the received price in the list self.closes.append(close_price) # Calc metrics sma = self.calc_metrics()[0] std = self.calc_metrics()[1] upper = self.calc_metrics()[2] lower = self.calc_metrics()[3] if sma == 0 or std == 0 or upper == 0 or lower == 0: pass else: # New entry new_entry = { 'Date': self.counter, 'Close': close_price, 'SMA': sma, 'STD': std, 'Upper': upper, 'Lower': lower, 'buy_signal': np.nan, 'sell_signal': np.nan } # Get signal self.buy_sell(new_entry) # Add entry to file new_entry_str = '{},{},{},{},{},{},{},{}'.format( self.counter, close_price, new_entry['buy_signal'], new_entry['sell_signal'], new_entry['SMA'], new_entry['STD'], new_entry['Upper'], new_entry['Lower'] ) file_manager.append_to_file('temp_files/{}.csv'.format(self.symbol), new_entry_str) # Add entry to dataframe self.df = self.df.append(new_entry, ignore_index=True) # Print data on the screen print('{}\tPrice: ${}\tUpper band: {}\tLower band: {}'.format( self.counter, close_price, new_entry['Upper'], new_entry['Lower'] )) def calc_metrics(self): if len(self.closes) > 20: closes = self.closes[-20:] # Calc the STD sma = sum(closes) / self.PERIOD std = self.std(closes, sma) # Calc Upper band and lower band upper = sma + (2 * std) lower = sma - (2 * std) return sma, std, upper, lower else: return 0, 0, 0, 0 def std(self, data, mean): # Square deviations deviations = [(x - mean) ** 2 for x in data] # Variance variance = sum(deviations) / self.PERIOD return math.sqrt(variance) def __init__(self): # Period over which calculations will be made self.PERIOD = 20 # Display header display_header() # Enter asset self.symbol = enter_data() self.counter = 0 self.buy_price = 0 # Setup Plot plt.style.use('seaborn') self.fig, self.ax = plt.subplots() # Account references self.__orders = Orders() self.__account = Account() self.__market = Market() # Dataframe to store data self.df = pd.DataFrame() # Qty to purchase self.QTY = 3000 # Tracks position status self.in_position = False # Tracks the close prices self.closes = [] # Init websocket self.ws = WebSocket(self) # Setup the plot's process self.p = Process(target=self.plot_live_graph) def buy_sell(self, data): if data['Close'] > data['Upper']: # Sell! print('Sell signal!') if self.in_position: if data['Close'] - self.buy_price >= 0: # Run thread to submit order t = Thread(target=self.__orders.submit_order, args=[self.symbol, self.QTY, 'sell']) t.start() # Change position status self.in_position = False # Reset previous buy price self.buy_price = 0 # Add sell signal data['sell_signal'] = data['Close'] t.join() else: print('Can\'t sell now. We bought at a higher price.') else: print('Nothing to sell.') elif data['Close'] < data['Lower']: # Buy print('Buy signal!') if not self.in_position: # Run thread to submit order t = Thread(target=self.__orders.submit_order, args=[self.symbol, self.QTY, 'buy']) t.start() # Change position status self.in_position = True # Set the previous buy price self.buy_price = data['Close'] # Add buy signal data['buy_signal'] = data['Close'] t.join() else: print('Already in position.') def close_position_before_market_close(self): # Close position print("Market closing soon.") # Liquidate self.liquidate_position() print("[EXITING]") def liquidate_position(self): has_position = self.__account.has_position(self.symbol) if has_position[0]: print("[Liquidating].") side = 'sell' qty = abs(int(float(has_position[1].qty))) t_submit_order = Thread(target=self.__orders.submit_order, args=[self.symbol, qty, side]) t_submit_order.start() t_submit_order.join() def plot_live_graph(self): self.fig.suptitle("Price of {} over time".format(self.symbol)) ani = animation.FuncAnimation(self.fig, self.animate_graph) plt.show() def animate_graph(self, i): # Read file file_df = pd.read_csv('temp_files/{}.csv'.format(self.symbol)) if not file_df.empty: # Clear and plot self.ax.clear() self.ax.plot(file_df['Date'], file_df['Close'], alpha=0.5, linewidth=3) self.ax.plot(file_df['Date'], file_df['Upper'], alpha=0.5, linewidth=1) self.ax.plot(file_df['Date'], file_df['Lower'], alpha=0.5, linewidth=1) self.ax.plot(file_df['Date'], file_df['SMA'], alpha=0.5, linewidth=1) # Draw buy and sell signals self.ax.scatter(file_df['Date'], file_df['buy_signal'], marker='^', color='green', alpha=1.0) self.ax.scatter(file_df['Date'], file_df['sell_signal'], marker='v', color='red', alpha=1.0) # Set labels self.ax.set_ylabel("Price of {} in $".format(self.symbol)) self.ax.set_xlabel("Time") self.ax.tick_params(axis='x', rotation=45) plt.xticks(fontsize=5) def execute(self): # Cancel existing orders self.__orders.cancel_opened_orders() # Liquidate position if it exists self.liquidate_position() # Wait for market to open t = Thread(target=self.__market.await_market_open) t.start() t.join() print("[Market Opened]") # Setup file file = open('temp_files/{}.csv'.format(self.symbol), 'w') file.write('Date,Close,buy_signal,sell_signal,SMA,STD,Upper,Lower\n') file.close() # Run the web socket t_socket = Thread(target=self.ws.connect_socket) t_socket.start() # Run the plot's process self.p.start() # Wait for thread to finish work t_socket.join() # Delete file file_manager.delete_file('SPY.csv'.format(self.symbol), True)
class BollingerBands(IAlgorithm): def ws_open(self, ws): self.ws.on_open(ws) # Get the last 20 prices self.closes = list(self.df['Close'][-20:]) # Stream minute bars self.ws.stream_minute_bars(self.symbol) def ws_close(self, ws): self.ws.on_close(ws) # Delete csv file file_manager.delete_file('temp_files/{}.csv'.format(self.symbol)) # Terminate process if still running if self.p is not None: self.p.terminate() self.p.join() def ws_message(self, ws, message): # Liquidate position if self.__market.is_market_closing(): self.close_position_before_market_close() # Close graphs if self.p is not None: self.p.terminate() self.p.join() return # Convert data to python dict message = json.loads(message) self.ws.on_message(ws, message) # Get the required data: close price, date bar_data = message['data'] close_price = bar_data['c'] close_time = datetime.fromtimestamp(int(str( bar_data['e'])[:-3])).strftime("%H:%M") # Add the received price in the list self.closes.append(close_price) # Calc metrics sma = self.calc_metrics()[0] std = self.calc_metrics()[1] upper = self.calc_metrics()[2] lower = self.calc_metrics()[3] # New entry new_entry = { 'Date': close_time, 'Close': close_price, 'SMA': sma, 'STD': std, 'Upper': upper, 'Lower': lower, 'buy_signal': np.nan, 'sell_signal': np.nan } # Get signal self.buy_sell(new_entry) # Add entry to file new_entry_str = '\n{},{},{},{},{},{},{},{}'.format( close_time, close_price, new_entry['buy_signal'], new_entry['sell_signal'], new_entry['SMA'], new_entry['STD'], new_entry['Upper'], new_entry['Lower']) file_manager.append_to_file('temp_files/{}.csv'.format(self.symbol), new_entry_str) # Add entry to dataframe self.df = self.df.append(new_entry, ignore_index=True) # Print data on the screen print('{}\t{}\tUpper band: {}\tLower band: {}'.format( close_time, close_price, new_entry['Upper'], new_entry['Lower'])) def calc_metrics(self): closes = self.closes[-20:] # Calc the STD sma = sum(closes) / self.PERIOD std = self.std(closes, sma) # Calc Upper band and lower band upper = sma + (2 * std) lower = sma - (2 * std) return sma, std, upper, lower def std(self, data, mean): # Square deviations deviations = [(x - mean)**2 for x in data] # Variance variance = sum(deviations) / self.PERIOD return math.sqrt(variance) def __init__(self, mode): # Set bot mode self.mode = mode # In case something goes wrong self.error = False # Period over which calculations will be made self.PERIOD = 20 # Display header display_header() # Enter asset self.symbol = enter_data() if self.mode == 'active': # Setup Plot plt.style.use('seaborn') self.fig, self.ax = plt.subplots() # Account references self.__orders = Orders() self.__account = Account() self.__market = Market() # Dataframe to store data self.df = pd.DataFrame() # Qty to purchase self.QTY = 1000 # Track buy price self.buy_price = 0 # Tracks position status self.in_position = False # Tracks the close prices self.closes = [] # Init websocket self.ws = WebSocket(self) # Setup the plot's process self.p = Process(target=self.plot_live_graph) elif self.mode == 'test': # self.position = False self.hist_df = pd.DataFrame() def retrieve_data(self): # In case no error, write data to a file csv_file = CSVReadWrite("temp_files/{}.csv".format(self.symbol), "Date,Close") if self.mode == 'active': bars_dict = bars.get_historical_data(self.symbol, 100, '1Min') if bars_dict: csv_file.write_file(bars_dict, 't', 'c') self.df = pd.read_csv('temp_files/{}.csv'.format(self.symbol)) self.df = self.df.set_index( pd.DatetimeIndex(self.df['Date'].values).strftime("%H:%M")) self.df['buy_signal'] = np.nan self.df['sell_signal'] = np.nan else: self.error = True else: bars_dict = bars.get_historical_data(self.symbol, 500, 'day') if bars_dict: csv_file.write_file(bars_dict, 't', 'c') self.hist_df = pd.read_csv('temp_files/{}.csv'.format( self.symbol)) self.hist_df = self.hist_df.set_index( pd.DatetimeIndex( self.hist_df['Date'].values).strftime("%Y:%m:%d")) else: self.error = True def pre_calculate(self, data): # Calculate the Simple Moving Average data['SMA'] = data['Close'].rolling(window=self.PERIOD).mean() # Calculate the standard deviation data['STD'] = data['Close'].rolling(window=self.PERIOD).std() # Calculate the upper bands and the lower bands data['Upper'] = data['SMA'] + (2 * data['STD']) data['Lower'] = data['SMA'] - (2 * data['STD']) # Write to file data.to_csv(r'temp_files/{}.csv'.format(self.symbol), index=False) def buy_sell(self, data): if data['Close'] > data['Upper']: # Sell! print('Sell signal!') if self.in_position: if self.buy_price <= data['Close']: # Run thread to submit order t = Thread(target=self.__orders.submit_order, args=[self.symbol, self.QTY, 'sell']) t.start() # Change position status self.in_position = False # Reset buy price self.buy_price = 0 # Add sell signal data['sell_signal'] = data['Close'] # Wait for order to finish t.join() else: print('We bought at a higher price. Can\'t sell now.') else: print('Nothing to sell.') elif data['Close'] < data['Lower']: # Buy print('Buy signal!') if not self.in_position: # Run thread to submit order t = Thread(target=self.__orders.submit_order, args=[self.symbol, self.QTY, 'buy']) t.start() # Change position status self.in_position = True # Set buy price self.buy_price = data['Close'] # Add buy signal data['buy_signal'] = data['Close'] # Wait for order to finish t.join() else: print('Already in position.') def buy_sell_historical(self, data): buy_signal = [] sell_signal = [] for i in range(len(data['Close'])): if data['Close'][i] >= data['Upper'][i]: # Sell buy_signal.append(np.nan) sell_signal.append(data['Close'][i]) elif data['Close'][i] <= data['Lower'][i]: # Buy buy_signal.append(data['Close'][i]) sell_signal.append(np.nan) else: # Do nothing buy_signal.append(np.nan) sell_signal.append(np.nan) return buy_signal, sell_signal def close_position_before_market_close(self): # Close position print("Market closing soon.") # Liquidate self.liquidate_position() print("[EXITING]") def liquidate_position(self): has_position = self.__account.has_position(self.symbol) if has_position[0]: print("[Liquidating].") side = 'sell' qty = abs(int(float(has_position[1].qty))) t_submit_order = Thread(target=self.__orders.submit_order, args=[self.symbol, qty, side]) t_submit_order.start() t_submit_order.join() def plot_hist_graph(self, data): plt.style.use('fivethirtyeight') fig = plt.figure(figsize=(12.2, 6.4), facecolor='white') # Add the subplot ax = fig.add_subplot(111) ax.xaxis.set_ticks([]) # Change the color of the left and bottom axis ax.spines['bottom'].set_color('gray') ax.spines['left'].set_color('gray') # Get the index values x_axis = data.index # Remove grid ax.grid(False) # Disable the top and right axis ax.spines['top'].set_visible(False) ax.spines['right'].set_visible(False) # Plot the bands ax.plot(x_axis, data['Upper'], color='brown', lw=1, label='Upper', alpha=0.5) ax.plot(x_axis, data['Lower'], color='brown', lw=1, label='Lower', alpha=0.5) # Plot the closing price and the moving average ax.plot(x_axis, data['Close'], color='black', lw=3, label='Close Price', alpha=0.5) ax.plot(x_axis, data['SMA'], color='blue', lw=1, label='Simple Moving Average') # Add the buy and sell signals ax.scatter(x_axis, data['Buy'], label='Buy', alpha=1, color='green', marker='^') ax.scatter(x_axis, data['Sell'], label='Sell', alpha=1, color='red', marker='v') # Set the title and show the plot ax.set_title("Bollinger Bands for {}".format(self.symbol), color='black') ax.set_ylabel('USD Price ($)', color='black') ax.set_xlabel('Time', color='black') plt.xticks(rotation=45, fontsize=7) ax.legend(loc='upper left', framealpha=0.2, fancybox=True) plt.show() def plot_live_graph(self): self.fig.suptitle("Price of {} over time".format(self.symbol)) ani = animation.FuncAnimation(self.fig, self.animate_graph) plt.show() def animate_graph(self, i): # Read file file_df = pd.read_csv('temp_files/{}.csv'.format(self.symbol)) # Clear and plot self.ax.clear() self.ax.plot(file_df['Date'], file_df['Close'], linewidth=3) self.ax.plot(file_df['Date'], file_df['Upper'], linewidth=1) self.ax.plot(file_df['Date'], file_df['Lower'], linewidth=1) self.ax.plot(file_df['Date'], file_df['SMA'], linewidth=1) # Draw buy and sell signals self.ax.scatter(file_df['Date'], file_df['buy_signal'], marker='^', color='green', alpha=1.0) self.ax.scatter(file_df['Date'], file_df['sell_signal'], marker='v', color='red', alpha=1.0) # Set labels self.ax.set_ylabel("Price of {} in $".format(self.symbol)) self.ax.xaxis.set_ticks([]) def execute(self): if self.error: print('Error occurred') return if self.mode == 'active': # Cancel existing orders self.__orders.cancel_opened_orders() # Liquidate position if it exists self.liquidate_position() # Wait for market to open t = Thread(target=self.__market.await_market_open) t.start() t.join() print("[Market Opened]") # Retrieve historical data about the asset self.retrieve_data() # Calculate parameters self.pre_calculate(self.df) # Run the web socket t_socket = Thread(target=self.ws.connect_socket) t_socket.start() # Run the plot's process self.p.start() # Wait for thread to finish work t_socket.join() elif self.mode == 'test': # Retrieve historical data self.retrieve_data() # Calculate metrics self.pre_calculate(self.hist_df) # Get buy and sell signals self.hist_df = self.hist_df[self.PERIOD - 1:] self.hist_df['Buy'] = self.buy_sell_historical(self.hist_df)[0] self.hist_df['Sell'] = self.buy_sell_historical(self.hist_df)[1] # Plot the graph self.plot_hist_graph(self.hist_df) # Delete csv file file_manager.delete_file('{}.csv'.format(self.symbol), True)
class DualAverageCrossover(IAlgorithm): def ws_open(self, ws): self.ws.on_open(ws) # Get the last 100 prices self.closes = list(self.df['Close'])[-100:] # Stream minute bars self.ws.stream_minute_bars(self.symbol) def ws_close(self, ws): self.ws.on_close(ws) # Delete csv file file_manager.delete_file('temp_files/{}.csv'.format(self.symbol)) # Terminate process if still running if self.p is not None: self.p.terminate() self.p.join() def ws_message(self, ws, message): # Liquidate position if self.__market.is_market_closing(): self.close_position_before_market_close() # Close graphs if self.p is not None: self.p.terminate() self.p.join() return # Convert data to python dict message = json.loads(message) self.ws.on_message(ws, message) # Get the required data: time, close price bar_data = message['data'] close_price = bar_data['c'] close_time = datetime.fromtimestamp(int(str( bar_data['e'])[:-3])).strftime("%H:%M") # Add the received price in the list self.closes.append(close_price) # Calc metrics sma30 = self.calc_metrics()[0] sma100 = self.calc_metrics()[1] # New Entry new_entry = { 'Date': close_time, 'Close': close_price, 'SMA30': sma30, 'SMA100': sma100, 'buy_signal': np.nan, 'sell_signal': np.nan } # Get Signal self.buy_sell(new_entry) # Add Entry to file new_entry_str = '{},{},{},{},{},{} '.format(close_time, close_price, new_entry['buy_signal'], new_entry['sell_signal'], sma30, sma100) file_manager.append_to_file('temp_files/{}.csv'.format(self.symbol), new_entry_str) # Add entry to dataframe self.df = self.df.append(new_entry, ignore_index=True) # Print data on the screen print('{}\tPrice: {}\tSMA30: {}\tSMA100: {}'.format( close_time, close_price, new_entry['SMA30'], new_entry['SMA100'])) def calc_metrics(self): closes = self.closes[-100:] sma30 = sum(closes[-30:]) / 30 sma100 = sum(closes) / 100 return sma30, sma100 def __init__(self, mode): # In case of any error self.error = False # Bot mode self.mode = mode # Display Header display_header() self.symbol = enter_data() if self.mode == 'active': # Setup Plot plt.style.use('seaborn') self.fig, self.ax = plt.subplots() # Account references self.__orders = Orders() self.__account = Account() self.__market = Market() # Dataframe to store data self.df = pd.DataFrame() # Qty to purchase self.QTY = 50 # Tracks position status self.in_position = False # Tracks the close prices self.closes = [] # Init websocket self.ws = WebSocket(self) # Track buy price self.buy_price = 0 # Setup the plot's process self.p = Process(target=self.plot_live_graph) elif self.mode == 'test': self.hist_df = pd.DataFrame() else: print('Weird!') def retrieve_data(self): # Retrieve bars from API print("[Requesting Data]") # Create CSV File csv_file = CSVReadWrite("temp_files/{}.csv".format(self.symbol), "Date,Close") if self.mode == 'active': bars_dict = bars.get_historical_data(self.symbol, 200, '1Min') if bars_dict: csv_file.write_file(bars_dict, 't', 'c') self.df = pd.read_csv('temp_files/{}.csv'.format(self.symbol)) self.df = self.df.set_index( pd.DatetimeIndex(self.df['Date'].values).strftime("%H:%M")) self.df['buy_signal'] = np.nan self.df['sell_signal'] = np.nan else: self.error = True elif self.mode == 'test': bars_dict = bars.get_historical_data(self.symbol, 400, 'day') if bars_dict: csv_file.write_file(bars_dict, 't', 'c') self.hist_df = pd.read_csv('temp_files/{}.csv'.format( self.symbol)) self.hist_df = self.hist_df.set_index( pd.DatetimeIndex(self.hist_df['Date'].values)) else: self.error = True def pre_calculate(self, data): # Calculate SMA30 data['SMA30'] = data['Close'].rolling(window=30).mean() # Calculate SMA100 data['SMA100'] = data['Close'].rolling(window=100).mean() # Write to file data.to_csv(r'temp_files/{}.csv'.format(self.symbol), index=False) def buy_sell(self, data): if data['SMA30'] > data['SMA100']: # Sell if self.in_position: if self.buy_price <= data['Close']: # Submit order t = Thread(target=self.__orders.submit_order, args=[self.symbol, self.QTY, 'sell']) t.start() # Change position status self.in_position = False # Add sell signal data['sell_signal'] = data['Close'] # Reset buy price self.buy_price = 0 # Wait for order to finish t.join() else: print('We bought at a higher price. Can\'t sell now.') else: print('Sell signal generated. No asset to sell.') elif data['SMA100'] < data['SMA30']: # Buy if not self.in_position: # Submit order t = Thread(target=self.__orders.submit_order, args=[self.symbol, self.QTY, 'buy']) t.start() # Change position status self.in_position = True # Add buy signal data['buy_signal'] = data['Close'] # Set buy price self.buy_price = data['Close'] # Wait for order to finish t.join() def liquidate_position(self): has_position = self.__account.has_position(self.symbol) if has_position[0]: print("[Closing Position].") side = 'sell' qty = abs(int(float(has_position[1].qty))) t_submit_order = Thread(target=self.__orders.submit_order, args=[self.symbol, qty, side]) t_submit_order.start() t_submit_order.join() def close_position_before_market_close(self): # Close position print("Market closing soon.") # Liquidate self.liquidate_position() print("[EXITING]") exit() def buy_sell_historical(self, data): print("[Executing Algo]") buy_signal = [] sell_signal = [] crossed = -1 for i in range(len(data)): if data['SMA30'][i] > data['SMA100'][i]: if crossed != 1: sell_signal.append(data['Close'][i]) buy_signal.append(np.nan) crossed = 1 else: sell_signal.append(np.nan) buy_signal.append(np.nan) elif data['SMA30'][i] < data['SMA100'][i] and crossed == 1: if crossed != 0: sell_signal.append(np.nan) buy_signal.append(data['Close'][i]) crossed = 0 else: sell_signal.append(np.nan) buy_signal.append(np.nan) else: sell_signal.append(np.nan) buy_signal.append(np.nan) return buy_signal, sell_signal def plot_hist_graph(self, data): print("[Drawing Graph]") plt.style.use("fivethirtyeight") fig, ax = plt.subplots(1, 1, facecolor='black') fig.suptitle('Dual Moving Averages Crossover', color='white') # Disable the grid ax.grid(False) # Set background color and change axis values color ax.set_facecolor('black') ax.tick_params(axis='x', colors='white') ax.tick_params(axis='y', colors='white') ax.set_ylabel('{} price in $ (USD)'.format(self.symbol), color='white') # Disable the top and right axis ax.spines['top'].set_visible(False) ax.spines['right'].set_visible(False) # Change the color of the left and bottom axis ax.spines['left'].set_color('gray') ax.spines['bottom'].set_color('gray') # Plot asset prices ax.plot(data['Close'], label='Close Prices', color='orange', alpha=0.5, linewidth=2) # Plot SMA30 and SMA100 ax.plot(data['SMA30'], label='SMA30', color='brown', alpha=0.4, linewidth=1) ax.plot(data['SMA100'], label='SMA100', color='brown', alpha=0.4, linewidth=1) # Draw buy and sell signals ax.scatter(data.index, data['Buy'], label='Buy', marker='^', color='green') ax.scatter(data.index, data['Sell'], label='Sell', marker='v', color='red') ax.legend(loc='upper left') plt.xticks(rotation=45, fontsize=7) plt.show() def plot_live_graph(self): self.fig.suptitle("Dual Moving Averages Crossover") ani = animation.FuncAnimation(self.fig, self.animate_graph) plt.show() def animate_graph(self, i): # Read file file_df = pd.read_csv('temp_files/{}.csv'.format(self.symbol)) # Clear and plot self.ax.clear() self.ax.plot(file_df['Date'], file_df['Close'], label='Close Price', color='black', lw=2) self.ax.plot(file_df['Date'], file_df['SMA30'], label='SMA30', color='red', lw=1) self.ax.plot(file_df['Date'], file_df['SMA100'], label='SMA100', color='blue', lw=1) # Draw buy and sell signals self.ax.scatter(file_df['Date'], file_df['buy_signal'], label='Buy Signal', color='green', alpha=1.0, marker='^') self.ax.scatter(file_df['Date'], file_df['sell_signal'], label='Sell Signal', color='red', alpha=1.0, marker='v') # Remove grid self.ax.grid(False) self.ax.xaxis.set_ticks([]) # Show the legend self.ax.legend(loc='upper left') # Set labels self.ax.set_ylabel('Close Price of {} in $'.format(self.symbol)) def execute(self): if self.error: # Delete csv file file_manager.delete_file('temp_files/{}.csv'.format(self.symbol)) return if self.mode == 'active': # Cancel existing orders self.__orders.cancel_opened_orders() # Liquidate position if it exists self.liquidate_position() # Wait for market to open t = Thread(target=self.__market.await_market_open) t.start() t.join() print("[Market Opened]") # Retrieve historical data about the asset self.retrieve_data() # Calculate metrics self.pre_calculate(self.df) # Start algo in a thread t_socket = Thread(target=self.ws.connect_socket) t_socket.start() # Run the plot's process self.p.start() # Wait for socket to close t_socket.join() elif self.mode == 'test': # Retrieve historical data self.retrieve_data() # Calculate Metrics self.pre_calculate(self.hist_df) # Get buy and sell signals self.hist_df = self.hist_df[99:] self.hist_df['Buy'] = self.buy_sell_historical(self.hist_df)[0] self.hist_df['Sell'] = self.buy_sell_historical(self.hist_df)[1] # Plot graph self.plot_hist_graph(self.hist_df) # Delete CSV File file_manager.delete_file('{}.csv'.format(self.symbol), True)