def plot(ticker_columns): """ Args: ticker_columns (list): Tickers and ticker columns to plot. This argument must be an iterable on the format: [[instrument_ticker_a, column_name_a], [instrument_ticker_b, column_name_b], ...] """ # create linked_plot() arguments l = [] for instrument_name, column_name in ticker_columns: instrument = get_instrument(instrument_name.upper()) plot_title = instrument_name.upper() + "_" + column_name l.append((instrument.data, column_name, plot_title)) # create the plot linked_plot(l)
def get_instrument(self, ticker): """ Get an altered version of the instrument which only contains date up till today. Args: ticker(str): Ticker name Return: A deepcopied version of the Instrument object """ # get a copy of the Instrument object which we can modify instrument = deepcopy(get_instrument(ticker)) row_index = instrument.get_day_index(self.today) # delete data which is into the future and the strategy now nothing of instrument.data = np.delete(instrument.data, np.s_[row_index + 1:]) return instrument
def get_value(self, date): """ Get the closing value of an instrument at a given date The closing value will be used if it exists, otherwise the 'value' field will be used. Nasdaq OMX data typical doesn't have closing values. Args: date(datetime.date): Date to get value for Return: The monetary value of the asset """ instrument = get_instrument(self.ticker) day_data = instrument.get_day(date) # preferably use the 'close' field, then the 'value' field try: current_price = day_data['close'] except KeyError: current_price = day_data['value'] return self.quantity * current_price
def plot(ticker_columns): """ Args: ticker_columns (list): Tickers and ticker columns to plot. This argument must be an iterable on the format: [[instrument_ticker_a, column_name_a], [instrument_ticker_b, column_name_b], ...] """ linked_plot = LinkedPlot(window_title="plot_instrument.py") # add plots to the main window for instrument_name, column_name in ticker_columns: instrument = get_instrument(instrument_name.upper()) # create a new plot with one subplot (data series) in it linked_plot.add_plot(plot_title=instrument_name.upper()) linked_plot.add_subplot(instrument.data, y_axis_name=column_name) # show the GUI window linked_plot.show()
def simulate(strategy, money, from_date, to_date): # share holding positions {ticker: Share,} portfolio = {} # for all trading days between the two dates for today in trading_days(from_date, to_date): # run the strategy for this date orders = strategy.execute(today) # process the orders for order in orders: # get the instrument object instrument = get_instrument(order.ticker) # the the market date for this instrument for this date ticker_day = instrument.get_day(today) # assume orders get filled at best price if order.action == 'buy': if order.price is None: order.fill(ticker_day['low']) elif ticker_day['low'] <= order.price: order.fill(ticker_day['low']) elif order.action == 'sell': if order.price is None: order.fill(ticker_day['high']) elif ticker_day['high'] >= order.price: order.fill(ticker_day['high']) else: raise Exception("Order.action is neither 'sell' nor 'buy'") if order.filled: # update the Share object if it exists for this ticker try: share = portfolio[order.ticker] new_quantity = share.quantity + order.quantity share.price = ((share.quantity * share.price) + \ (order.quantity * order.price)) / new_quantity share.quantity = new_quantity except KeyError: # create a new share object share = Share(order.ticker, order.quantity, order.filled_price) portfolio[order.ticker] = share money -= order.total interest = broker.calculate_interest(money) money += interest # calculate the current market value portfolio_value = money for share in portfolio.values(): share_value = share.get_value(today) portfolio_value += share_value # the total value of the account account_value = money + portfolio_value loan_ratio = broker.calculate_loan_ratio(account_value, portfolio_value) if loan_ratio < broker.MIN_LOAN_TO_VALUE_RATIO: raise Exception("Loan-to-value-ratio is too low: " + str(loan_ratio)) # print a message summary of today print("%s: account_value: %.0f, money: %.0f, interest: %.0f" % \ (str(today), account_value, money, interest)) indent = len(str(today)) + 2 for order in orders: print(' ' * indent + str(order))
variance = statistics.variance(gain_ratios) std_deviation = statistics.stdev(gain_ratios) data = OrderedDict() data['trades'] = trades data['year_count'] = year_count data['avg_gain_ratio'] = avg_gain_ratio data['pos_gain_ratio'] = pos_gain_ratio data['variance'] = variance data['std_deviation'] = std_deviation return data if __name__ == "__main__": # Parse command line arguments parser = argparse.ArgumentParser( description="Find the historical return between dates") parser.add_argument("ticker", help="Ticker name (ex.: OBX.OSE)") parser.add_argument("buy_date", help="Buy date: YYYY-MM-DD") parser.add_argument("sell_date", help="Sell date: YYYY-MM-DD") args = parser.parse_args() # get the instrument from the database instrument = get_instrument(args.ticker.upper()) buy_date = parse_date(args.buy_date) sell_date = parse_date(args.sell_date) pprint(historical_return_from_to_date(instrument, buy_date, sell_date))
def simulate(strategy, money, from_date, to_date, reference): # the number of shares we could have bought from the reference instrument reference_shares = money / reference.get_price(from_date) # share holding positions {ticker: Share,} portfolio = {} # log what the strategy is doing by appending tuples: strategy_log = [] # info about what the strategy is doing on the format tuple(date, str) action_markers = [] # for all trading days between the two dates for today in trading_days(from_date, to_date): # label text to show for this day in the plot action_label = None # run the strategy for this date orders = strategy.execute(today, portfolio, money) # process the orders for order in orders: # get the instrument object instrument = get_instrument(order.ticker) # get the market date for this instrument for this date try: ticker_day = instrument.get_day(today) except KeyError: ticker_day = None # assume orders get filled at average price average_price = instrument.get_price(today) # If there was no trading for this ticker on this date # we're going to assume that this trade wasn't filled if ticker_day is None: pass # try to fill orders elif order.action == 'buy': if order.price is None: order.fill(average_price) elif average_price <= order.price: order.fill(average_price) money -= order.total elif order.action == 'sell': if order.price is None: order.fill(average_price) elif average_price >= order.price: order.fill(average_price) money += order.total else: raise Exception("Order.action is neither 'sell' nor 'buy'") if order.filled: # update the action label for the plot if action_label is None: action_label = "" else: action_label += "\n" action_label += order.action + " " + \ order.ticker + " " + str(order.filled_price) # update the Share object if it exists for this ticker try: share = portfolio[order.ticker] # the new number of shares of this stock we own now if order.action == 'sell': new_quantity = share.quantity - order.quantity else: new_quantity = share.quantity + order.quantity share.price = ((share.quantity * share.price) + (order.quantity * order.filled_price)) / new_quantity share.quantity = new_quantity if new_quantity == 0: portfolio.pop(order.ticker) except KeyError: # create a new share object share = Share(order.ticker, order.quantity, order.filled_price) portfolio[order.ticker] = share interest = broker.calculate_interest(money) money += interest # calculate the current market value portfolio_value = 0 for share in portfolio.values(): share_value = share.get_value(today) portfolio_value += share_value # the total value of the account account_value = money + portfolio_value loan_ratio = broker.calculate_loan_ratio( account_value, portfolio_value) if loan_ratio < broker.MIN_LOAN_TO_VALUE_RATIO: print("Loan-to-value-ratio is too low: " + str(loan_ratio)) break # calculate the value of the reference shares reference_value = reference_shares * reference.get_price(today) # add an entry to the log for today strategy_log.append((today, account_value, money, portfolio_value, loan_ratio, reference_value)) if action_label is not None: action_markers.append((today, action_label)) # print a message summary of today print("%s: reference_value: %.0f, account_value: %.0f, money: %.0f, interest: %.0f" % (str(today), reference_value, account_value, money, interest)) indent = len(str(today)) + 2 for order in orders: print(' ' * indent + str(order)) matrix = np.array(strategy_log, dtype=[('date', 'O'), ('account_value', 'f8'), ('money', 'f8'), ('portfolio_value', 'f8'), ('loan_ratio', 'f8'), ('reference_value', 'f8')]) # create a plot showing the behavior of the strategy plot = LinkedPlot(window_title=str(strategy)) plot.add_plot("Account value", title_above=False) plot.add_subplot(matrix, "account_value", "Account value") plot.add_subplot(matrix, "reference_value", str(reference)) for date, text in action_markers: plot.add_marker(date, "Account value", "account_value", "Account value", text=text) plot.show()
args = parser.parse_args() # load the strategy class import strategy try: strategy_class = getattr(strategy, args.strategy) except AttributeError: print('Could not import ' + args.strategy + ' from strategy') print("Available strategies are:") # print all items from the strategy module that end with "Strategy" for attr in dir(strategy): if attr.endswith("Strategy"): print(" " + attr) sys.exit(1) # parse the from/to dates from_date = parse_date(args.from_date) to_date = parse_date(args.to_date) money = float(args.money) # create the strategy instance strategy = strategy_class(money, [], from_date, to_date) # get the reference instument reference = get_instrument(args.reference.upper()) # run the simulation simulate(strategy, money, from_date, to_date, reference)