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()
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')
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)
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
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)
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
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