Temporal is the durable workflow engine that ensures your code runs exactly once, with automatic retries, state persistence, and fault tolerance. Combined with Purple Flea's financial APIs, you get trading agents that never lose state — even across failures, restarts, and multi-day workflows.
Financial workflows have requirements that crash naive agent implementations. Temporal solves all of them at the infrastructure level.
Network timeouts and agent crashes can cause a naive implementation to fire a trade twice — once that succeeds server-side but whose response is never received. Temporal's workflow history guarantees that each execute_trade activity runs exactly once, even if the worker crashes mid-execution.
Purple Flea API calls can fail transiently — rate limits, network blips, server restarts. Instead of writing brittle retry loops, Temporal activities are automatically retried with configurable exponential backoff. Your workflow simply moves forward when the activity succeeds.
Resilient by defaultA "rebalance monthly" DCA workflow can issue a trade, call workflow.sleep(timedelta(days=30)), and wake up a month later to execute the next trade — with full state persistence in between. No cron job, no database, no missed executions.
A Temporal-powered Purple Flea agent has three layers: activities wrapping API calls, workflows orchestrating logic, and the Temporal server persisting all state.
Each Purple Flea API call is wrapped as a Temporal @activity.defn function. Activities are retried on failure, and their results are persisted in workflow history — so a restarted worker never re-executes a completed activity.
Workflow functions orchestrate activities using normal Python control flow — loops, conditionals, await. Workflow code must be deterministic (no random, no datetime.now()) but otherwise reads like ordinary sequential code.
Workers are long-running Python processes that poll Temporal for tasks. You can run them on any server — your VPS, a container, Lambda. Scale horizontally by running more workers; Temporal distributes tasks automatically.
A complete Temporal workflow using the Python SDK — Purple Flea activities with automatic retry, plus a DCA workflow that runs for 52 weeks.
from temporalio import activity, workflow
from temporalio.client import Client
from temporalio.worker import Worker
from datetime import timedelta
import requests
import os
PURPLE_FLEA_KEY = os.environ["PURPLE_FLEA_API_KEY"]
BASE_URL = "https://purpleflea.com/api/v1"
# ─── ACTIVITIES ───────────────────────────────────────────────────────────────
@activity.defn
async def execute_trade(symbol: str, side: str, size_usd: float) -> dict:
"""Purple Flea trade wrapped as Temporal activity — auto-retried on failure"""
response = requests.post(
f"{BASE_URL}/trade",
json={"symbol": symbol, "side": side, "size": size_usd, "leverage": 2},
headers={"Authorization": f"Bearer {PURPLE_FLEA_KEY}"}
)
response.raise_for_status()
return response.json()
@activity.defn
async def get_portfolio() -> dict:
"""Fetch all open positions and unrealized PnL"""
response = requests.get(
f"{BASE_URL}/portfolio",
headers={"Authorization": f"Bearer {PURPLE_FLEA_KEY}"}
)
response.raise_for_status()
return response.json()
@activity.defn
async def close_all_positions() -> dict:
"""Emergency close — exits all positions at market"""
response = requests.post(
f"{BASE_URL}/trade/close-all",
headers={"Authorization": f"Bearer {PURPLE_FLEA_KEY}"}
)
response.raise_for_status()
return response.json()
@activity.defn
async def create_escrow(amount_usd: float, counterparty_id: str, condition: str) -> dict:
"""Create trustless escrow with Purple Flea (1% fee, 15% referral)"""
response = requests.post(
f"{BASE_URL}/escrow/create",
json={"amount_usd": amount_usd, "counterparty": counterparty_id, "condition": condition},
headers={"Authorization": f"Bearer {PURPLE_FLEA_KEY}"}
)
response.raise_for_status()
return response.json()
# ─── WORKFLOWS ────────────────────────────────────────────────────────────────
@workflow.defn
class DCAWorkflow:
"""Dollar-cost average into BTC every week for 52 weeks"""
@workflow.run
async def run(self, weekly_amount: float):
for week in range(52):
result = await workflow.execute_activity(
execute_trade,
args=["BTC-PERP", "long", weekly_amount],
schedule_to_close_timeout=timedelta(minutes=5),
retry_policy=RetryPolicy(
backoff_coefficient=2.0,
maximum_attempts=10,
maximum_interval=timedelta(minutes=2)
)
)
# Persist weekly result in workflow history
workflow.logger.info(f"Week {week+1}: bought BTC at {result['entry_price']}")
# Sleep for exactly 7 days — Temporal timer, not OS sleep
await workflow.sleep(timedelta(days=7))
@workflow.defn
class RiskMonitorWorkflow:
"""Monitor portfolio and close all if drawdown exceeds threshold"""
@workflow.run
async def run(self, max_drawdown_pct: float = 0.15):
while True:
portfolio = await workflow.execute_activity(
get_portfolio,
schedule_to_close_timeout=timedelta(seconds=30)
)
drawdown = portfolio.get("drawdown_pct", 0)
if drawdown >= max_drawdown_pct:
await workflow.execute_activity(
close_all_positions,
schedule_to_close_timeout=timedelta(minutes=2)
)
workflow.logger.warning(f"Drawdown {drawdown:.1%} — closed all positions")
return
# Check every 5 minutes
await workflow.sleep(timedelta(minutes=5))
Production-tested workflow designs for common financial agent use cases with Purple Flea.
Buy a fixed dollar amount of any Purple Flea perpetual on a weekly or monthly schedule for N periods. Uses workflow.sleep() between executions — persisted across worker restarts, never misses a period, never double-buys.
A long-running loop that polls GET /portfolio every N minutes and calls close_all_positions if drawdown exceeds a configurable threshold. Runs indefinitely with Temporal — no server, no cron, no missed checks.
Multi-step workflow: create_escrow → sleep until deadline → check_condition → branch to release_payment or dispute. Each step is idempotent — a crashed worker picks up exactly where it left off.
Schedule domain renewals, monitor expiry dates, and automatically register new domains when conditions are met. Uses workflow.sleep() with precise timers instead of unreliable cron jobs.
Each Purple Flea API endpoint maps to a Temporal activity function. All activities support automatic retry with backoff.
| Activity Function | Description | Purple Flea Endpoint |
|---|---|---|
| execute_trade(symbol, side, size_usd) | Open a leveraged perpetual position. Returns position ID, entry price, liquidation price. | POST /api/v1/trade |
| get_portfolio() | Fetch all open positions with unrealized PnL, drawdown percentage, and total exposure. | GET /api/v1/portfolio |
| close_all_positions() | Market-close all open positions. Returns realized PnL and fees paid. | POST /api/v1/trade/close-all |
| wallet_balance(chain) | Get confirmed balance for a specific chain or all chains. Returns balance in native asset and USD equivalent. | GET /api/v1/wallet/balance |
| casino_bet(game, amount_usd, params) | Place a provably fair casino bet (crash, coin flip, dice, slots). Returns outcome and updated balance. | POST /api/v1/casino/bet |
| create_escrow(amount_usd, counterparty, condition) | Create a trustless escrow between two agent IDs. 1% fee on release; 15% referral on fees. | POST /api/v1/escrow/create |
| release_escrow(escrow_id) | Release escrowed funds to counterparty once condition is confirmed. Idempotent — safe to retry. | POST /api/v1/escrow/release |
| register_domain(name) | Register a crypto-native domain. Returns registration ID and expiry timestamp. | POST /api/v1/domains/register |
How Temporal handles every failure mode in a production Purple Flea financial agent.
Set schedule_to_close_timeout on each activity. If the Purple Flea API doesn't respond within the window, Temporal marks the activity as failed and schedules a retry according to your RetryPolicy. Your workflow code never sees the timeout — it just awaits the next attempt.
Activity functions should raise_for_status() on every Purple Flea response. A 429 raises an exception, which Temporal catches and retries with configurable exponential backoff (e.g. backoff_coefficient=2.0, initial_interval=timedelta(seconds=5)). No manual sleep loops needed.
Temporal stores full workflow execution history server-side. If your worker process crashes mid-workflow, a new worker picks up the task from exactly the last successfully completed activity. No state is lost, no activities are re-run, and no positions are accidentally opened twice.
If execute_trade POSTs successfully to Purple Flea but the response is lost in transit (network failure after server ACK), Temporal's activity idempotency key ensures the activity is not retried with a new request. Include a client_request_id in your API body and Purple Flea will deduplicate on its end.
If the Temporal server itself is unavailable, workers queue up pending activity results locally and flush them when the server reconnects. Long-sleep workflows (e.g. DCA sleeping 7 days) are unaffected — the timer is persisted in the Temporal service, not in your worker process.
Get a free API key and start wrapping Purple Flea calls in Temporal activities. Your trading workflows will be fault-tolerant, exactly-once, and capable of sleeping for months.