Metadata-Version: 2.4
Name: predigy-edge-sdk
Version: 2.1.0
Summary: Official Python SDK for the EDGE by Predigy prediction market API (retail, parlay, compliance/MICS, LP)
Author: Predigy LLC
License: MIT
Project-URL: Homepage, https://edge-by-predigy.netlify.app
Project-URL: Repository, https://github.com/predigy/edge
Project-URL: Documentation, https://edge-production-7b77.up.railway.app/docs
Project-URL: Bug Tracker, https://github.com/predigy/edge/issues
Keywords: edge,predigy,prediction-market,lmsr,sdk,retail,parlay,compliance,mics,liquidity-provider
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Requires-Python: >=3.10
Description-Content-Type: text/markdown
Requires-Dist: httpx>=0.25.0
Requires-Dist: pydantic>=2.0.0
Provides-Extra: dev
Requires-Dist: pytest>=8.0; extra == "dev"
Requires-Dist: pytest-asyncio>=0.23; extra == "dev"

# EDGE Python SDK

Official Python SDK for the [EDGE by Predigy](https://edge-by-predigy.netlify.app) prediction market API.

EDGE is a prediction market pricing engine that integrates with sportsbook platforms. This SDK provides a fully-typed async client for all API operations.

---

## Installation

```bash
pip install predigy-edge-sdk
```

**Requirements:** Python 3.11+

---

## Quick Start

```python
import asyncio
from edge_sdk import EdgeClient

async def main():
    async with EdgeClient(
        base_url="https://edge-production-7b77.up.railway.app",
        api_key="your-api-key",
    ) as client:
        # List open markets
        result = await client.list_markets(status="OPEN")
        for market in result.markets:
            print(f"{market.title}: YES={market.prices.yes:.1%}, NO={market.prices.no:.1%}")

        # Get a quote before trading
        quote = await client.get_quote("mkt_abc123", side="YES", amount=50.0)
        print(f"Cost: ${quote.total_cost:.2f} for {quote.contracts:.1f} contracts")

        # Execute the trade
        trade = await client.execute_trade("mkt_abc123", side="YES", amount=50.0)
        print(f"Trade {trade.trade_id} executed! New balance: ${trade.new_balance:.2f}")

asyncio.run(main())
```

---

## Authentication

Every request requires an API key passed in the `X-API-Key` header. The SDK handles this automatically:

```python
client = EdgeClient(
    base_url="https://edge-production-7b77.up.railway.app",
    api_key="your-api-key",
)
```

You receive your API key when your operator account is created by the Predigy team.

---

## API Reference

### Markets

```python
# List markets with optional filters
markets = await client.list_markets(status="OPEN", category="NBA", limit=10)

# Get a single market by external ID
market = await client.get_market("mkt_abc123")

# Create a new market (admin)
market = await client.create_market(
    title="Lakers vs Celtics — Lakers Win",
    category="NBA",
    description="Will the Lakers win tonight's game?",
    b_base=5000.0,
    initial_price_yes=0.55,
)
```

### Quotes and Trades

```python
# Get a price quote (does not execute a trade)
quote = await client.get_quote("mkt_abc123", side="YES", amount=100.0)
print(f"Contracts: {quote.contracts}")
print(f"Avg price: ${quote.avg_fill_price:.4f}")
print(f"Fee: ${quote.fee:.2f} ({quote.fee_rate:.2%})")
print(f"Total cost: ${quote.total_cost:.2f}")

# Execute a trade
trade = await client.execute_trade("mkt_abc123", side="YES", amount=100.0)

# Execute with slippage protection
trade = await client.execute_trade(
    "mkt_abc123", side="YES", amount=100.0,
    max_avg_price=0.60,  # Reject if avg price exceeds $0.60
)

# Sell (cash out) contracts from an existing position
sell = await client.sell_position("mkt_abc123", side="YES", contracts=50.0)
print(f"Net payout: ${sell.net_payout:.2f}")
```

### Portfolio

```python
portfolio = await client.get_portfolio()
print(f"Balance: ${portfolio.balance:.2f}")
print(f"Unrealized P&L: ${portfolio.total_unrealized_pnl:.2f}")

for pos in portfolio.positions:
    print(f"  {pos.market_title} ({pos.side}): {pos.contracts} contracts, P&L: ${pos.unrealized_pnl:.2f}")
```

### Admin Operations

```python
# Get platform statistics
stats = await client.get_stats()
print(f"Total markets: {stats.total_markets}")
print(f"Total volume: ${stats.total_volume:,.2f}")

# Settle a market
result = await client.settle_market("mkt_abc123", outcome="YES")

# Reset sandbox data
await client.reset_sandbox()
```

### Balance Bonus (Admin / Compliance)

The counter-flow surge rebate ("Balance Bonus") read + config surface
(SDK 2.1.0). Reads require a `READ_ONLY` key; config writes require an
`ADMIN` key. The backend owns all validation, clamping, and audit — these
methods are thin HTTP wrappers.

```python
# Read the rebate ledger (locked credits the operator owes)
ledger = await client.compliance.list_rebate_ledger(
    market_id="mkt_abc123",
    vested=True,
    limit=100,
)

# Per-market rebate period summary
period = await client.compliance.get_rebate_period("mkt_abc123")

# Read the Balance Bonus config (tiers + resolved values + source + clamps)
config = await client.get_balance_bonus_config(market_id="mkt_abc123")

# Tune one market's config (None resets a knob to the inherited value)
await client.update_balance_bonus_config(
    scope="market",
    market_id="mkt_abc123",
    config={"enabled": True, "headline_cap": 0.12},
)
```

### Webhooks

```python
# Register a webhook endpoint
webhook = await client.create_webhook(
    url="https://your-app.com/webhook",
    events=["trade.executed", "market.settled"],
    description="Production trade notifications",
)
print(f"Webhook ID: {webhook.webhook.external_id}")
print(f"Secret: {webhook.secret}")  # Store this — shown only once!

# List webhooks
webhooks = await client.list_webhooks()

# Delete a webhook
await client.delete_webhook("whk_abc123")
```

### Health Check

```python
health = await client.health_check()
print(health)  # {"status": "healthy"}
```

---

## Error Handling

The SDK raises typed exceptions for different error scenarios:

```python
from edge_sdk.exceptions import (
    EdgeAPIError,       # Base class for all API errors
    EdgeAuthError,      # 401 — Invalid or missing API key
    EdgeRateLimitError, # 429 — Too many requests
    EdgeValidationError,# 422 — Invalid request data
)

try:
    trade = await client.execute_trade("mkt_abc123", side="YES", amount=100.0)
except EdgeAuthError as e:
    print(f"Authentication failed: {e.detail}")
except EdgeRateLimitError as e:
    print(f"Rate limited. Retry after {e.retry_after} seconds")
except EdgeValidationError as e:
    print(f"Invalid request: {e.detail}")
except EdgeAPIError as e:
    print(f"API error {e.status_code}: {e.detail}")
    print(f"Request ID: {e.request_id}")  # Useful for support
```

All exceptions include a `request_id` field that you can reference when contacting support.

---

## Webhook Verification

When receiving webhook deliveries, verify the HMAC-SHA256 signature to ensure the payload is authentic:

```python
from edge_sdk import verify_signature

# In your webhook handler (e.g., FastAPI)
@app.post("/webhook")
async def handle_webhook(request: Request):
    body = await request.body()
    signature = request.headers.get("X-Edge-Signature", "")

    if not verify_signature(body, signature, WEBHOOK_SECRET):
        raise HTTPException(401, "Invalid signature")

    event = json.loads(body)
    print(f"Received event: {event['event_type']}")
    # Process event...
```

The `X-Edge-Signature` header format is `sha256=<hex_digest>`.

**Webhook event types:**
- `trade.executed` — A trade was placed
- `market.created` — A new market was created
- `market.settled` — A market was settled with an outcome
- `market.suspended` — A market was suspended
- `surge.activated` — Surge pricing was triggered
- `liquidity.adjusted` — Dynamic liquidity parameter changed

---

## Advanced Usage

### Custom HTTP Client

You can provide your own `httpx.AsyncClient` for custom timeouts, proxies, or connection pooling:

```python
import httpx

custom_client = httpx.AsyncClient(
    base_url="https://edge-production-7b77.up.railway.app",
    timeout=60.0,
    headers={"X-API-Key": "your-api-key", "Content-Type": "application/json"},
    limits=httpx.Limits(max_connections=20),
)

client = EdgeClient(
    base_url="https://edge-production-7b77.up.railway.app",
    api_key="your-api-key",
    http_client=custom_client,
)
```

### Type Safety

The SDK is fully typed with Pydantic models. All responses are validated and provide IDE autocompletion. The `py.typed` marker (PEP 561) enables type checking in tools like mypy and pyright.

---

## Links

- **API Documentation:** [docs/API.md](../../docs/API.md)
- **Integration Guide:** [docs/EDGE_INTEGRATION_GUIDE.md](../../docs/EDGE_INTEGRATION_GUIDE.md)
- **Live API (Swagger):** [edge-production-7b77.up.railway.app/docs](https://edge-production-7b77.up.railway.app/docs)
- **Frontend Demo:** [edge-by-predigy.netlify.app](https://edge-by-predigy.netlify.app)

---

## License

Proprietary. Copyright Predigy LLC. All rights reserved.
