GaiaEx AcademyGaiaEx Academy
Аналіз даних з Pandas, NumPy та Matplotlib
РозробникПрограмування12 min read

Аналіз даних з Pandas, NumPy та Matplotlib

Очищайте, перетворюйте й візуалізуйте фінансові дані як квант-аналітик

Поділитися

NumPy: двигун під капотом

Кожне серйозне фінансове обчислення в Python зрештою виконується через NumPy. Хоча списки Python гнучкі, вони повільні — кожен елемент є повноцінним об'єктом Python із накладними витратами на перевірку типів. Масиви NumPy зберігають числа в суцільних блоках пам'яті, дозволяючи операціям виконуватись у 100 разів швидше, ніж чисті циклі Python.

Ось різниця на практиці:

import numpy as np

# Створити масив з 1 мільйона випадкових денних доходностей
returns = np.random.normal(0.0005, 0.02, 1_000_000)

# Векторизовані операції — циклі не потрібні
cumulative = np.cumprod(1 + returns)  # Зростання $1
sharpe = returns.mean() / returns.std() * np.sqrt(252)
max_drawdown = np.min(cumulative / np.maximum.accumulate(cumulative) - 1)

print(f"Sharpe Ratio: {sharpe:.3f}")
print(f"Max Drawdown: {max_drawdown:.2%}")

Ключові концепції NumPy для фінансів:

  • Векторизовані операції — застосовують математику до цілих масивів одразу, замість циклічного проходу елемент за елементом.
  • Broadcasting — автоматично узгоджує масиви різних форм для арифметики (наприклад, віднімання скалярного середнього від кожного елемента).
  • Лінійна алгебраnp.linalg надає матричне множення, розкладання на власні значення та розв'язувачі, які використовуються в оптимізації портфеля.
  • Випадкова вибірка — симуляції Монте-Карло, бутстреп-вибірка та стохастичне моделювання всі покладаються на np.random.

Порада щодо продуктивності: завжди надавайте перевагу векторизованим операціям NumPy над циклами for у Python. Оптимізація портфеля з 500 активів, що триває 30 секунд із циклами, може завершитися за менш ніж 50 мілісекунд із векторизованим NumPy — прискорення в 600 разів.

NumPy: суцільна пам'ять + векторизовані операції ndarray — dtype, shape, strides (C-contiguous) один цикл у C/Fortran, а не мільйон кроків байт-коду Python broadcasting: узгодження форм для поелементної математики наприклад, вектор доходностей − скалярне середнє, або (n,) з матрицею (n, m) linalg: cov, eig, solve — тут живе математика портфеля
Масиви — це швидкий шлях; broadcasting — це те, як ви зберігаєте читабельний код без циклів.

Pandas: DataFrame для фінансових даних

Якщо NumPy — це двигун, то pandas — це панель приладів. Він обгортає масиви NumPy у позначені, індексовані структури, які роблять обробку фінансових даних інтуїтивною й виразною.

Дві основні структури:

  • Series — одна колонка даних з індексом (уявіть: часовий ряд цін закриття).
  • DataFrame — таблиця колонок, кожна з яких є Series, що спільно використовують спільний індекс (уявіть: дані свічок OHLCV).

Завантаження та інспекція даних прості:

import pandas as pd

# Читати з CSV
df = pd.read_csv("btc_daily.csv", parse_dates=["date"], index_col="date")

# Або з JSON (поширено у відповідях API)
df = pd.read_json("https://api.example.com/candles?symbol=ETH")

# Швидка інспекція
print(df.shape)          # (365, 5)
print(df.dtypes)         # Типи колонок
print(df.describe())     # Статистичне резюме
print(df.tail())         # Останні 5 рядків

Що робить pandas незамінним для фінансів — це його DatetimeIndex. Щойно ваш індекс має тип datetime, ви відкриваєте потужні операції з часовими рядами:

# Виріз за діапазоном дат
q1_data = df["2025-01":"2025-03"]

# Ресемплінг денних даних до тижневого OHLC
weekly = df["close"].resample("W").ohlc()

# Заповнення пропущених даних вперед (вихідні, свята)
df = df.asfreq("D").ffill()

