trading-strategies
agentmc15/polymarket-trader
Framework for developing, testing, and deploying trading strategies for prediction markets.
What is trading-strategies?
A Python framework for building, backtesting, and deploying trading strategies on prediction markets like Polymarket. Provides base classes and implementations for arbitrage, copy trading, momentum, and mean reversion strategies with signal generation and position sizing.
- Define custom trading strategies by extending BaseStrategy with market analysis logic
- Generate buy/sell/hold signals with confidence scores based on market conditions
- Calculate appropriate position sizes based on portfolio value and signal confidence
- Implement arbitrage detection for pricing inefficiencies across markets
- Track and copy trades from successful traders with configurable size scaling
- Analyze price momentum, volume ratios, and orderbook imbalance for trading signals
How to install trading-strategies
npx skills add https://github.com/agentmc15/polymarket-trader --skill trading-strategies- Python 3.7+
- Access to Polymarket market data (prices, orderbook, recent trades)
- Historical price data for backtesting (if using mean reversion or momentum strategies)
How to use trading-strategies
- 1.Create a new strategy class inheriting from BaseStrategy
- 2.Implement the analyze() method to generate signals based on MarketState data
- 3.Implement calculate_position_size() to determine trade sizes
- 4.Configure strategy parameters (thresholds, lookback periods, confidence minimums)
- 5.Call analyze() with current market state to receive trading signals
- 6.Check should_execute() before executing signals to filter by confidence threshold
- 7.Track signal history and positions for performance monitoring
Use cases
- Detect and exploit YES+NO price imbalances in prediction markets
- Automatically mirror trades from high-performing traders with scaled position sizes
- Trade price momentum when volume spikes and orderbook shows directional bias
- Buy oversold positions and sell overbought positions based on historical mean prices
- Backtest strategy performance before deploying real capital
- Quantitative traders building prediction market bots
- Developers creating algorithmic trading systems for Polymarket
- Traders wanting to automate arbitrage or copy-trading strategies
- Anyone backtesting trading logic before live deployment
trading-strategies FAQ
MarketState requires token_id, yes_price, no_price, volume_24h, open_interest, orderbook (with bids/asks), recent_trades list, and timestamp.
Collect historical MarketState snapshots, replay them through your strategy's analyze() method, and compare signals against actual price movements.
Yes, you can run multiple strategy instances in parallel and aggregate their signals, or create a composite strategy that weights multiple analysis methods.
A 0-1 value indicating how strongly the strategy believes in the signal; used by should_execute() to filter low-conviction trades.
Pass your current portfolio_value to calculate_position_size() which scales positions appropriately; each strategy type implements its own sizing logic.
Full instructions (SKILL.md)
Source of truth, from agentmc15/polymarket-trader.
name: trading-strategies description: Framework for developing, testing, and deploying trading strategies for prediction markets. Use when creating new strategies, implementing signals, or building backtesting logic.
Trading Strategy Development Skill
Strategy Base Class
from abc import ABC, abstractmethod
from dataclasses import dataclass
from typing import Optional
from datetime import datetime
from enum import Enum
class SignalType(Enum):
BUY = "buy"
SELL = "sell"
HOLD = "hold"
@dataclass
class Signal:
type: SignalType
token_id: str
price: float
size: float
confidence: float # 0-1
timestamp: datetime
metadata: dict = None
@dataclass
class MarketState:
token_id: str
yes_price: float
no_price: float
volume_24h: float
open_interest: float
orderbook: dict
recent_trades: list
timestamp: datetime
class BaseStrategy(ABC):
"""Base class for all trading strategies."""
def __init__(self, config: dict):
self.config = config
self.positions = {}
self.signals_history = []
@abstractmethod
async def analyze(self, market: MarketState) -> Optional[Signal]:
"""Analyze market and generate signal."""
pass
@abstractmethod
def calculate_position_size(
self,
signal: Signal,
portfolio_value: float
) -> float:
"""Calculate appropriate position size."""
pass
def should_execute(self, signal: Signal) -> bool:
"""Determine if signal should be executed."""
return signal.confidence >= self.config.get("min_confidence", 0.6)
Strategy Types
1. Arbitrage Strategy
class ArbitrageStrategy(BaseStrategy):
"""Detect and exploit pricing inefficiencies."""
async def find_opportunities(
self,
markets: list[MarketState]
) -> list[Signal]:
opportunities = []
# Check YES + NO > 1 (overpriced)
for market in markets:
total = market.yes_price + market.no_price
if total > 1.02: # 2% threshold
opportunities.append(
self._create_arb_signal(market, "overpriced", total)
)
# Check related markets
opportunities.extend(
await self._find_related_arbs(markets)
)
return opportunities
async def analyze(self, market: MarketState) -> Optional[Signal]:
total = market.yes_price + market.no_price
# Overpriced market (YES + NO > 1)
if total > 1.0 + self.config.get("arb_threshold", 0.02):
profit_pct = (total - 1.0) * 100
return Signal(
type=SignalType.SELL,
token_id=market.token_id,
price=total,
size=self.config.get("default_size", 100),
confidence=min(profit_pct / 10, 1.0),
timestamp=datetime.utcnow(),
metadata={"arb_type": "overpriced", "profit_pct": profit_pct}
)
return None
2. Copy Trading Strategy
class CopyTradingStrategy(BaseStrategy):
"""Mirror trades of successful traders."""
def __init__(self, config: dict):
super().__init__(config)
self.tracked_traders = config.get("tracked_traders", [])
self.trade_delay = config.get("delay_seconds", 30)
self.size_multiplier = config.get("size_multiplier", 0.5)
async def process_trader_activity(
self,
trader_address: str,
trade: dict
) -> Optional[Signal]:
"""Generate signal based on tracked trader activity."""
if trader_address not in self.tracked_traders:
return None
trader_score = await self._get_trader_score(trader_address)
return Signal(
type=SignalType.BUY if trade["side"] == "BUY" else SignalType.SELL,
token_id=trade["token_id"],
price=trade["price"],
size=self._scale_size(trade["size"], trader_score),
confidence=trader_score,
timestamp=datetime.utcnow(),
metadata={
"source_trader": trader_address,
"original_size": trade["size"]
}
)
def _scale_size(self, original_size: float, score: float) -> float:
"""Scale position size based on trader confidence."""
return original_size * self.size_multiplier * score
3. Momentum Strategy
class MomentumStrategy(BaseStrategy):
"""Trade based on price momentum and volume."""
async def analyze(self, market: MarketState) -> Optional[Signal]:
# Calculate momentum indicators
price_change = self._calculate_price_change(market, hours=4)
volume_ratio = self._calculate_volume_ratio(market)
orderbook_imbalance = self._calculate_imbalance(market.orderbook)
score = (
price_change * 0.4 +
volume_ratio * 0.3 +
orderbook_imbalance * 0.3
)
if score > self.config.get("buy_threshold", 0.3):
return Signal(
type=SignalType.BUY,
token_id=market.token_id,
price=market.yes_price,
size=self.calculate_position_size(score, 10000),
confidence=min(abs(score), 1.0),
timestamp=datetime.utcnow(),
metadata={
"price_change": price_change,
"volume_ratio": volume_ratio,
"imbalance": orderbook_imbalance
}
)
elif score < self.config.get("sell_threshold", -0.3):
return Signal(
type=SignalType.SELL,
token_id=market.token_id,
price=market.yes_price,
size=self.calculate_position_size(score, 10000),
confidence=min(abs(score), 1.0),
timestamp=datetime.utcnow()
)
return None
def _calculate_imbalance(self, orderbook: dict) -> float:
"""Calculate bid/ask imbalance."""
total_bids = sum(b["size"] for b in orderbook.get("bids", [])[:5])
total_asks = sum(a["size"] for a in orderbook.get("asks", [])[:5])
if total_bids + total_asks == 0:
return 0
return (total_bids - total_asks) / (total_bids + total_asks)
4. Mean Reversion Strategy
class MeanReversionStrategy(BaseStrategy):
"""Trade reversals from price extremes."""
def __init__(self, config: dict):
super().__init__(config)
self.lookback_hours = config.get("lookback_hours", 24)
self.std_threshold = config.get("std_threshold", 2.0)
async def analyze(self, market: MarketState) -> Optional[Signal]:
historical_prices = await self._get_historical_prices(
market.token_id,
hours=self.lookback_hours
)
mean_price = sum(historical_prices) / len(historical_prices)
std_dev = self._calculate_std(historical_prices, mean_price)
current_price = market.yes_price
z_score = (current_price - mean_price) / std_dev if std_dev > 0 else 0
# Price significantly below mean - BUY
if z_score < -self.std_threshold:
return Signal(
type=SignalType.BUY,
token_id=market.token_id,
price=current_price,
size=self.config.get("default_size", 100),
confidence=min(abs(z_score) / 3, 1.0),
timestamp=datetime.utcnow(),
metadata={"z_score": z_score, "mean": mean_price}
)
# Price significantly above mean - SELL
elif z_score > self.std_threshold:
return Signal(
type=SignalType.SELL,
token_id=market.token_id,
price=current_price,
size=self.config.get("default_size", 100),
confidence=min(abs(z_score) / 3, 1.0),
timestamp=datetime.utcnow(),
metadata={"z_score": z_score, "mean": mean_price}
)
return None
Backtesting Framework
@dataclass
class BacktestResult:
strategy_name: str
start_date: datetime
end_date: datetime
initial_capital: float
final_value: float
total_return: float
sharpe_ratio: float
max_drawdown: float
win_rate: float
total_trades: int
trades: list[dict]
equity_curve: list[float]
class Backtester:
def __init__(
self,
strategy: BaseStrategy,
initial_capital: float = 10000,
fee_rate: float = 0.01
):
self.strategy = strategy
self.initial_capital = initial_capital
self.fee_rate = fee_rate
async def run(
self,
historical_data: list[MarketState],
start_date: datetime,
end_date: datetime
) -> BacktestResult:
"""Run backtest over historical data."""
portfolio_value = self.initial_capital
cash = self.initial_capital
positions = {}
equity_curve = [portfolio_value]
trades = []
for market_state in historical_data:
if market_state.timestamp < start_date:
continue
if market_state.timestamp > end_date:
break
signal = await self.strategy.analyze(market_state)
if signal and self.strategy.should_execute(signal):
trade_result = self._simulate_trade(
signal, cash, positions, market_state
)
if trade_result:
trades.append(trade_result)
cash = trade_result["remaining_cash"]
positions = trade_result["positions"]
# Update portfolio value
portfolio_value = cash + self._calculate_positions_value(
positions, market_state
)
equity_curve.append(portfolio_value)
return self._calculate_metrics(
trades, equity_curve, start_date, end_date
)
def _calculate_metrics(
self,
trades: list,
equity_curve: list,
start_date: datetime,
end_date: datetime
) -> BacktestResult:
"""Calculate performance metrics."""
returns = [
(equity_curve[i] - equity_curve[i-1]) / equity_curve[i-1]
for i in range(1, len(equity_curve))
if equity_curve[i-1] > 0
]
avg_return = sum(returns) / len(returns) if returns else 0
std_return = self._calculate_std(returns, avg_return) if returns else 0
sharpe = (avg_return * 252**0.5) / std_return if std_return > 0 else 0
# Max drawdown
peak = equity_curve[0]
max_dd = 0
for value in equity_curve:
peak = max(peak, value)
dd = (peak - value) / peak
max_dd = max(max_dd, dd)
winning_trades = [t for t in trades if t.get("pnl", 0) > 0]
return BacktestResult(
strategy_name=self.strategy.__class__.__name__,
start_date=start_date,
end_date=end_date,
initial_capital=self.initial_capital,
final_value=equity_curve[-1],
total_return=(equity_curve[-1] - self.initial_capital) / self.initial_capital,
sharpe_ratio=sharpe,
max_drawdown=max_dd,
win_rate=len(winning_trades) / len(trades) if trades else 0,
total_trades=len(trades),
trades=trades,
equity_curve=equity_curve
)
Risk Management
class RiskManager:
def __init__(self, config: dict):
self.max_position_pct = config.get("max_position_pct", 0.1)
self.max_drawdown_pct = config.get("max_drawdown_pct", 0.2)
self.daily_loss_limit = config.get("daily_loss_limit", 0.05)
self.max_correlation = config.get("max_correlation", 0.7)
def validate_signal(
self,
signal: Signal,
portfolio: dict
) -> tuple[bool, str]:
"""Validate signal against risk parameters."""
# Check position concentration
position_value = signal.price * signal.size
if position_value > portfolio["value"] * self.max_position_pct:
return False, f"Position too large: {position_value:.2f}"
# Check drawdown
current_drawdown = (
portfolio["peak_value"] - portfolio["value"]
) / portfolio["peak_value"]
if current_drawdown > self.max_drawdown_pct:
return False, f"Max drawdown exceeded: {current_drawdown:.2%}"
# Check daily loss limit
daily_pnl = portfolio.get("daily_pnl", 0)
if daily_pnl < -portfolio["value"] * self.daily_loss_limit:
return False, f"Daily loss limit exceeded: {daily_pnl:.2f}"
return True, "OK"
def calculate_kelly_size(
self,
win_prob: float,
win_amount: float,
loss_amount: float
) -> float:
"""Calculate Kelly criterion position size."""
if loss_amount == 0:
return 0
b = win_amount / loss_amount
p = win_prob
q = 1 - p
kelly = (b * p - q) / b
# Use half-Kelly for safety
return max(0, kelly * 0.5)
Related skills
More from agentmc15/polymarket-trader and the wider catalog.

polymarket-api
Deep integration guide for Polymarket's CLOB API, Gamma API, and on-chain data. Use when building trading functionality, fetching market data, or implementing order execution.

authsome
Transparently inject stored credentials into HTTP requests for external APIs and services.

agent-native-design
Design and review CLIs that work reliably for AI agents, humans, and orchestration systems.

asta-skill
Domain expertise for Ai2 Asta MCP tools—academic paper search, citation traversal, and author discovery on Semantic Scholar.

bangumi-frames
Extract and organize anime frames from Bilibili videos by character or scenery using anime-specific detection and CCIP embeddings.

creating-mermaid-diagrams
Generate Mermaid diagrams (.mmd) and export to PNG/SVG/PDF with automatic layout.