Principles & schemas
The locked rules that survive every rewrite. Read this once, then again before you ship.
Positioning rules
- Polytraders is the trading-infrastructure layer for Polymarket — user-controlled execution tools, risk controls, strategy templates, market analytics, and builder-attributed order routing. Not a bot store.
- No copy-trading, no signal-following, no wallet-following.
3.14is Liquidity-Pulse, an internal liquidity model. - No performance claims. Sharpe, PnL, hit-rate, target return — none of it. Configuration knobs only.
- No operator names anywhere on the page. The product describes itself.
- Plain-English reporting is mandatory for every bot. If a non-technical user can't understand what happened, the bot is not done.
Authority hierarchy
Risk > Security > Execution > Strategy > Discovery > Intelligence > Governance. A higher layer can always block a lower one. Governance never blocks anything; it explains.
The six standard schemas
OrderIntent — Strategy → Risk (Polymarket V2)
type OrderIntent = {
intent_id: string; // UUIDv4 — idempotency key for the entire pipeline
strategy_id: string; // which strategy emitted it
market_id: string; // Polymarket condition_id (bytes32 hex)
outcome_id: string; // YES or NO token id
side: "BUY" | "SELL";
size_usd: number; // pUSD notional
price: number; // 0.001..0.999 (tick = 0.001)
order_type: "LIMIT" | "MARKET" | "POST_ONLY" | "GTC" | "GTD" | "FOK" | "IOC";
time_in_force?: number; // seconds
reduce_only?: boolean;
// V2 builder attribution — native field, NOT HMAC headers
builder?: { code: string; // bytes32 builderCode
fee_bps: number }; // ≤ 100 taker, ≤ 50 maker
// V2 negative-risk awareness
negrisk_aware?: boolean;
emitted_at: string; // ISO 8601
};
// NOTE: fees are NOT on the signed order in V2. The operator sets fees at
// match time. Only the BUILDER fee rate (capped) is on the order.
RiskVote — every Risk bot
type RiskDecision = "APPROVE" | "RESHAPE_REQUIRED" | "REJECT" | "WARNING_ONLY";
type RiskVote = {
guard_id: string;
decision: RiskDecision;
severity: "INFO" | "WARN" | "P1" | "P0";
reason_code: string; // UPPER_SNAKE, stable, machine-readable
message: string;
constraints?: {
max_size_usd?: number;
max_price?: number;
min_price?: number;
passive_only?: boolean;
close_only?: boolean;
cooldown_seconds?: number;
require_manual_review?: boolean;
};
inputs_used: string[];
checked_at: string;
};
ExecutionPlan — Risk → Execution
type ExecutionPlan = {
plan_id: string;
intent_id: string;
effective_size_usd: number;
effective_price: number;
order_type: OrderIntent["order_type"];
passive_only: boolean;
close_only: boolean;
builder?: { code: string; fee_bps: number };
constraints_applied: RiskVote[];
approved_at: string;
};
SecurityCheck — Security layer
type SecurityCheck = {
check_id: string;
scope: "wallet" | "contract" | "session" | "signing";
decision: "ALLOW" | "DENY" | "REQUIRE_2FA" | "PAUSE";
reason_code: string;
evidence: Record<string, unknown>;
checked_at: string;
};
GovernanceLog — Governance layer
type GovernanceLog = {
log_id: string;
kind: "config_change" | "incident" | "manual_override" | "reconciliation" | "audit";
actor: string;
target: string;
before?: unknown;
after?: unknown;
reason: string;
evidence_uri?: string;
created_at: string;
};
PostTradeExplanation — Governance
type PostTradeExplanation = {
fill_id: string;
intent_id: string;
user_summary: string; // plain English, no jargon
guards_consulted: { guard_id: string; decision: string; reason_code: string }[];
exec_path: string[]; // SmartRouter trail
builder_attribution?: { code: string; fee_bps: number };
generated_at: string;
};
Reason-code rules
- UPPER_SNAKE_CASE only.
- Stable across versions — never reword an existing code; deprecate and add a new one.
- Specific enough to drive a dashboard filter; never an English sentence.
- Examples:
ORDER_BOOK_UNAVAILABLE,STALE_MARKET_DATA,SPREAD_TOO_WIDE,INSUFFICIENT_VISIBLE_DEPTH,STRATEGY_BUDGET_EXCEEDED,ORACLE_DISPUTE_ACTIVE,WALLET_PERMISSION_DENIED,CONTRACT_ADDRESS_NOT_ALLOWED,PARAMETER_CHANGE_REQUIRES_APPROVAL.
Default-value guidance
| Bot status | Default posture |
|---|---|
| Planned | Conservative specification only. No live impact. |
| Beta | Conservative defaults, low caps, manual review on edge cases. |
| Limited live | Conservative defaults, explicit override process required. |
| General live | Defaults may relax only with performance + incident data. |
| Advanced | Manual review, capped exposure, full explanation always. |
Threshold standards
| Type | Meaning |
|---|---|
| Informational | Bot logs but takes no action. |
| Warning | Bot reports concern but does not block. |
| Soft constraint | Bot downsizes, delays, or changes execution mode. |
| Hard constraint | Bot rejects, pauses, or requires manual review. |
| Locked rule | Cannot be changed by user or strategy. |
Implementation references
Each link below opens a focused sub-page covering one slice of the implementation surface. Read in order if you are new; jump in if you know what you need.
Polytraders SDK
Shared types, helpers, and SDK constants every bot imports.
Reason-code registry
The five severities, the global registry, and per-bot scoping rules.
Observability standards
Mandatory metrics, logs, traces, and alerts every bot ships with.
Developer runbook
From git-clone to first decision in under fifteen minutes.
Promotion gates
Observable thresholds for moving a bot between readiness states.
Failure-injection recipes
Five standard chaos scenarios plus per-bot specifics.
Glossary
Plain-English definitions of every acronym and Polymarket concept.
Dependency graph
Cross-bot graph and external-service SLAs.
V2 migration delta
Every change V1→V2 and what it means for each layer.
API surfaces
The eleven endpoint enums every input declares against.
Do not build
These ten patterns are forbidden. They are the easiest mistakes to make and the most expensive ones to catch in production.
| Forbidden pattern | Why |
|---|---|
| Strategy bot submitting orders directly | Bypasses the Risk pipeline. Any code path from Strategy to the signer that does not pass through Risk is a P0 review block. |
| Bot consuming raw Polymarket payloads | Inconsistent shape, no freshness stamp, no provenance hash. All consumers read normalised objects from the data-flow layer. |
| Bot emitting free-text errors only | Breaks monitoring, dashboards, replay and audit. Every emission carries a reason_code from the registry. |
| Bot using unversioned config | Makes incidents impossible to reproduce. BotConfig.configVersion is mandatory and lives in every emitted envelope. |
| Bot silently failing open | The most dangerous pattern in trading systems. The documented safe_fallback must fire on every failure mode. |
| Bot with hard-coded market IDs or contract addresses | Not reusable, breaks on every Polymarket migration. They live in BotConfig and are validated against the on-chain registry by Security. |
| Bot with no shadow-mode path | Cannot safely test live. Every bot supports off + shadow + enforced at minimum; many also support advisory and quarantine. |
| Scoring documentation completeness as readiness | A 27/27 docs score means the spec is complete — not that the bot is implemented, tested under load, or running in shadow. v3 splits readiness into three scores (docs, impl, runtime) so this stops being possible. |
| Risk evaluating orders before Strategy emits an OrderIntent | Risk has no input until Strategy decides. The pipeline order is Discovery → Intel → Strategy emits OrderIntent → Risk → Execution. Reordering this is the single most common architecture mistake in v2. |
| Shipping a bot config without a declared parameter search space | Every tunable bot must declare a SEARCH_SPACE in its config schema (min, max, type per parameter). Without it the optimizer cannot tune the bot, the docs page cannot render sliders, and human reviewers cannot verify the config falls inside a sane range. |
Final instruction
Do not expand the bot library by adding more bot names. Expand it by making each bot implementable. A good bot page should allow a developer to build the first version without asking: what data do I need? what parameters exist? what are the defaults? what should happen if the data is missing? when should it reject? what does it log? what does the user see? how do I know it is ready to ship?