Как построить рыночный профиль (Market Profile) с помощью Python

Рыночный профиль (Market Profile) — это мощный инструмент анализа, который помогает трейдерам понять распределение цен и объемов в течение определенного периода. В этой статье мы разберем, как использовать Python и Plotly для построения рыночного профиля, включая его реализацию через shapes для наглядного отображения.
Из материала вы узнаете:
- Как получить данные OHLC (Open, High, Low, Close) с помощью yfinance
- Как сгруппировать данные по дню, неделе, месяцу для рыночного профиля
- Как визуализировать рыночный профиль через shapes в Plotly
- Полезные паттерны использования Market Profile
Что такое рыночный профиль и зачем он нужен?
Рыночный профиль отображает распределение объема по уровням цен. В отличие от классических свечных графиков, Market Profile показывает, где накапливается ликвидность, а где рынок движется без особого интереса участников.
Что можно увидеть в Market Profile:
- Уровни Value Area (зоны справедливой цены)
- Point of Control (PoC) — уровень с наибольшей ликвидностью
- Области с маленьким объемом (возможные уровни поддержки и сопротивления)
Шаг 1. Получаем данные OHLC с помощью Python
Для начала загрузим данные с yfinance.
import pandas as pd
import numpy as np
import plotly.graph_objects as go
import yfinance as yf
# 🔹 Настройки тикера и интервала
TICKER = "AAPL" # Можно заменить на другой актив
PERIOD = "1mo" # Длительность загрузки данных
INTERVAL = "1h" # Интервал свечей
# Функция для загрузки данных OHLC
def get_ohlc_data(ticker=TICKER, period=PERIOD, interval=INTERVAL):
data = yf.download(ticker, period=period, interval=interval)
data.reset_index(inplace=True)
# 📌 Убираем MultiIndex, если он есть
data.columns = [col[0].lower() if isinstance(col, tuple) else col.lower() for col in data.columns]
return data
# Загружаем данные
data = get_ohlc_data()
print(data.head()) # Проверяем структуру
Разбор кода:
- Используем
yfinance
для загрузки данных - Переводим названия колонок в нижний регистр (
.lower()
) - Убираем возможный
MultiIndex
, чтобы избежать ошибок
Шаг 2. Рассчитываем Market Profile для разных временных интервалов
Теперь мы хотим строить Market Profile не только для 1 дня, но и для недели (1W) и месяца (1M).
# 🔹 Параметры Market Profile
MARKET_PROFILE_INTERVAL = "1D" # Варианты: "1D", "1W", "1M"
PRICE_BINS_METHOD = "auto" # Количество бинов (можно поставить число)
VOLUME_SCALE = 0.5 # Масштабирование ширины профиля
# Функция для расчета Market Profile
def calculate_market_profile(df, interval=MARKET_PROFILE_INTERVAL):
if interval == "1D":
df['date'] = df['datetime'].dt.floor('D') # Группируем по дням
elif interval == "1W":
df['date'] = df['datetime'].dt.to_period('W').apply(lambda r: r.start_time)
elif interval == "1M":
df['date'] = df['datetime'].dt.to_period('M').apply(lambda r: r.start_time)
else:
raise ValueError("Неверный интервал! Используйте '1D', '1W' или '1M'.")
grouped = df.groupby('date')
market_profiles = []
for date, group in grouped:
price_bins = np.histogram_bin_edges(group['close'], bins=PRICE_BINS_METHOD)
hist, edges = np.histogram(group['close'], bins=price_bins)
market_profiles.append({
'date': pd.to_datetime(date),
'prices': edges[:-1],
'volumes': hist / hist.max() * VOLUME_SCALE
})
return market_profiles
# Рассчитываем Market Profile
market_profiles = calculate_market_profile(data, interval=MARKET_PROFILE_INTERVAL)
print(market_profiles[:2]) # Проверяем структуру
Разбор кода:
- Группируем свечи по 1D, 1W или 1M
- Строим гистограмму по цене (np.histogram)
- Масштабируем объемы, чтобы Market Profile был читабельным
Шаг 3. Визуализируем Market Profile в Plotly (shapes)
Теперь построим Market Profile через shapes в Plotly.
# Функция для построения Market Profile через SHAPES
def plot_market_profile(df, market_profiles):
fig = go.Figure()
# 📌 Добавляем OHLC график
fig.add_trace(go.Candlestick(
x=df['datetime'],
open=df['open'],
high=df['high'],
low=df['low'],
close=df['close'],
name='OHLC'
))
# 📌 Добавляем Market Profile через SHAPES
shapes = []
for profile in market_profiles:
date = profile['date']
for price, volume in zip(profile['prices'], profile['volumes']):
shapes.append(
dict(
type="line",
x0=date, x1=date + pd.Timedelta(hours=volume * 24),
y0=price, y1=price,
line=dict(color="blue", width=2)
)
)
# 📌 Настройки графика
fig.update_layout(
title=f'Market Profile ({MARKET_PROFILE_INTERVAL}) for {TICKER}',
xaxis_title='Datetime',
yaxis_title='Price',
xaxis=dict(type='date', tickformat="%Y-%m-%d", tickmode='linear', rangeslider=dict(visible=False)),
yaxis=dict(autorange='reversed'),
showlegend=True,
shapes=shapes
)
fig.show()
# Визуализация
plot_market_profile(data, market_profiles)
Разбор кода:
- Используем shapes для Market Profile (рисуем линии горизонтально)
- Привязываем их к ценовому диапазону и дате
- Market Profile теперь масштабируется динамически
Этот подход можно доработать и использовать в алготрейдинге, бэктестинге и реальном трейдинге.

Где пригодится Market Profile?
- Для поиска ключевых уровней поддержки и сопротивления
- Для определения балансных зон (где цена «застревает»)
- Для анализа объемов внутри свечных данных
- Для поиска Point of Control (PoC) — где цена была самой активной
Совет: Market Profile особенно полезен в фьючерсах и акциях, где объемы важны для принятия решений.
Код доступен в нашем репозитории на github. Не забудьте подписаться на профиль и поставить звездочку репозиторию.