Esempio n. 1
0
def job():
    for func in [ema, sma, macd, rsi, bb]:
        buy_list = []
        sell_list = []
        for symbol in sp.get_sp500():
            # TODO: needs a refresh
            func.generate_signals(symbol,
                                  start_date=utils.add_business_days(
                                      datetime.date.today(), -200),
                                  end_date=datetime.date.today())
            df = pd.read_csv(utils.get_file_path(config.ta_data_path,
                                                 func.table_filename,
                                                 symbol=symbol),
                             index_col="Date",
                             parse_dates=["Date"])
            if df.index[-1].date() != datetime.date.today():
                print(
                    "Last date in {} file does not equal todays date. Is today a weekend or a holiday?"
                    .format(symbol))
            if df[func.get_signal_name()][-1] == ta.buy_signal:
                buy_list.append(symbol)
            if df[func.get_signal_name()][-1] == ta.sell_signal:
                sell_list.append(symbol)

        df = pd.DataFrame({
            "Buy": pd.Series(buy_list),
            "Sell": pd.Series(sell_list)
        })
        df.to_csv(utils.get_file_path(config.ta_data_path,
                                      func.get_signal_name() + table_filename,
                                      dated=True,
                                      start_date="",
                                      end_date=datetime.date.today()),
                  index=False)
