def analyse(self):
        symbol = select(sym.name for sym in self.stock.price_item.symbols
                        if Tag.YAO in sym.item.tags.name).first()
        try:
            yao_item = yf.Ticker(symbol)
            data = yao_item.dividends
        except ValueError:
            raise RuntimeError("Couldn't load dividends for {}".format(symbol))

        dates = data.index.array
        drop = []
        # let us calculate the dividend yield
        for my_date in dates:
            price = Price.select(
                    lambda p: p.symbol.name == symbol
                    and p.date.date() == my_date.date()
                ).first()
            if price:
                div_yield = (data[my_date] / price.close) * 100
                if div_yield > self.max_yield:
                    drop.append(my_date)
                    self.logger.error(
                        '{} has a non plausible div yield at {} ({} = {} / {} * 100).'
                        .format(symbol, my_date, div_yield, data[my_date], price.close)
                    )
                else:
                    data[my_date] = div_yield
            else:
                drop.append(my_date)
        data = data.drop(labels=drop)
        self.calc = data.median(axis=0)
        if self.calc is None or math.isnan(self.calc):
            raise RuntimeError("Couldn't calculate dividend yield.")
        return super(DividendKings, self).analyse()
Пример #2
0
 def test_1_create(self):
     """
     Test database client
     :return:
     """
     config = {
         'max_history': 1,
         'indices': [],
         'currencies': ['EUR'],
         'create': True,
         'db_args': {
             'provider': 'sqlite',
             'filename': 'database_create.sqlite',
             'create_db': True
         },
     }
     logger = logging.getLogger('test')
     create = CreateAndFillDataBase(config, logger)
     self.assertEqual(create.build(), 0)
     config['indices'] = ['DAX']
     config['currencies'] = ['CAD']
     create = CreateAndFillDataBase(config, logger)
     self.assertEqual(create.build(), -1)
     config['currencies'] = ['EUR', 'USD']
     # check setup with multiple currencies
     with freeze_time('2019-01-14'):
         create = CreateAndFillDataBase(config, logger)
         self.assertEqual(create.build(), 0)
     with db_session:
         # check euro
         prices_ctx = Price.select(
             lambda p: p.symbol.name == 'IFX.F').count()
         self.assertGreater(prices_ctx, 1)
         # check usd
         prices_ctx = Price.select(
             lambda p: p.symbol.name == 'IFNNF').count()
         self.assertGreater(prices_ctx, 1)
     with freeze_time('2019-01-14'):
         config['currencies'] = ['EUR']
         create = CreateAndFillDataBase(config, logger)
         self.assertEqual(create.build(), 0)
     with db_session:
         stocks = Stock.select().count()
         self.assertEqual(stocks, 30)
         prices = list(select(max(p.date) for p in Price))
         self.assertEqual(len(prices), 1)
         self.assertEqual(prices[0].strftime('%Y-%m-%d'), '2019-01-11')
Пример #3
0
    def test_5_create_flat(self):
        """
        Test flat create
        :return:
        """
        config = {
            'max_history': 1,
            'indices': ['DAX'],
            'currencies': ['EUR'],
            'prices': False,  # disables price downloading
            'create': True,
            'db_args': {
                'provider': 'sqlite',
                'filename': 'database_create.sqlite',
                'create_db': True
            },
        }
        logger = logging.getLogger('test')
        create = CreateAndFillDataBase(config, logger)
        self.assertEqual(create.build(), 0)
        with db_session:
            # check euro
            prices_ctx = select(p for p in Price).count()
            self.assertEqual(prices_ctx, 0)

        config = {
            'symbols': ['IFX.F', 'ADS.F'],
            'prices': True,
            'fundamentals': True,
            'max_history': 1,
            'db_args': {
                'provider': 'sqlite',
                'filename': 'database_create.sqlite',
                'create_db': False
            },
        }
        update = UpdateDataBaseStocks(config, logger)
        self.assertEqual(update.build(), 0)
        with db_session:
            prices_ctx = Price.select(
                lambda p: p.symbol.name == 'IFX.F').count()
            self.assertGreater(prices_ctx, 1)
            prices_ctx = Price.select(
                lambda p: p.symbol.name == 'ADS.F').count()
            self.assertGreater(prices_ctx, 1)
            data_ctx = select(d for d in Data).count()
            self.assertEqual(data_ctx, 12)
Пример #4
0
    def get_index_bars(self, symbol, my_filter):
        now = datetime.strptime('2019-07-30', '%Y-%m-%d')
        before = now + relativedelta(months=-my_filter.lookback)
        my_index = Index.select(
            lambda i: symbol in i.stocks.price_item.symbols.name).first()

        bars = Price.select(
            lambda p: p.symbol.name in my_index.price_item.symbols.name and p.
            date >= before and p.date <= now)
        return bars
