Skip to content

Commit 1fca1fa

Browse files
committed
feat: store event_slug in trades for accurate Polymarket links
- Add event_slug column to trades table with DB migration for old DBs - Add event_slug to Trade model (default empty for backwards compat) - Pass market.event_slug when recording trades in engine buy/sell - Expose event_slug in web trades API and frontend TradeHistory links - Unify all ↗ links to use /event/{event_slug}/{market_slug} format
1 parent 3b990ce commit 1fca1fa

7 files changed

Lines changed: 69 additions & 5 deletions

File tree

frontend/src/api/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ export interface TradeRecord {
4949
market_condition_id: string
5050
market_slug: string
5151
market_question: string
52+
event_slug?: string
5253
outcome: string
5354
side: string
5455
order_type: string

frontend/src/components/TradeHistory.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ export default function TradeHistory({ trades }: Props) {
7979
{t.market_question || t.market_slug}
8080
{' '}
8181
<a
82-
href={`https://polymarket.com/event/${t.market_slug}`}
82+
href={t.event_slug ? `https://polymarket.com/event/${t.event_slug}/${t.market_slug}` : `https://polymarket.com/event/${t.market_slug}`}
8383
target="_blank"
8484
rel="noopener noreferrer"
8585
style={{ fontSize: '0.85em', color: '#4f46e5', textDecoration: 'none', fontWeight: 600, marginLeft: 4 }}

pm_trader/db.py

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
market_condition_id TEXT NOT NULL,
2424
market_slug TEXT NOT NULL,
2525
market_question TEXT NOT NULL,
26+
event_slug TEXT NOT NULL DEFAULT '',
2627
outcome TEXT NOT NULL CHECK (length(outcome) > 0),
2728
side TEXT NOT NULL CHECK (side IN ('buy', 'sell')),
2829
order_type TEXT NOT NULL DEFAULT 'fok' CHECK (order_type IN ('fok', 'fak')),
@@ -92,6 +93,13 @@ def close(self) -> None:
9293
def init_schema(self) -> None:
9394
"""Create all tables if they don't exist."""
9495
self.conn.executescript(SCHEMA_SQL)
96+
self._migrate()
97+
98+
def _migrate(self) -> None:
99+
"""Add columns that may be missing from older databases."""
100+
cols = {row[1] for row in self.conn.execute("PRAGMA table_info(trades)").fetchall()}
101+
if "event_slug" not in cols:
102+
self.conn.execute("ALTER TABLE trades ADD COLUMN event_slug TEXT NOT NULL DEFAULT ''")
95103

96104
# ------------------------------------------------------------------
97105
# Account
@@ -150,6 +158,7 @@ def insert_trade(
150158
market_condition_id: str,
151159
market_slug: str,
152160
market_question: str,
161+
event_slug: str = "",
153162
outcome: str,
154163
side: str,
155164
order_type: str,
@@ -167,15 +176,15 @@ def insert_trade(
167176
"""\
168177
INSERT INTO trades (
169178
market_condition_id, market_slug, market_question,
170-
outcome, side, order_type,
179+
event_slug, outcome, side, order_type,
171180
avg_price, amount_usd, shares,
172181
fee_rate_bps, fee, slippage,
173182
levels_filled, is_partial
174-
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
183+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
175184
""",
176185
(
177186
market_condition_id, market_slug, market_question,
178-
outcome, side, order_type,
187+
event_slug, outcome, side, order_type,
179188
avg_price, amount_usd, shares,
180189
fee_rate_bps, fee, slippage,
181190
levels_filled, int(is_partial),
@@ -338,6 +347,7 @@ def _row_to_trade(row: sqlite3.Row) -> Trade:
338347
market_condition_id=row["market_condition_id"],
339348
market_slug=row["market_slug"],
340349
market_question=row["market_question"],
350+
event_slug=row["event_slug"],
341351
outcome=row["outcome"],
342352
side=row["side"],
343353
order_type=row["order_type"],

pm_trader/engine.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,7 @@ def buy(
167167
market_condition_id=market.condition_id,
168168
market_slug=market.slug,
169169
market_question=market.question,
170+
event_slug=market.event_slug,
170171
outcome=outcome,
171172
side="buy",
172173
order_type=order_type,
@@ -280,6 +281,7 @@ def sell(
280281
market_condition_id=market.condition_id,
281282
market_slug=market.slug,
282283
market_question=market.question,
284+
event_slug=market.event_slug,
283285
outcome=outcome,
284286
side="sell",
285287
order_type=order_type,
@@ -561,6 +563,7 @@ def _execute_limit_buy(self, market, order, fill, fee_rate_bps: int) -> None:
561563
market_condition_id=market.condition_id,
562564
market_slug=market.slug,
563565
market_question=market.question,
566+
event_slug=market.event_slug,
564567
outcome=order.outcome,
565568
side="buy",
566569
order_type="fak",
@@ -598,6 +601,7 @@ def _execute_limit_sell(self, market, order, fill, fee_rate_bps: int) -> None:
598601
market_condition_id=market.condition_id,
599602
market_slug=market.slug,
600603
market_question=market.question,
604+
event_slug=market.event_slug,
601605
outcome=order.outcome,
602606
side="sell",
603607
order_type="fak",

pm_trader/models.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,7 @@ class Trade:
245245
levels_filled: int
246246
is_partial: bool
247247
created_at: str
248+
event_slug: str = ""
248249

249250

250251
# ---------------------------------------------------------------------------

pm_trader/web/routes/dashboard.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ def export_trades(
8888
def _trade_to_dict(t) -> dict:
8989
return {
9090
"id": t.id, "market_condition_id": t.market_condition_id,
91-
"market_slug": t.market_slug, "market_question": t.market_question,
91+
"market_slug": t.market_slug, "market_question": t.market_question, "event_slug": t.event_slug,
9292
"outcome": t.outcome, "side": t.side, "order_type": t.order_type,
9393
"avg_price": t.avg_price, "amount_usd": t.amount_usd,
9494
"shares": t.shares, "fee_rate_bps": t.fee_rate_bps,

tests/test_db.py

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,54 @@ def test_insert_trade_returns_trade(self, db: Database) -> None:
187187
assert trade.levels_filled == 2
188188
assert trade.is_partial is False
189189
assert trade.created_at is not None
190+
assert trade.event_slug == ""
191+
192+
def test_insert_trade_with_event_slug(self, db: Database) -> None:
193+
trade = db.insert_trade(
194+
market_condition_id="0xabc",
195+
market_slug="test-market",
196+
market_question="Test?",
197+
event_slug="parent-event",
198+
outcome="yes", side="buy", order_type="fok",
199+
avg_price=0.5, amount_usd=100, shares=200,
200+
fee_rate_bps=0, fee=0, slippage=0,
201+
levels_filled=1, is_partial=False,
202+
)
203+
assert trade.event_slug == "parent-event"
204+
205+
def test_row_to_trade_old_db_without_event_slug(self, db: Database) -> None:
206+
"""Old databases without event_slug column get migrated on init_schema."""
207+
db.conn.execute("DROP TABLE IF EXISTS trades")
208+
db.conn.execute("""\
209+
CREATE TABLE trades (
210+
id INTEGER PRIMARY KEY AUTOINCREMENT,
211+
market_condition_id TEXT NOT NULL,
212+
market_slug TEXT NOT NULL,
213+
market_question TEXT NOT NULL,
214+
outcome TEXT NOT NULL,
215+
side TEXT NOT NULL,
216+
order_type TEXT NOT NULL DEFAULT 'fok',
217+
avg_price REAL NOT NULL,
218+
amount_usd REAL NOT NULL,
219+
shares REAL NOT NULL,
220+
fee_rate_bps INTEGER NOT NULL,
221+
fee REAL NOT NULL DEFAULT 0,
222+
slippage REAL NOT NULL DEFAULT 0,
223+
levels_filled INTEGER NOT NULL DEFAULT 1,
224+
is_partial INTEGER NOT NULL DEFAULT 0,
225+
created_at TEXT NOT NULL DEFAULT (datetime('now'))
226+
)
227+
""")
228+
db.conn.execute(
229+
"INSERT INTO trades (market_condition_id, market_slug, market_question, outcome, side, avg_price, amount_usd, shares, fee_rate_bps) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)",
230+
("0x1", "old-market", "Old?", "yes", "buy", 0.5, 100, 200, 0),
231+
)
232+
db.conn.commit()
233+
# Migration adds the column
234+
db.init_schema()
235+
trades = db.get_trades()
236+
assert len(trades) == 1
237+
assert trades[0].event_slug == ""
190238

191239
def test_insert_trade_sell_with_fee(self, db: Database) -> None:
192240
trade = db.insert_trade(

0 commit comments

Comments
 (0)