Esempio n. 2
0
    def sell(self, symbol, date, sell_size=0):
        """Simulates selling a stock

        Parameters:
            symbol : str
            date : datetime
            sell_size : float, optional
                How much to sell. If 0, sell all
            partial_shares : bool
                Whether partial shares are supported. If True, the amount sold will always equal amount, even if that number isn't reachable in a number of whole shares
            short_sell : bool
        """

        if symbol in self.portfolio:
            if self.portfolio[symbol] > 0:
                # sell at close price, or next day's open price?
                if sell_size == 0:  # sell all
                    self.cash += self.portfolio[symbol] * self.get_price_on_date(symbol, utils.add_business_days(date, self.slippage), time="Close" if self.slippage == 0 else "Open")
                    self.cash -= self.calculate_commission(self.portfolio[symbol])
                    self.log.loc[date][actions_column_name] = self.log.loc[date][actions_column_name] + "{} {} {} Shares at {} totalling {:.2f} ".format(ta.sell_signal, symbol, self.portfolio[symbol], self.get_price_on_date(symbol, utils.add_business_days(date, self.slippage), time="Close" if self.slippage == 0 else "Open"), self.portfolio[symbol] * self.get_price_on_date(symbol, utils.add_business_days(date, self.slippage), time="Close" if self.slippage == 0 else "Open"))
                    self.portfolio.pop(symbol)
                else:
                    shares = (sell_size // self.get_price_on_date(symbol, utils.add_business_days(date, self.slippage), time="Close" if self.slippage == 0 else "Open")) if not self.partial_shares else (sell_size / self.get_price_on_date(symbol, utils.add_business_days(date, self.slippage), time="Close" if self.slippage == 0 else "Open"))
                    shares = shares if shares < self.portfolio[symbol] else self.portfolio[symbol]
                    if shares < 0:
                        print("Amount {} Price {} Shares {}".format(sell_size, self.get_price_on_date(symbol, utils.add_business_days(date, self.slippage), time="Close" if self.slippage == 0 else "Open"), shares), flush=True)
                        raise Exception
                    if shares != 0:
                        self.cash += shares * self.get_price_on_date(symbol, utils.add_business_days(date, self.slippage), time="Close" if self.slippage == 0 else "Open")
                        self.cash -= self.calculate_commission(shares)
                        self.log.loc[date][actions_column_name] = self.log.loc[date][actions_column_name] + "{} {} {} Shares at {} totalling {:.2f} ".format(ta.sell_signal, symbol, shares, self.get_price_on_date(symbol, utils.add_business_days(date, self.slippage), time="Close" if self.slippage == 0 else "Open"), shares * self.get_price_on_date(symbol, utils.add_business_days(date, self.slippage), time="Close" if self.slippage == 0 else "Open"))
                        self.portfolio[symbol] -= shares
                        if self.portfolio[symbol] < 0:
                            print("Amount {} Price {} Shares {} Shares in portfolio {}".format(sell_size, self.get_price_on_date(symbol, utils.add_business_days(date, self.slippage), time="Close" if self.slippage == 0 else "Open"), shares, self.portfolio[symbol]), flush=True)
                            raise Exception
                        if self.portfolio[symbol] == 0:
                            self.portfolio.pop(symbol)
                self.set_stop_loss(symbol, date, Operation.Sell)
                self.update_winners_losers(symbol, date, Operation.Sell)
            else:
                # short sell more
                pass
        else:
            if self.short_sell:
                pass
Esempio n. 3
0
    def update_winners_losers(self, symbol, date, func):
        """Updates the cost basis when buying and updates winners/losers when selling

        Parameters:
            symbol : str
            date : datetime
            func : str
        """

        if func == Operation.Buy:
            self.cost_basis[symbol] = self.get_price_on_date(symbol, utils.add_business_days(date, self.slippage), time="Close" if self.slippage == 0 else "Open")
        if func == Operation.Sell:
            if self.cost_basis[symbol] < self.get_price_on_date(symbol, utils.add_business_days(date, self.slippage), time="Close" if self.slippage == 0 else "Open"):
                self.winners_losers["Winners"] += 1
            else:
                self.winners_losers["Losers"] += 1
            try:
                self.cost_basis.pop(symbol)  # not actually nessecary since next time we buy the stock it will overwrite the cost basis
            except KeyError:
                print(symbol)
                print(self.cost_basis)
                raise
Esempio n. 4
0
    def set_stop_loss(self, symbol, date, func):
        """Sets initial values in the stop loss dictionary when buying and removes entries when selling

        Parameters:
            symbol : str
            date : datetime
            func : str
        """

        if func == Operation.Buy:
            self.stop_loss[symbol] = self.get_price_on_date(symbol, utils.add_business_days(date, self.slippage), time="Close" if self.slippage == 0 else "Open")
        if func == Operation.Sell:
            self.stop_loss.pop(symbol)
Esempio n. 5
0
    def buy(self, symbol, date, purchase_size):
        """Simulates buying a stock

        Parameters:
            symbol : str
            date : datetime
            purchase_size : float, optional
                How much to buy. If 0, buy the default amount
            partial_shares : bool
                Whether partial shares are supported. If True, the amount bought will always equal amount, even if that number isn't reachable in a number of whole shares
        """

        if purchase_size == 0:
            purchase_size = self.purchase_size

        if self.cash < purchase_size:
            self.log.loc[date][actions_column_name] = self.log.loc[date][actions_column_name] + "Unable to buy {} ".format(symbol)
            # purchase_size = self.cash
        elif symbol not in self.portfolio:
            # buy at close price, or next day's open price?
            shares = (purchase_size // self.get_price_on_date(symbol, utils.add_business_days(date, self.slippage), time="Close" if self.slippage == 0 else "Open")) if not self.partial_shares else (purchase_size / self.get_price_on_date(symbol, utils.add_business_days(date, self.slippage), time="Close" if self.slippage == 0 else "Open"))
            if shares < 0:
                # Sometimes shares is -1. When variables are printed, math does not add up to -1??
                print("Symbol {} self.purchase_size {} Purchase size {} Price {} Shares {}".format(symbol, self.purchase_size, purchase_size, self.get_price_on_date(symbol, utils.add_business_days(date, self.slippage), time="Close" if self.slippage == 0 else "Open"), shares), flush=True)
                raise Exception
            if shares != 0:
                self.portfolio[symbol] = shares
                self.cash -= shares * self.get_price_on_date(symbol, utils.add_business_days(date, self.slippage), time="Close" if self.slippage == 0 else "Open")
                self.cash -= self.calculate_commission(shares)
                self.log.loc[date][actions_column_name] = self.log.loc[date][actions_column_name] + "{} {} {} Shares at {} totaling {:.2f} ".format(ta.buy_signal, symbol, shares, self.get_price_on_date(symbol, utils.add_business_days(date, self.slippage), time="Close" if self.slippage == 0 else "Open"), shares * self.get_price_on_date(symbol, utils.add_business_days(date, self.slippage), time="Close" if self.slippage == 0 else "Open"))

                self.set_stop_loss(symbol, date, Operation.Buy)
                self.update_winners_losers(symbol, date, Operation.Buy)
        else:
            if self.short_sell and self.portfolio[symbol] < 0:
                pass
            elif self.portfolio[symbol] > 0:
                # buy more
                pass
Esempio n. 6
0
    def get_price_on_date(self, symbol, date, time="Close"):
        """Gets the price of the given symbol on the given date

        Parameters:
            symbol : str
            date : datetime
            time : str
                Which column to use to determine price. Valid times are "Open" and "Close"

        Returns:
            float
                The price of the given symbol on the given date
        """

        start_time = timer()

        if symbol in self.price_files:
            df = self.price_files[symbol]
        else:
            if utils.refresh(utils.get_file_path(config.prices_data_path, prices.price_table_filename, symbol=symbol), refresh=False):
                prices.download_data_from_yahoo(symbol, start_date=self.start_date, end_date=self.end_date)
            df = pd.read_csv(utils.get_file_path(config.prices_data_path, prices.price_table_filename, symbol=symbol), index_col="Date", parse_dates=["Date"])[self.start_date:self.end_date]
            self.price_files[symbol] = df

        price = df.loc[date][time] if date in df.index else self.get_price_on_date(symbol, utils.add_business_days(date, -1), time=time)

        self.times[get_price_time] = self.times[get_price_time] + timer() - start_time
        return price
Esempio n. 7
0
    "RMO", "VINC", "PRCH", "ARKO", "OPEN", "AVCT", "PAE", "VRT", "RPAY", "WTRH"
]
# list of spacs with missing data
data_issues_list = ["AGLY", "CLVR", "HUNTF", "KLDI", "LAZY", "SONG"]

spac_data = pd.read_csv(utils.get_file_path(config.spac_data_path,
                                            "SPAC.csv",
                                            symbol=""),
                        index_col=False,
                        parse_dates=["Completion Date"])
pre_and_post_merger_prices = []
failed_count = 0
failed_symbols = []
for index, row in spac_data.iterrows():
    symbol = row["Post-SPAC Ticker Symbol"]
    start_date = utils.add_business_days(row["Completion Date"],
                                         days_before_merger)
    end_date = utils.add_business_days(row["Completion Date"],
                                       days_after_merger)

    if symbol not in data_issues_list:
        # Never refresh for spacs, Yahoo consistently missing data around mergers
        df = pd.read_csv(utils.get_file_path(config.spac_data_path,
                                             prices.price_table_filename,
                                             symbol=symbol),
                         index_col="Date",
                         parse_dates=["Date"])
        try:
            # Preferably we would use the below line and also filter dfs for [start_date:end_date]
            # but there are issues where the dates are not as expected due to holdidays. Also OPEN is missing a day randomly
            pre_and_post_merger_prices.append(
                (df.loc[start_date]["Close"], df.loc[end_date]["Close"]))