Фундаментальные финансовые показатели

Простейший пример

Кратко опишем алгоритм

  1. Отфильтровываем лучшие 50 компаний по показателю капитализации.
  2. Отбираем две отрасли с максимальным средним коэффициентом цена/прибыль (P/E ratio).
  3. Каждый месяц закрываем всю нашу позицию перед тем, как открывать новую.
  4. Выводим в лог требуемую позицию.
  5. import pandas as pd
    import numpy as np
     
    def initialize(context):
        # Словарь акций с их весами
        context.stock_weights = {}
        # Счетчик дней до ребалансировки портфеля
        context.days = 0
        # Количество секторов с которыми будем работать (покупать)
        context.sect_numb = 2
     
        # Превязка секторов
        context.sector_mappings = {
            101.0: "Basic Materials",
            102.0: "Consumer Cyclical",
            103.0: "Financial Services",
            104.0: "Real Estate",
            205.0: "Consumer Defensive",
            206.0: "Healthcare",
            207.0: "Utilites",
            308.0: "Communication Services",
            309.0: "Energy",
            310.0: "Industrials",
            311.0: "Technology"
        }
         
        # Ребалансировка портфеля ежемесячно в первый день в момент открытия торгов
        schedule_function(rebalance,
                date_rule=date_rules.month_start(),
                time_rule=time_rules.market_open())
    Теперь рассмотрим основной метод, который вызывается каждый раз перед началом торгового дня. В нашем случае это
    означает, что он запускается ежемесячно в первый день месяца. Метод обновляет множество акций и соотвествующие фундаментальные экономические показатели.
    def before_trading_start(context, data): 
        # Количество анализируемых акций    
        num_stocks = 50
     
        # Формируем запрос SQLAlchemy на основе pe_ratio
        # и принадлежности к секторам
        # Мы отфильтровываем результат, чтобы обязательно были значения
        # по капитализации и количеству акции.
        # Мы ограничиваем вывод количеством num_stocks и возвращаем данные
        # в порядке убывания
     
        fundamental_df = get_fundamentals(
            query(
                fundamentals.valuation_ratios.pe_ratio,
                fundamentals.asset_classification.morningstar_sector_code
            )
            .filter(fundamentals.valuation.market_cap != None)
            .filter(fundamentals.valuation.shares_outstanding != None)
            .order_by(fundamentals.valuation.market_cap.desc())
            .limit(num_stocks)
        )
        # Находим сектора с наибольшим средним коэффициентом цена/прибыль (pe_ratio)
        sector_pe_dict = {}
        for stock in fundamental_df:
            sector = fundamental_df[stock]['morningstar_sector_code']
            pe = fundamental_df[stock]['pe_ratio']
            
            # If it exists add our pe to the existing list. 
            # Otherwise don't add it.
            if sector in sector_pe_dict:
                sector_pe_dict[sector].append(pe)
            else:
                sector_pe_dict[sector] = []
        
        # Находим среднее PE для кажного сектора
        sector_pe_dict = dict([(sectors, np.average(sector_pe_dict[sectors])) 
                    for sectors in sector_pe_dict if len(sector_pe_dict[sectors]) > 0])
        
        # Сортируем в низходящем порядке и берем первых sect_numb
        sectors = sorted(sector_pe_dict, key=lambda x: sector_pe_dict[x], reverse=True)[:context.sect_numb]
        
        # Отфильтровываем акции только выбранных секторов
        context.stocks = [stock for stock in fundamental_df
                    if fundamental_df[stock]['morningstar_sector_code'] in sectors]
        # Инициализируем
        # Initialize a context.sectors variable
        context.sectors = [context.sector_mappings[sect] for sect in sectors]
        # Обновляем
        # Update context.fundamental_df with the securities (and pe_ratio) that we need
        context.fundamental_df = fundamental_df[context.stocks]
            
        update_universe(context.fundamental_df.columns.values)