Простейший пример
Кратко опишем алгоритм
- Отфильтровываем лучшие 50 компаний по показателю капитализации.
- Отбираем две отрасли с максимальным средним коэффициентом цена/прибыль (P/E ratio).
- Каждый месяц закрываем всю нашу позицию перед тем, как открывать новую.
- Выводим в лог требуемую позицию.
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)