def test_get_portfolio_shares_owned_on_date(self):
        logic = OrderHistoryLogic()
        order1 = Order(
            user_id=1,
            order_type=order_history.BUY_ORDER_TYPE,
            ticker='AAPL',
            date=datetime.date(2017, 6, 12),
            num_shares=2,
            price=150.0,
        )
        order2 = Order(
            user_id=1,
            order_type=order_history.BUY_ORDER_TYPE,
            ticker='ATVI',
            date=datetime.date(2017, 6, 19),
            num_shares=3,
            price=170.0,
        )
        order3 = Order(
            user_id=1,
            order_type=order_history.SELL_ORDER_TYPE,
            ticker='AAPL',
            date=datetime.date(2017, 6, 26),
            num_shares=1,
            price=180.0,
        )
        logic.add_orders([order1, order2, order3])
        results = logic.get_portfolio_shares_owned_on_date(order1.user_id, datetime.date(2017, 6, 27))

        assert results == {'AAPL': 1, 'ATVI': 3}
    def test_add_buy_orders(self):
        logic = OrderHistoryLogic()
        user_id = 1
        order = Order(
            user_id=user_id,
            order_type=order_history.BUY_ORDER_TYPE,
            date=datetime.date(2015, 8, 9),
            ticker='AAPL',
            num_shares=20,
            price=150.001,
        )
        logic.add_orders([order])

        session = Session()

        resp = session.query(OrderHistory).all()
        assert len(resp) == 1
        order_in_db = resp[0]
        assert order_in_db.user_id == user_id
        assert order_in_db.date == order.date.isoformat()
        assert order_in_db.ticker == order.ticker
        assert order_in_db.num_shares == order.num_shares
        assert order_in_db.price == order.price

        session.close()
Example #3
0
class SchwabIngestor(object):
    def __init__(self):
        self.arg_parser = argparse.ArgumentParser(
            description='Process an etrade csv file')
        self.arg_parser.add_argument('--csv-path', help='path to csv file')
        self.order_logic = OrderHistoryLogic()
        self.user_id = USER_ID

    def run(self):
        self.args = self.arg_parser.parse_args()
        orders = self.parse_orders_from_csv(self.args.csv_path)
        self.order_logic.add_orders(self.user_id, orders)

    def parse_orders_from_csv(self, csv_path):
        with open(csv_path) as csv_file:
            reader = csv.reader(csv_file)
            orders = self.parse_orders_from_csv_reader(reader)
            return orders

    def parse_orders_from_csv_reader(self, reader):
        orders = []
        for row in reader:

            try:
                # Ingore lines that don't parse
                order = self.extract_order_from_row(row)
            except RowParserException:
                continue

            if order:
                orders.append(order)

        return orders

    def extract_order_from_row(self, row):
        try:
            date = datetime.datetime.strptime(row[0], "%m/%d/%Y").date()
            txn_type = row[1]
            ticker = row[2]
            num_shares = int(row[4])
            share_price = float(row[5].replace('$', ''))
        except Exception:
            raise RowParserException()

        if ticker in blacklisted_tickers or txn_type != 'Buy':
            return None

        return Order(self.user_id, BUY_ORDER_TYPE, ticker, date, num_shares,
                     share_price)
 def test_get_ticker_total_purchased_sold(self):
     logic = OrderHistoryLogic()
     order1 = Order(
         user_id=1,
         order_type=order_history.BUY_ORDER_TYPE,
         ticker='AAPL',
         date=datetime.date(2017, 6, 12),
         num_shares=2,
         price=150.0,
     )
     order2 = Order(
         user_id=1,
         order_type=order_history.BUY_ORDER_TYPE,
         ticker='ATVI',
         date=datetime.date(2017, 6, 19),
         num_shares=3,
         price=170.0,
     )
     order3 = Order(
         user_id=1,
         order_type=order_history.SELL_ORDER_TYPE,
         ticker='AAPL',
         date=datetime.date(2017, 6, 26),
         num_shares=1,
         price=180.0,
     )
     order4 = Order(
         user_id=1,
         order_type=order_history.SELL_ORDER_TYPE,
         ticker='ATVI',
         date=datetime.date(2017, 6, 29),
         num_shares=3,
         price=120.0,
     )
     logic.add_orders([order1, order2, order3, order4])
     purchased, sold = logic.get_ticker_total_purchased_sold(order1.user_id)
     assert purchased == {
         'AAPL': order1.num_shares * order1.price,
         'ATVI': order2.num_shares * order2.price
     }
     assert sold == {
         'AAPL': order3.num_shares * order3.price,
         'ATVI': order4.num_shares * order4.price
     }
 def test_get_orders_for_user(self):
     logic = OrderHistoryLogic()
     order1 = Order(
         user_id=1,
         order_type=order_history.BUY_ORDER_TYPE,
         ticker='AAPL',
         date=datetime.date(2017, 6, 12),
         num_shares=2,
         price=150.0,
     )
     order2 = Order(
         user_id=1,
         order_type=order_history.BUY_ORDER_TYPE,
         ticker='AAPL',
         date=datetime.date(2017, 6, 19),
         num_shares=3,
         price=170.0,
     )
     order3 = Order(
         user_id=2,
         order_type=order_history.BUY_ORDER_TYPE,
         ticker='AAPL',
         date=datetime.date(2017, 6, 19),
         num_shares=3,
         price=170.0,
     )
     logic.add_orders([order1, order2, order3])
     assert set(logic.get_orders_for_user(1)) == set([order1, order2])
     assert logic.get_ticker_to_orders(1) == {'AAPL': [order1, order2]}
    def test_get_all_order_tickers_min_date(self):
        logic = OrderHistoryLogic()
        user_id_1 = 1
        user_id_2 = 2
        order1 = Order(
            user_id=user_id_1,
            order_type=order_history.BUY_ORDER_TYPE,
            date=datetime.date(2015, 8, 9),
            ticker='AAPL',
            num_shares=20,
            price=150.001,
        )
        order2 = Order(
            user_id=user_id_2,
            order_type=order_history.BUY_ORDER_TYPE,
            date=datetime.date(2017, 1, 1),
            ticker='AAPL',
            num_shares=20,
            price=152.333,
        )
        logic.add_orders([order1, order2])

        ticker_dates = logic.get_all_order_tickers_min_date()
        assert ticker_dates == [TickerDate(order1.ticker, order1.date)]
