Проблемы item-to-item рекомендаций одежды
Какие особенности и риски есть у item-to-item рекомендаций в fashion каталоге?
Сначала проговорите ответ вслух или тезисами.
Формулы, план решения, риски и примеры.
Откройте разбор только после своей попытки.
Показать разбор
Короткий ответ
В fashion важны визуальная похожесть, размер/пол/стиль, сезонность, availability и cold-start; pure co-click similarity часто ловит popularity bias.
Подробный разбор
Item-to-item в одежде нельзя сводить только к "что часто покупают вместе". Нужно разделять заменители и complements, учитывать размеры, gender/fit, бренд, цвет, стиль, цену, сезонность и наличие на складе.
Классические риски: popularity bias, устаревшие товары, нехватка истории для новых SKU, leakage из будущих заказов, плохая персонализация и отсутствие diversity. Хорошая схема часто смешивает collaborative signals, content/image embeddings и business constraints, а offline метрики дополняет online CTR/conversion и user satisfaction.
Почему time-series модель может развалиться после хорошего offline
Модель на временном ряде показывает хороший offline score, но в реальности не работает. Какие причины проверить первыми?
Сначала проговорите ответ вслух или тезисами.
Формулы, план решения, риски и примеры.
Откройте разбор только после своей попытки.
Показать разбор
Короткий ответ
Первое - leakage, random split, неверный prediction horizon, признаки из будущего и train/test режим, который не имитирует реальный момент решения.
Подробный разбор
Для временных рядов offline должен имитировать будущее: train на прошлом, validation на будущем. Нужно проверить rolling features, normalization, joins, target shift и любые признаки, которые используют данные после момента решения.
Хороший random split почти ничего не доказывает: соседние точки временного ряда похожи, окна могут пересекаться, а scaler или агрегаты могли быть fit на full dataset. Отдельно проверяют drift, costs/latency и gap между моментом наблюдения признаков и моментом предсказания.
Как получить уверенность модели в предсказании
Модель дает prediction для trading/time-series задачи. Как оценить confidence и использовать его в решении?
Сначала проговорите ответ вслух или тезисами.
Формулы, план решения, риски и примеры.
Откройте разбор только после своей попытки.
Показать разбор
Короткий ответ
Confidence можно брать из calibrated probability, uncertainty estimate или empirical reliability по бинам score; score модели сам по себе не всегда является уверенностью.
Подробный разбор
Важно отделить score модели от настоящей уверенности. Для классификации проверяют calibration curve, Brier/log loss, reliability bins и expected calibration error. Для регрессии можно строить prediction intervals, quantile models или ансамбли.
В trading confidence обычно связывают с threshold и размером позиции, но это нужно проверять out-of-time: бины с большим confidence должны иметь лучший realized outcome. Иначе модель может быть уверена только на train distribution.
HFT/time-series задача: постановка и признаки
Даны временные рыночные данные для HFT-задачи. Как подойти к постановке target, построению признаков, валидации и первому baseline?
Сначала проговорите ответ вслух или тезисами.
Формулы, план решения, риски и примеры.
Откройте разбор только после своей попытки.
Показать разбор
Короткий ответ
Нужно сначала зафиксировать target и горизонт прогноза, затем строить признаки только из прошлого, валидироваться по времени и отдельно проверять leakage, latency и устойчивость на новых периодах.
Подробный разбор
Для HFT/time-series задачи нельзя начинать с модели. Сначала нужно понять, что именно предсказываем: направление цены, доходность, вероятность движения, spread или другой target. Потом фиксируем горизонт прогноза и момент времени, в который модель должна принять решение.
Дальше признаки: лаги цены/объема, rolling statistics, imbalance, spread, volatility, агрегаты по окнам и признаки микроструктуры рынка. Все они должны считаться только из информации, доступной до момента предсказания.
Валидация должна быть временной: train на прошлом, validation на будущем, без random split. Для финансовых рядов особенно важно проверить leakage через нормализацию, rolling features, future joins и неявное использование будущих строк.
Baseline: простой rule-based или линейная модель/GBDT на лаговых признаках. Только после него имеет смысл обсуждать sequence-модели, если есть достаточно данных и понятная latency/cost граница.
Типичные ошибки
- Использовать random split для временного ряда.
- Считать rolling features или normalization по всему датасету.
- Начать с Transformer без target, горизонта и baseline.
Как сказать на собеседовании
- Сначала спроси target, горизонт и момент принятия решения.
- Отдельно проговори, какие признаки доступны online, а какие являются leakage.
Trades и order book как источники признаков
Какие сигналы обычно извлекают из trades и order book при HFT-задаче прогноза цены?
Сначала проговорите ответ вслух или тезисами.
Формулы, план решения, риски и примеры.
Откройте разбор только после своей попытки.
Показать разбор
Короткий ответ
Из стакана берут bid/ask, spread, mid-price, depth/imbalance; из trades - signed volume, intensity, VWAP и агрегации по коротким окнам.
Подробный разбор
Order book дает состояние ликвидности: best bid/ask, mid-price, spread, объемы на уровнях, imbalance между bid/ask, slope/depth и изменения этих величин. Trades дают фактическую агрессию рынка: price, size, side/sign, trade count, volume, VWAP и burst intensity.
Так как события нерегулярные, признаки часто выравнивают на регулярную временную сетку: forward-fill для состояния стакана, rolling aggregations для сделок и lag features. Критично фиксировать момент доступности каждого признака, иначе легко заглянуть в будущее.
Как выбрать target для HFT mid-price prediction
Даны trades и order book. Как сформулировать target для предсказания будущего движения mid-price?
Сначала проговорите ответ вслух или тезисами.
Формулы, план решения, риски и примеры.
Откройте разбор только после своей попытки.
Показать разбор
Короткий ответ
Нужно зафиксировать decision time, horizon и форму target: future return, direction, thresholded move или no-trade/up/down с учетом spread и costs.
Подробный разбор
Target должен соответствовать действию модели. Например, можно предсказывать relative change mid-price через 100 ms или 1 s, знак движения после учета spread/cost, или вероятность движения выше threshold.
Нельзя строить target так, чтобы признаки случайно видели будущее окно. Для шумных HFT-данных часто вводят no-trade class или threshold, чтобы не заставлять модель предсказывать микрошум, который не покрывает транзакционные издержки.
Time grid и признаки из нерегулярных HFT событий
Как построить feature matrix на регулярной 100 ms сетке из нерегулярных trades и order book events?
Сначала проговорите ответ вслух или тезисами.
Формулы, план решения, риски и примеры.
Откройте разбор только после своей попытки.
Показать разбор
Короткий ответ
Сетка задает decision timestamps; state features forward-fill-ятся из последнего стакана, trades агрегируются только из прошлого окна.
Подробный разбор
Сначала выбирается регулярная сетка timestamp-ов, например каждые 100 ms. Для order book state на каждую точку берется последний известный snapshot не позже timestamp: best bid/ask, mid, spread, imbalance и depth. Для trades считаются rolling или bucket aggregations за прошлые окна: count, volume, signed volume, VWAP, max/min price.
Нельзя использовать события после decision timestamp. Target должен быть смещен в будущее, например future mid-price return через заданный horizon. Для train/test split нужен temporal split с gap, иначе rolling windows и forward-fill могут протащить leakage между выборками.
Feature builder для Coinbase/Binance time grid
Нужно собрать признаки для HFT lead-lag датасета.
Даны:
- регулярная сетка времени
grid; - нерегулярные обновления L1 order book для Binance и Coinbase;
- нерегулярные сделки с обеих бирж.
Для каждого grid_ts нужно построить строку признаков, используя только события с timestamp <= grid_ts.
Для каждого стакана сделайте forward fill последнего известного bid/ask и верните:
bn_mid,bn_spread,bn_bid_size,bn_ask_size;cb_mid,cb_spread,cb_bid_size,cb_ask_size.
Для сделок посчитайте суммарный notional price * amount в окне (previous_grid_ts, grid_ts] отдельно по бирже и стороне:
binance_buy_notional,binance_sell_notional;coinbase_buy_notional,coinbase_sell_notional.
Если для стакана еще нет значения, верните None. Если сделок в окне нет, верните 0.0.
Сигнатура
def build_time_grid_features(
grid: list[int],
l1_binance: list[dict],
l1_coinbase: list[dict],
trades: list[dict],
) -> list[dict]:Решение прямо на странице
Напишите код, запустите проверки и только потом открывайте разбор.
Нажмите «Запустить проверки» или Ctrl+Enter.
Показать разбор
Подсказки
- Forward fill
Для каждого grid_ts нужен последний L1 update с ts <= grid_ts.
- Окна сделок
Используйте (previous_grid_ts, grid_ts], чтобы сделка на границе не попала в два окна.
Идея решения
Сортируем сетку, стаканы и сделки по времени. Дальше идем sweep-line по grid.
Для каждой биржи держим последний L1 update с ts <= grid_ts; это и есть forward fill. Mid-price считается как (bid + ask) / 2, spread как ask - bid.
Сделки агрегируем указателем по полуоткрытому окну (previous_grid_ts, grid_ts]. Это важно, чтобы сделка на границе попала ровно в одно окно.
Эталонный код
def build_time_grid_features(
grid: list[int],
l1_binance: list[dict],
l1_coinbase: list[dict],
trades: list[dict],
) -> list[dict]:
grid = sorted(grid)
books = {
'bn': sorted(l1_binance, key=lambda row: row['ts']),
'cb': sorted(l1_coinbase, key=lambda row: row['ts']),
}
pointers = {'bn': 0, 'cb': 0}
last = {'bn': None, 'cb': None}
trades = sorted(trades, key=lambda row: row['ts'])
trade_index = 0
def add_book_features(row: dict, prefix: str, book) -> None:
if book is None:
row[f'{prefix}_mid'] = None
row[f'{prefix}_spread'] = None
row[f'{prefix}_bid_size'] = None
row[f'{prefix}_ask_size'] = None
return
row[f'{prefix}_mid'] = (book['bid_price'] + book['ask_price']) / 2
row[f'{prefix}_spread'] = book['ask_price'] - book['bid_price']
row[f'{prefix}_bid_size'] = book['bid_size']
row[f'{prefix}_ask_size'] = book['ask_size']
result: list[dict] = []
previous_grid_ts = None
for grid_ts in grid:
for prefix, updates in books.items():
while pointers[prefix] < len(updates) and updates[pointers[prefix]]['ts'] <= grid_ts:
last[prefix] = updates[pointers[prefix]]
pointers[prefix] += 1
row = {'ts': grid_ts}
add_book_features(row, 'bn', last['bn'])
add_book_features(row, 'cb', last['cb'])
buckets = {
'binance_buy_notional': 0.0,
'binance_sell_notional': 0.0,
'coinbase_buy_notional': 0.0,
'coinbase_sell_notional': 0.0,
}
lower_bound = float('-inf') if previous_grid_ts is None else previous_grid_ts
while trade_index < len(trades) and trades[trade_index]['ts'] <= grid_ts:
trade = trades[trade_index]
if trade['ts'] > lower_bound:
exchange = trade['exchange'].lower()
side = trade['side'].lower()
buckets[f'{exchange}_{side}_notional'] += trade['price'] * trade['amount']
trade_index += 1
row.update(buckets)
result.append(row)
previous_grid_ts = grid_ts
return resultПочему CatBoost, а не линейная модель
В time-series табличной задаче кандидат выбирает CatBoost. Как объяснить выбор и какой baseline нужен?
Сначала проговорите ответ вслух или тезисами.
Формулы, план решения, риски и примеры.
Откройте разбор только после своей попытки.
Показать разбор
Короткий ответ
CatBoost ловит нелинейности и interactions, но его нужно сравнить с naive, linear/ridge и простыми rules на temporal validation.
Подробный разбор
Сильный ответ не продает CatBoost как магию. Сначала baseline: константа, last value, линейная модель на лагах и простые rules. Потом GBDT, если есть нелинейные зависимости, разные масштабы признаков и interactions.
Улучшение должно быть на temporal validation, без leakage. Для HFT/time-series также важно проверить стабильность по периодам, sensitivity к drift и связь offline metric с trading proxy или PnL after costs.
Как понять, хороший ли MSE на тесте
Модель получила MSE на тестовом периоде. Как понять, хороший это результат или нет?
Сначала проговорите ответ вслух или тезисами.
Формулы, план решения, риски и примеры.
Откройте разбор только после своей попытки.
Показать разбор
Короткий ответ
MSE имеет смысл только относительно baseline, масштаба target, variance и бизнес-метрики; маленький MSE не гарантирует полезный trading signal.
Подробный разбор
Нужно сравнить MSE с константным прогнозом, last value, линейной моделью и variance target. Без baseline число MSE почти невозможно интерпретировать.
Для trading маленький MSE не гарантирует прибыль: важны направление, ranking, threshold, calibration и proxy-PnL после costs. Также стоит смотреть стабильность по периодам и slice metrics, потому что средняя ошибка может скрывать деградацию на волатильных режимах.
PnL proxy по предсказаниям движения цены
Есть предсказания будущего изменения цены в basis points и фактически реализованные изменения.
Нужно построить простую proxy-метрику без полноценного бэктестера:
- если
prediction > threshold_bps, открываем long; - если
prediction < -threshold_bps, открываем short; - иначе не торгуем.
PnL одной сделки в bps:
- для long:
realized_bps; - для short:
-realized_bps.
Из каждой сделки вычитается fee_bps.
Сигнатура
def pnl_proxy(predicted_bps: list[int], realized_bps: list[int], threshold_bps: int = 0, fee_bps: int = 0) -> dict:
Верните словарь с ключами trades, hits, hit_rate, gross_bps, net_bps.
Решение прямо на странице
Напишите код, запустите проверки и только потом открывайте разбор.
Нажмите «Запустить проверки» или Ctrl+Enter.
Показать разбор
Подсказки
- Сигнал, а не magnitude
В этой proxy-метрике prediction используется для выбора long/short/no-trade.
- Комиссия за сделку
Fee вычитается из net PnL один раз за каждую открытую позицию.
Идея решения
Сначала переводим prediction в торговый сигнал: 1 для long, -1 для short и 0 для no-trade.
Gross PnL сделки равен signal * realized_bps. Hit — это сделка с положительным gross PnL. Net PnL дополнительно вычитает комиссию за каждую сделку.
Эталонный код
def pnl_proxy(predicted_bps: list[int], realized_bps: list[int], threshold_bps: int = 0, fee_bps: int = 0) -> dict:
if len(predicted_bps) != len(realized_bps):
raise ValueError('predicted_bps and realized_bps must have the same length')
trades = 0
hits = 0
gross_bps = 0
for prediction, realized in zip(predicted_bps, realized_bps):
if prediction > threshold_bps:
signal = 1
elif prediction < -threshold_bps:
signal = -1
else:
signal = 0
if signal == 0:
continue
trade_pnl = signal * realized
trades += 1
gross_bps += trade_pnl
if trade_pnl > 0:
hits += 1
hit_rate = None if trades == 0 else hits / trades
net_bps = gross_bps - trades * fee_bps
return {
'trades': trades,
'hits': hits,
'hit_rate': hit_rate,
'gross_bps': gross_bps,
'net_bps': net_bps,
}Ревью notebook: leakage и gap между train/test
На ревью notebook для временного ряда нужно найти leakage. Что проверять в feature generation и split?
Сначала проговорите ответ вслух или тезисами.
Формулы, план решения, риски и примеры.
Откройте разбор только после своей попытки.
Показать разбор
Короткий ответ
Проверяем, что все признаки считаются только из прошлого, split идет по времени, а между train/test есть gap при пересекающихся окнах.
Подробный разбор
Типовые ошибки: rolling по всему датасету, scaler fit на full data, target-window пересекается с feature-window, random split, join будущих данных и использование признаков, которые в production станут доступны позже.
Gap нужен, если target или rolling features используют соседние интервалы и иначе train косвенно видит test. Хорошее ревью также проверяет reproducibility, backtest slices, feature freshness и связь offline score с proxy business или trading metric.
Walk-forward splits с gap для временного ряда
Для временных рядов нельзя делать random split: validation должен идти после train по времени.
Напишите функцию, которая строит n_folds walk-forward splits. Каждый split использует expanding train prefix, затем optional gap, затем validation window фиксированного размера.
Индексы полуоткрытые: [start, end).
Сигнатура
def walk_forward_splits(n_samples: int, n_folds: int, validation_size: int, gap: int = 0) -> list[dict]:
Каждый элемент результата:
{"train_start": 0, "train_end": ..., "valid_start": ..., "valid_end": ...}Решение прямо на странице
Напишите код, запустите проверки и только потом открывайте разбор.
Нажмите «Запустить проверки» или Ctrl+Enter.
Показать разбор
Подсказки
- Validation окна в конце
Сначала найдите start первого validation окна: n_samples - n_folds * validation_size.
- Gap вычитается из train_end
Validation все равно начинается в valid_start, а train должен закончиться раньше на gap.
Идея решения
Последние n_folds * validation_size наблюдений отводим под последовательные validation окна.
Для каждого окна valid_start:valid_end train идет от нуля до valid_start - gap. Gap нужен, когда признаки используют lag/rolling windows или есть задержка между данными и моментом предсказания.
Эталонный код
def walk_forward_splits(n_samples: int, n_folds: int, validation_size: int, gap: int = 0) -> list[dict]:
if n_samples <= 0 or n_folds <= 0 or validation_size <= 0 or gap < 0:
raise ValueError('invalid split parameters')
first_valid_start = n_samples - n_folds * validation_size
if first_valid_start <= gap:
raise ValueError('not enough samples for the requested splits')
splits = []
for fold in range(n_folds):
valid_start = first_valid_start + fold * validation_size
valid_end = valid_start + validation_size
train_end = valid_start - gap
splits.append({
'train_start': 0,
'train_end': train_end,
'valid_start': valid_start,
'valid_end': valid_end,
})
return splitsКакую deep learning архитектуру выбрать для временного ряда
После градиентного бустинга: если смотреть в сторону deep learning, какую архитектуру предложить для последовательных данных или временного ряда и почему?
Сначала проговорите ответ вслух или тезисами.
Формулы, план решения, риски и примеры.
Откройте разбор только после своей попытки.
Показать разбор
Короткий ответ
Для последовательностей можно предложить TCN/LSTM/Transformer, но выбор зависит от длины истории, latency, объема данных и требований к интерпретируемости. Часто стартуют с агрегированных временных признаков и легкой sequence-модели.
Подробный разбор
Ответ должен идти от данных. Если есть временной ряд или последовательность событий, можно использовать LSTM/GRU, TCN или Transformer. Для длинных зависимостей и большого объема данных Transformer гибче, но дороже. Для latency-sensitive задач часто разумнее TCN или компактная recurrent модель.
Нужно объяснить вход: сырые события, агрегированные окна, признаки стакана/каталога/пользователя, временные embeddings, маски, normalization. Если данные очень частые, их обычно агрегируют до разумного resolution, иначе модель будет дорогой и шумной.
Сравнение с GBDT важно: deep learning имеет смысл при больших данных, сложных последовательных паттернах и достаточной инфраструктуре. Иначе бустинг на аккуратных rolling features может быть сильнее и проще в production.
Типичные ошибки
- Автоматически выбирать Transformer без обсуждения latency и данных.
- Не описать, какие именно последовательности подаются на вход.
- Не сравнить с сильным baseline на бустинге.
Как сказать на собеседовании
- Начни с baseline: GBDT на rolling features.
- Потом предложи sequence model и явно назови, когда она должна выиграть.