Ці операції обробляють неохайні реалії фінансових даних — розриви, різниці часових зон, нерегулярні часові позначки — так, щоб ви могли зосередитися на аналізі, а не на «сантехніці» даних.

Ковзні обчислення: ковзні середні та волатильність

Фінансовий аналіз за своєю суттю є віконним. Ви рідко переймаєтеся однією точкою даних окремо — контекст походить із того, як вона співвідноситься з нещодавньою історією. Метод .rolling() у pandas — ваш основний інструмент для цього.

import pandas as pd
import numpy as np

# Припустимо, df має колонку "close" з DatetimeIndex
df["sma_20"] = df["close"].rolling(20).mean()
df["sma_50"] = df["close"].rolling(50).mean()
df["ema_12"] = df["close"].ewm(span=12).mean()

# Денні доходності та ковзна волатильність
df["returns"] = df["close"].pct_change()
df["vol_30d"] = df["returns"].rolling(30).std() * np.sqrt(365)

# Смуги Боллінджера
df["bb_upper"] = df["sma_20"] + 2 * df["close"].rolling(20).std()
df["bb_lower"] = df["sma_20"] - 2 * df["close"].rolling(20).std()

# Ковзна кореляція між двома активами
df["corr_btc_eth"] = df["btc_returns"].rolling(60).corr(df["eth_returns"])

Ключові ковзні обчислення, які має знати кожен трейдер:

  • Проста ковзна середня (SMA) — рівнозважене середнє за N періодів. Запізнюється, але стабільна.
  • Експоненційна ковзна середня (EMA) — надає більшу вагу нещодавнім даним через .ewm(). Реагує швидше на зміни ціни.
  • Ковзна волатильність — стандартне відхилення доходностей за вікном, річна. Необхідна для розрахунку розміру позицій та ризик-бюджетів.
  • Ковзна кореляція — вимірює, наскільки два активи рухаються разом протягом часу. Критично важлива для диверсифікації портфеля.

На платформах, як GaiaEx, ви можете отримати історичні дані свічок через торговий API, завантажити їх у DataFrame pandas і обчислити ці індикатори за секунди — поки ваші активи залишаються безпечними у вашому MPC-гаманці.

GroupBy та агрегація для аналізу портфеля

Коли ви керуєте кількома активами, .groupby() стає незамінним. Він дозволяє розбити дані за категоріями, застосувати обчислення й об'єднати результати — шаблон split-apply-combine (розділити-застосувати-об'єднати).

# DataFrame з кількома активами
trades = pd.DataFrame({
    "symbol": ["BTC", "ETH", "BTC", "SOL", "ETH", "BTC"],
    "side": ["buy", "buy", "sell", "buy", "sell", "buy"],
    "pnl": [120.5, -45.2, 89.0, 210.3, 55.8, -30.1],
    "volume": [5000, 3200, 4800, 1500, 2900, 5100],
})

# Ефективність за активом
summary = trades.groupby("symbol").agg(
    total_pnl=("pnl", "sum"),
    avg_pnl=("pnl", "mean"),
    trade_count=("pnl", "count"),
    total_volume=("volume", "sum"),
    win_rate=("pnl", lambda x: (x > 0).mean()),
)

print(summary.sort_values("total_pnl", ascending=False))

Розширені паттерни агрегації для роботи з портфелем:

  • Багаторівневий groupby — групування за активом і стороною, щоб побачити ефективність лонгів проти шортів для кожного активу.
  • Власні функції агрегації — обчислення коефіцієнтів Шарпа, Сортіно, або максимальної просадки для кожної групи активів.
  • Зведені таблиці (Pivot tables) — переформатування даних для перегляду щомісячних доходностей за активом у форматі, придатному для теплокарти, за допомогою pd.pivot_table().
  • Ресемплінг з groupby — поєднання ресемплінгу на основі часу з категоріальним групуванням для аналізу часових рядів кількох активів.

Matplotlib: побудова графіків цінового руху та сигналів

Дані без візуалізації — це просто числа. Matplotlib перетворює ваш аналіз на графіки, що виявляють паттерни, невидимі в необроблених даних.