Пример #5
0
 def test_3_update(self):
     """
     Test database client update
     :return:
     """
     logger = logging.getLogger('test')
     config = {
         'symbols': [ALL_SYMBOLS],
         'prices': True,
         'fundamentals': True,
         'db_args': {
             'provider': 'sqlite',
             'filename': 'database_create.sqlite',
             'create_db': False
         },
     }
     update = UpdateDataBaseStocks(config, logger)
     update.build()
     with db_session:
         prices = list(select(max(p.date) for p in Price))
         self.assertEqual(len(prices), 1)
         my_date = datetime.datetime.strptime('2019-01-14', '%Y-%m-%d')
         self.assertGreater(prices[0], my_date)
         price_ctx = Price.select().count()
         data_ctx = Data.select().count()
         self.assertGreater(data_ctx, 1)
         self.assertGreater(price_ctx, 1)
     update.build()
     with db_session:
         price_ctx_now = Price.select().count()
         data_ctx_now = Data.select().count()
         self.assertGreaterEqual(price_ctx_now, price_ctx)
         self.assertGreaterEqual(data_ctx_now, data_ctx)
     config['symbols'] = ['ADS.F']
     update = UpdateDataBaseStocks(config, logger)
     update.build()
    def __build(self, my_filter, stock, symbol):
        my_filter.now_date = self.now_date
        if my_filter.look_back_date():
            my_filter.set_stock(stock)
            # set bar prices
            if my_filter.need_bars:
                bars = Price.select(
                    lambda p: p.symbol.name == symbol.name
                    and p.date >= my_filter.look_back_date()
                    and p.date <= self.now_date
                )
                my_filter.set_bars(bars)
            # set index
            if my_filter.need_index_bars:
                # get index symbol of stock
                index_sym = select(
                    i.price_item.symbols.name for i in Index
                    if i in stock.indexs
                ).first()

                bars = Price.select(
                    lambda p: p.symbol.name == index_sym
                    and p.date >= my_filter.look_back_date()
                    and p.date <= self.now_date
                )
                my_filter.set_index_bars(bars)

            strategy_status = my_filter.analyse()
            strategy_value = my_filter.get_calculation()
            fil_typ = Type.get(name=Type.FIL)

            fil_tag = Tag.select(lambda t: t.name == my_filter.name and
                                 t.type.name == Type.FIL) or \
                Tag(name=my_filter.name, type=fil_typ)

            my_res = Result(
                value=strategy_value,
                status=strategy_status,
                date=self.now_date
            )

            # add arguments to result
            arg_typ = Type.get(name=Type.ARG)
            for arg in my_filter.args:
                arg_tag = Tag.select(lambda t: t.name == arg and
                                     t.type.name == Type.ARG) or \
                                     Tag(name=arg, type=arg_typ)
                item = Item()
                item.add_tags([arg_tag])
                arg_str = json.dumps(my_filter.args[arg])
                Argument(item=item, arg=arg_str, result=my_res)
            # create signal item
            sig_item = Item()
            sig_item.add_tags([fil_tag])
            my_sig = Signal(item=sig_item, result=my_res)
            # add stock to signal
            my_sig.price_items.add(symbol.price_item)
            if strategy_status == BaseFilter.BUY:
                self.logger.debug("Buy %s", symbol)
            elif strategy_status == BaseFilter.HOLD:
                self.logger.debug("Hold %s", symbol)
            else:
                self.logger.debug("Do not buy Stock %s ", symbol)
Пример #7
0
    def __update(self, docs, stocks):
        for stock_item in stocks:
            # find coresbondanding document
            my_doc = None
            for doc_dict, doc in docs:
                if stock_item.name == doc_dict['name']:
                    my_doc = doc
                    break

            if not my_doc:
                raise RuntimeError(
                    f"Stock {stock_item.name} doesn't exist in firestore.")

            signals = []
            for signal_item in stock_item.price_item.signals:
                signal = {
                    'value': signal_item.result.value,
                    'status': signal_item.result.status,
                    'name': [tag.name for tag in signal_item.item.tags][0],
                }

                def is_in(signals, signal):
                    for si in signals:
                        if si['name'] == signal['name']:
                            return True
                    return False

                if not is_in(signals, signal):
                    signals.append(signal)

            stock = {
                'date': datetime.datetime.now().strftime('%m/%d/%Y'),
                'last_price_usd': None,
                'last_price_eur': None,
            }
            # add signals to document in a flat way to simplify queries
            for signal_item in signals:
                stock['{}_value'.format(
                    signal_item['name'])] = signal_item['value']
                stock['{}_status'.format(
                    signal_item['name'])] = signal_item['status']

            my_doc_dict = my_doc.to_dict()

            for price_key in (
                ('last_price_eur', 'symbols_eur'),
                ('last_price_usd', 'symbols_usd'),
            ):
                stock[price_key[0]] = {}
                # get prices for each symbol
                for usd_symbol in my_doc_dict[price_key[1]]:
                    stock[price_key[0]][usd_symbol] = (
                        Price.select(lambda p: p.symbol.name == usd_symbol).
                        order_by(lambda p: desc(p.date)).first())
                # set latest price for each symbol
                for key, value in stock[price_key[0]].items():
                    if value is None:
                        self.logger.warning(f'Prices are not correct for {key}'
                                            f'({stock_item.name}).')
                    else:
                        stock[price_key[0]][key] = stock[
                            price_key[0]][key].close
            yield my_doc, stock
Пример #8
0
 def get_bars(self, symbol, my_filter):
     now = datetime.strptime('2019-07-30', '%Y-%m-%d')
     before = now + relativedelta(months=-my_filter.lookback)
     bars = Price.select(lambda p: p.symbol.name == symbol and p.date >=
                         before and p.date <= now)
     return bars