Example #7
0
 def __init__(self):
     self.arg_parser = argparse.ArgumentParser(
         description='Process an etrade csv file')
     self.arg_parser.add_argument('--csv-path', help='path to csv file')
     self.order_logic = OrderHistoryLogic()
     self.user_id = USER_ID
 def __init__(self):
     self.order_logic = OrderHistoryLogic()
     self.price_logic = PriceHistoryLogic()
     self.log = logger
class AlphavantagePriceHistoryFetcher(object):
    def __init__(self):
        self.order_logic = OrderHistoryLogic()
        self.price_logic = PriceHistoryLogic()
        self.log = logger

    def run(self):
        ticker_min_order_dates = self.order_logic.get_all_order_tickers_min_date(
        )
        for ticker_date in ticker_min_order_dates:
            self.process_ticker_order_date(ticker_date)
        min_date = min(t.date for t in ticker_min_order_dates)
        for ticker in constants.BENCHMARK_TICKERS:
            self.process_ticker_order_date(TickerDate(ticker, min_date))

    # TODO, change name, doesn't matter if it's an order at this point
    def process_ticker_order_date(self, ticker_date):
        self.log.info("Processing ticker %s" % ticker_date.ticker)
        fetch_date = self.get_fetch_date(ticker_date)
        if self.should_fetch_data_for_date(fetch_date):
            self.log.info("Fetch history for ticker %s to %s" %
                          (ticker_date.ticker, fetch_date.isoformat()))
            history = self.fetch_ticker_history(
                TickerDate(ticker_date.ticker, fetch_date))
            self.price_logic.add_prices(history)

    def get_fetch_date(self, ticker_min_order_date):
        """gets a date that could be fetched,
        either the min order date or max history date + 1
        """
        if self.price_logic.does_ticker_date_history_exists(
                ticker_min_order_date):
            return self.price_logic.get_max_date_history_for_ticker(
                ticker_min_order_date.ticker) + datetime.timedelta(days=1)
        return ticker_min_order_date.date

    def fetch_ticker_history(self, ticker_date):
        self.log.info("...Fetching data from %s to now..." %
                      ticker_date.date.isoformat())
        url = self._form_url(ticker_date)
        # TODO check throttle
        time.sleep(12)  # Sleep to throttle hitting api
        response = requests.get(url)
        content = response.content
        data = self._parse_historical(content)
        data = [d for d in data if d.date >= ticker_date.date]
        print(data)
        assert data[0].date == ticker_date.date
        assert data[0].ticker == ticker_date.ticker
        return data

    def should_fetch_data_for_date(self, fetch_date):
        """See if there is possibly new data to fetch.
        fetch_date is the max_history date + 1 or order date if no history exists.
        Cases not to fetch:
        (1) fetch_date is today.
        (2) fetch_date is yesterday (not Friday) and it's after today's close.
        (3) fetch_date is a Friday and it's not Monday after close.
        """
        now_dt = datetime.datetime.now(pytz.timezone('US/Eastern'))
        fetch_weekday = fetch_date.weekday()
        day_diff = (now_dt.date() - fetch_date).days

        now_is_after_close = False
        if now_dt.hour >= 16:
            now_is_after_close = True

        if fetch_weekday <= 4:  # Mon-Friday
            if (day_diff == 0 and now_is_after_close) or day_diff >= 1:
                return True

        if fetch_weekday > 4:  # Saturday (data for week exists)
            if (day_diff == 2 and now_is_after_close) or day_diff >= 3:
                return True

        self.log.info("...Skipping fetch, no new data...")
        return False

    def _form_url(self, ticker_date):
        return URL_TEMPLATE.format(
            ticker=ticker_date.ticker,
            api_key=API_KEY,
        )

    def _parse_historical(self, content):
        """Gets bytes of json and returns lines of TickerDatePrice tuples
        { "Meta Data": {  "2. Symbol": "MOMO"},
          "Time Series (Daily)": {
            "2017-12-20": { "4. close": "26.0200", },
            "2017-12-19": { "4. close": "25.8600", },
        }
        """
        data = json.loads(content.decode())
        rows = []
        ticker = data['Meta Data']['2. Symbol']
        for date_str, price_data_point in data['Time Series (Daily)'].items():
            date = datetime.datetime.strptime(date_str, '%Y-%m-%d').date()
            price = float(price_data_point['4. close'])
            rows.append(TickerDatePrice(ticker, date, price))
        return sorted(rows, key=lambda x: x.date)