import matplotlib.pyplot as plt
import matplotlib.dates as mdates

fig, axes = plt.subplots(3, 1, figsize=(14, 10),
                         sharex=True, gridspec_kw={"height_ratios": [3, 1, 1]})

# Ціна + Ковзні середні
axes[0].plot(df.index, df["close"], label="Close", linewidth=1.2)
axes[0].plot(df.index, df["sma_20"], label="SMA 20", linestyle="--")
axes[0].fill_between(df.index, df["bb_upper"], df["bb_lower"],
                     alpha=0.1, color="blue", label="Bollinger Bands")
axes[0].set_ylabel("Price (USD)")
axes[0].legend(loc="upper left")

# Стовпчики обсягу
colors = ["green" if c > o else "red"
          for c, o in zip(df["close"], df["open"])]
axes[1].bar(df.index, df["volume"], color=colors, alpha=0.7)
axes[1].set_ylabel("Volume")

# Ковзна волатильність
axes[2].plot(df.index, df["vol_30d"], color="purple")
axes[2].set_ylabel("30d Volatility")
axes[2].axhline(y=0.8, color="red", linestyle=":", alpha=0.5)

axes[2].xaxis.set_major_formatter(mdates.DateFormatter("%b %Y"))
plt.tight_layout()
plt.savefig("analysis_dashboard.png", dpi=150)
plt.show()

Це створює професійну панель із трьома блоками: ціновий рух зі смугами Боллінджера зверху, обсяг у середині, і волатильність знизу. Цей макет віддзеркалює те, що ви побачили б на професійних торгових терміналах.

Для статистичної візуалізації seaborn будується на Matplotlib із функціями вищого рівня:

import seaborn as sns

# Розподіл доходностей
sns.histplot(df["returns"].dropna(), bins=100, kde=True)

# Теплокарта кореляції між активами
corr_matrix = portfolio_returns.corr()
sns.heatmap(corr_matrix, annot=True, cmap="RdYlGn", center=0)
Pandas → аналіз; Matplotlib → інсайт DataFrame індекс + колонки rolling resample groupby Метрики Series доходність, волатильність, Sharpe matplotlib.pyplot — figure, axes, artists ціна обсяг індикатори seaborn необов'язковий — той самий шар Artist, гарніші стандартні налаштування
Pandas готує впорядковані таблиці; Matplotlib відображає їх на осях, які ви можете анотувати й поширювати.

Складаємо все разом: повний конвеєр аналізу

Справжня сила виникає, коли ви об'єднуєте ці інструменти у повторюваний конвеєр. Ось робочий процес, який професійні квант-аналітики використовують щодня:

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

def analyze_asset(symbol: str, df: pd.DataFrame) -> dict:
    """Повний конвеєр аналізу для одного активу."""
    df["returns"] = df["close"].pct_change()
    df["log_returns"] = np.log(df["close"] / df["close"].shift(1))

    return {
        "symbol": symbol,
        "total_return": (df["close"].iloc[-1] / df["close"].iloc[0]) - 1,
        "annual_vol": df["returns"].std() * np.sqrt(365),
        "sharpe": df["returns"].mean() / df["returns"].std() * np.sqrt(365),
        "max_drawdown": (df["close"] / df["close"].cummax() - 1).min(),
        "skewness": df["returns"].skew(),
        "kurtosis": df["returns"].kurtosis(),
    }

# Аналіз кількох активів
results = [analyze_asset(sym, data) for sym, data in assets.items()]
summary = pd.DataFrame(results).set_index("symbol")
print(summary.round(4))

Цей конвеєр бере необроблені цінові дані й видає комплексний профіль ризику й доходності для кожного активу. Звідси ви можете подавати ці метрики в оптимізатор портфеля, генерувати рекомендації щодо розподілу, або запускати сигнали ребалансування.

Стек pandas-NumPy-Matplotlib — це основа, на якій будується все інше у Python-фінансах. Опануйте ці три бібліотеки, і у вас будуть навички аналізувати будь-який ринок, будувати будь-який індикатор і візуалізувати будь-яку стратегію — незалежно від того, торгуєте ви акціями на NYSE, криптою на GaiaEx, чи деривативами на CME.