Разработка маркетплейса торговых стратегий
Маркетплейс торговых стратегий — это платформа, где разработчики публикуют алгоритмические стратегии, а пользователи подписываются и запускают их на своих аккаунтах. По модели работает как App Store, только вместо приложений — торговые алгоритмы.
Архитектура платформы
Strategy Runtime — среда исполнения стратегий. Каждая стратегия запускается в изолированном контейнере с ограниченными ресурсами и доступом только к разрешённым API.
Strategy SDK — набор инструментов для разработчиков стратегий: типизированные интерфейсы, доступ к рыночным данным, возможность выставления ордеров через платформенный API.
Backtesting Integration — автоматический бэктест каждой стратегии перед публикацией.
Marketplace Frontend — каталог стратегий с фильтрацией, детальными карточками, системой подписок.
Billing System — приём платежей за подписки, распределение между платформой и разработчиком.
Strategy SDK
# Интерфейс для разработчиков стратегий
from abc import ABC, abstractmethod
class StrategyBase(ABC):
"""Базовый класс для всех стратегий на платформе"""
def __init__(self, context: StrategyContext):
self.ctx = context
@abstractmethod
async def on_candle(self, candle: Candle) -> None:
"""Вызывается при закрытии каждой свечи"""
async def on_trade(self, trade: Trade) -> None:
"""Опционально: вызывается при каждой сделке"""
async def on_order_update(self, order: Order) -> None:
"""Опционально: вызывается при изменении статуса ордера"""
# Доступные методы через context
async def buy_market(self, quantity: float) -> Order:
return await self.ctx.place_order('BUY', 'MARKET', quantity=quantity)
async def sell_market(self, quantity: float) -> Order:
return await self.ctx.place_order('SELL', 'MARKET', quantity=quantity)
def get_position(self) -> float:
return self.ctx.position.quantity
def get_balance(self) -> float:
return self.ctx.balance.usdt
# Пример простой стратегии от разработчика
class RSICrossStrategy(StrategyBase):
"""EMA crossover + RSI фильтр"""
def __init__(self, context, fast_period=9, slow_period=21, rsi_period=14):
super().__init__(context)
self.fast_ema = EMA(fast_period)
self.slow_ema = EMA(slow_period)
self.rsi = RSI(rsi_period)
async def on_candle(self, candle: Candle):
fast = self.fast_ema.update(candle.close)
slow = self.slow_ema.update(candle.close)
rsi = self.rsi.update(candle.close)
position = self.get_position()
if fast > slow and rsi < 70 and position == 0:
await self.buy_market(quantity=self.get_balance() * 0.95 / candle.close)
elif fast < slow and position > 0:
await self.sell_market(quantity=position)
Изоляция и безопасность
Стратегии запускают чужой код — это серьёзный security-риск. Меры защиты:
Docker контейнеры с ограничениями ресурсов:
# docker-compose.strategy.yml
services:
strategy-runner:
image: strategy-runtime:latest
mem_limit: 256m
cpus: 0.5
network_mode: none # нет прямого доступа к сети
read_only: true # read-only filesystem
security_opt:
- no-new-privileges:true
cap_drop:
- ALL
Сетевая изоляция — стратегия не может делать произвольные HTTP-запросы. Весь доступ к данным — через платформенные API внутри изолированной сети.
Code review — ручная проверка кода перед публикацией для новых разработчиков.
Sandbox тестирование — автоматический запуск в sandbox среде с проверкой на подозрительное поведение.
Backtesting Pipeline для публикации
Каждая стратегия перед публикацией должна пройти обязательный бэктест:
class PublicationPipeline:
REQUIRED_BACKTEST_PERIOD = 365 # дней
async def process_submission(self, strategy: StrategySubmission) -> PublicationResult:
# 1. Статический анализ кода
lint_result = await self.code_linter.check(strategy.code)
if lint_result.has_errors:
return PublicationResult.rejected(lint_result.errors)
# 2. Автоматический бэктест
backtest = await self.backtester.run(
strategy=strategy,
symbol=strategy.config.symbol,
period_days=self.REQUIRED_BACKTEST_PERIOD,
)
# 3. Проверка минимальных метрик
if backtest.sharpe_ratio < 0.5:
return PublicationResult.rejected("Sharpe ratio below minimum threshold")
if backtest.max_drawdown > 0.5:
return PublicationResult.rejected("Max drawdown exceeds 50%")
# 4. Публикация
published = await self.publish(strategy, backtest)
return PublicationResult.approved(published.id)
Монетизация для разработчиков
Несколько моделей:
Monthly Subscription — фиксированная плата в месяц. Простая модель, предсказуемый доход.
Performance Fee — % от прибыли подписчика. Align incentives: разработчик зарабатывает только когда зарабатывает пользователь.
One-time Purchase — разовая оплата за доступ к стратегии.
Free + Upsell — базовая версия бесплатно, advanced параметры — платно.
Расчёт дохода разработчика:
def calculate_developer_payout(subscription: Subscription, performance: PerformanceData) -> Decimal:
if subscription.model == 'MONTHLY':
platform_fee = subscription.price * Decimal('0.30')
return subscription.price - platform_fee
elif subscription.model == 'PERFORMANCE':
profit = performance.follower_profit
if profit <= 0:
return Decimal(0)
developer_share = profit * subscription.performance_fee_pct
platform_fee = developer_share * Decimal('0.30')
return developer_share - platform_fee
UI: карточка стратегии
Ключевые данные для принятия решения о подписке: graph P&L по времени, max drawdown, Sharpe ratio, win rate, количество активных подписчиков, средняя длительность позиции, поддерживаемые биржи и символы, описание логики на человеческом языке, история версий стратегии.
Прозрачность — ключевой фактор доверия: пользователи должны понимать что делает стратегия, даже не видя код.







