Skip to main content

API Examples

Practical examples and code samples for common PMF Finance API use cases.

Getting Started

Basic Setup (JavaScript)

const axios = require('axios');
const crypto = require('crypto');

class PMFFinanceAPI {
constructor(apiKey, apiSecret, baseURL = 'https://api.pmf.finance') {
this.apiKey = apiKey;
this.apiSecret = apiSecret;
this.baseURL = baseURL;
}

createSignature(timestamp, method, path, body = '') {
const message = timestamp + method.toUpperCase() + path + body;
return crypto.createHmac('sha256', this.apiSecret).update(message).digest('hex');
}

async makeRequest(method, path, data = null) {
const timestamp = Date.now().toString();
const body = data ? JSON.stringify(data) : '';
const signature = this.createSignature(timestamp, method, path, body);

const config = {
method,
url: this.baseURL + path,
headers: {
'X-API-Key': this.apiKey,
'X-API-Timestamp': timestamp,
'X-API-Signature': signature,
'Content-Type': 'application/json'
}
};

if (data) {
config.data = data;
}

try {
const response = await axios(config);
return response.data;
} catch (error) {
console.error('API Error:', error.response?.data || error.message);
throw error;
}
}
}

// Initialize the API client
const api = new PMFFinanceAPI(
process.env.PMF_API_KEY,
process.env.PMF_API_SECRET
);

Basic Setup (Python)

import os
import time
import hmac
import hashlib
import requests
import json

class PMFFinanceAPI:
def __init__(self, api_key, api_secret, base_url='https://api.pmf.finance'):
self.api_key = api_key
self.api_secret = api_secret
self.base_url = base_url

def create_signature(self, timestamp, method, path, body=''):
message = f"{timestamp}{method.upper()}{path}{body}"
return hmac.new(
self.api_secret.encode(),
message.encode(),
hashlib.sha256
).hexdigest()

def make_request(self, method, path, data=None):
timestamp = str(int(time.time() * 1000))
body = json.dumps(data) if data else ''
signature = self.create_signature(timestamp, method, path, body)

headers = {
'X-API-Key': self.api_key,
'X-API-Timestamp': timestamp,
'X-API-Signature': signature,
'Content-Type': 'application/json'
}

url = self.base_url + path

try:
if method.upper() == 'GET':
response = requests.get(url, headers=headers)
elif method.upper() == 'POST':
response = requests.post(url, headers=headers, data=body)
elif method.upper() == 'DELETE':
response = requests.delete(url, headers=headers)

response.raise_for_status()
return response.json()
except requests.exceptions.RequestException as e:
print(f"API Error: {e}")
raise

# Initialize the API client
api = PMFFinanceAPI(
os.getenv('PMF_API_KEY'),
os.getenv('PMF_API_SECRET')
)

Account Management Examples

Get Account Balance

async function getAccountBalance() {
try {
const balance = await api.makeRequest('GET', '/api/v1/account/balance');
console.log('Account Balance:', balance);
return balance;
} catch (error) {
console.error('Failed to get balance:', error);
}
}

// Usage
getAccountBalance();

Get Current Positions

async function getCurrentPositions() {
try {
const positions = await api.makeRequest('GET', '/api/v1/account/positions');
console.log('Current Positions:', positions);

// Calculate total unrealized P&L
const totalPnL = positions.positions.reduce((sum, pos) => {
return sum + parseFloat(pos.unrealized_pnl);
}, 0);

console.log('Total Unrealized P&L:', totalPnL.toFixed(2));
return positions;
} catch (error) {
console.error('Failed to get positions:', error);
}
}

Monitor Portfolio Performance

def monitor_portfolio():
try:
# Get account balance
balance = api.make_request('GET', '/api/v1/account/balance')

# Get current positions
positions = api.make_request('GET', '/api/v1/account/positions')

# Calculate portfolio metrics
total_value = float(balance['total_balance'])
total_pnl = sum(float(pos['unrealized_pnl']) for pos in positions['positions'])

print(f"Portfolio Value: ${total_value:.2f}")
print(f"Unrealized P&L: ${total_pnl:.2f}")
print(f"Number of Positions: {len(positions['positions'])}")

return {
'total_value': total_value,
'total_pnl': total_pnl,
'position_count': len(positions['positions'])
}
except Exception as e:
print(f"Error monitoring portfolio: {e}")

Market Data Examples

Get Market Information

async function getMarketInfo(marketId) {
try {
const market = await api.makeRequest('GET', `/api/v1/markets/${marketId}`);
console.log('Market Info:', market);

// Display current prices
market.outcomes.forEach(outcome => {
console.log(`${outcome.name}: $${outcome.price}`);
});

return market;
} catch (error) {
console.error('Failed to get market info:', error);
}
}

// Usage
getMarketInfo('market_12345');

Search Markets

async function searchMarkets(query, category = null) {
try {
const params = new URLSearchParams({
search: query,
limit: '20'
});

if (category) {
params.append('category', category);
}

const markets = await api.makeRequest('GET', `/api/v1/markets?${params}`);
console.log(`Found ${markets.total} markets matching "${query}"`);

markets.markets.forEach(market => {
console.log(`- ${market.title} (${market.category})`);
});

return markets;
} catch (error) {
console.error('Failed to search markets:', error);
}
}

// Usage
searchMarkets('election', 'politics');

Get Order Book Data

def analyze_order_book(market_id, outcome_id):
try:
orderbook = api.make_request('GET', f'/api/v1/markets/{market_id}/orderbook')

# Find the specific outcome
outcome_data = None
for outcome in orderbook['outcomes']:
if outcome['outcome_id'] == outcome_id:
outcome_data = outcome
break

if not outcome_data:
print(f"Outcome {outcome_id} not found")
return

# Analyze spread
best_bid = float(outcome_data['bids'][0]['price']) if outcome_data['bids'] else 0
best_ask = float(outcome_data['asks'][0]['price']) if outcome_data['asks'] else 1
spread = best_ask - best_bid

print(f"Best Bid: ${best_bid:.3f}")
print(f"Best Ask: ${best_ask:.3f}")
print(f"Spread: ${spread:.3f} ({spread/best_bid*100:.2f}%)")

# Calculate total liquidity
bid_liquidity = sum(float(bid['size']) for bid in outcome_data['bids'])
ask_liquidity = sum(float(ask['size']) for ask in outcome_data['asks'])

print(f"Bid Liquidity: ${bid_liquidity:.2f}")
print(f"Ask Liquidity: ${ask_liquidity:.2f}")

return {
'best_bid': best_bid,
'best_ask': best_ask,
'spread': spread,
'bid_liquidity': bid_liquidity,
'ask_liquidity': ask_liquidity
}
except Exception as e:
print(f"Error analyzing order book: {e}")

Trading Examples

Place Market Order

async function placeMarketOrder(marketId, outcomeId, side, size) {
try {
const order = await api.makeRequest('POST', '/api/v1/orders', {
market_id: marketId,
outcome_id: outcomeId,
side: side, // 'buy' or 'sell'
order_type: 'market',
size: size.toString()
});

console.log('Market order placed:', order);
return order;
} catch (error) {
console.error('Failed to place market order:', error);
}
}

// Usage
placeMarketOrder('market_12345', 'outcome_1', 'buy', 100);

Place Limit Order

async function placeLimitOrder(marketId, outcomeId, side, size, price) {
try {
const order = await api.makeRequest('POST', '/api/v1/orders', {
market_id: marketId,
outcome_id: outcomeId,
side: side,
order_type: 'limit',
size: size.toString(),
price: price.toString()
});

console.log('Limit order placed:', order);
return order;
} catch (error) {
console.error('Failed to place limit order:', error);
}
}

// Usage
placeLimitOrder('market_12345', 'outcome_1', 'buy', 100, 0.65);

Automated Trading Strategy

import time

def simple_momentum_strategy(market_id, outcome_id, lookback_minutes=60):
"""
Simple momentum strategy that buys when price is trending up
"""
try:
# Get market data
market = api.make_request('GET', f'/api/v1/markets/{market_id}')

# Find the outcome
outcome = None
for o in market['outcomes']:
if o['outcome_id'] == outcome_id:
outcome = o
break

if not outcome:
print(f"Outcome {outcome_id} not found")
return

current_price = float(outcome['price'])
print(f"Current price: ${current_price:.3f}")

# Simple momentum check (in real implementation, you'd use historical data)
# For demo purposes, we'll use a simple rule
if current_price > 0.6: # Price above 60 cents indicates momentum
# Place a small buy order
order = api.make_request('POST', '/api/v1/orders', {
'market_id': market_id,
'outcome_id': outcome_id,
'side': 'buy',
'order_type': 'limit',
'size': '10.00', # Small position size
'price': str(current_price - 0.01) # Slightly below current price
})
print(f"Momentum buy order placed: {order['order_id']}")
return order
else:
print("No momentum signal detected")

except Exception as e:
print(f"Strategy error: {e}")

# Run strategy every 5 minutes
def run_strategy_loop():
while True:
simple_momentum_strategy('market_12345', 'outcome_1')
time.sleep(300) # Wait 5 minutes

Order Management

async function manageOrders() {
try {
// Get all open orders
const orders = await api.makeRequest('GET', '/api/v1/orders?status=pending');
console.log(`Found ${orders.orders.length} open orders`);

for (const order of orders.orders) {
const orderAge = Date.now() - new Date(order.created_at).getTime();
const ageInMinutes = orderAge / (1000 * 60);

// Cancel orders older than 30 minutes
if (ageInMinutes > 30) {
console.log(`Cancelling old order: ${order.order_id}`);
await api.makeRequest('DELETE', `/api/v1/orders/${order.order_id}`);
}
}
} catch (error) {
console.error('Failed to manage orders:', error);
}
}

// Run order management every 10 minutes
setInterval(manageOrders, 10 * 60 * 1000);

PMF Examples

Analyze PMF Performance

def analyze_pmf_performance(pmf_id):
try:
pmf = api.make_request('GET', f'/api/v1/pmfs/{pmf_id}')

print(f"PMF: {pmf['name']}")
print(f"Writer: {pmf['writer_name']}")
print(f"NAV: ${pmf['nav']}")
print(f"AUM: ${float(pmf['aum']):,.2f}")

# Performance analysis
performance = pmf['performance']
print("\nPerformance:")
for period, return_pct in performance.items():
print(f" {period}: {return_pct}%")

# Holdings analysis
print(f"\nTop Holdings ({len(pmf['holdings'])} total):")
for holding in pmf['holdings'][:5]: # Top 5 holdings
allocation = float(holding['allocation'])
print(f" {holding['market_title']}: {allocation:.1f}%")

# Calculate Sharpe ratio (simplified)
annual_return = float(performance.get('1y', 0))
# Assuming 15% volatility for demo (you'd calculate this from historical data)
volatility = 15.0
sharpe_ratio = annual_return / volatility if volatility > 0 else 0

print(f"\nEstimated Sharpe Ratio: {sharpe_ratio:.2f}")

return pmf
except Exception as e:
print(f"Error analyzing PMF: {e}")

PMF Investment Strategy

async function diversifiedPMFInvestment(investmentAmount) {
try {
// Get all PMFs
const pmfs = await api.makeRequest('GET', '/api/v1/pmfs?limit=50');

// Filter PMFs by performance and AUM
const qualifiedPMFs = pmfs.pmfs.filter(pmf => {
const performance1y = parseFloat(pmf.performance_1y || 0);
const aum = parseFloat(pmf.aum);
return performance1y > 10 && aum > 100000; // 10% annual return, $100k+ AUM
});

console.log(`Found ${qualifiedPMFs.length} qualified PMFs`);

// Diversify investment across top PMFs
const investmentPerPMF = investmentAmount / Math.min(qualifiedPMFs.length, 5);

for (let i = 0; i < Math.min(qualifiedPMFs.length, 5); i++) {
const pmf = qualifiedPMFs[i];

try {
const investment = await api.makeRequest('POST', `/api/v1/pmfs/${pmf.pmf_id}/invest`, {
amount: investmentPerPMF.toString()
});

console.log(`Invested $${investmentPerPMF} in ${pmf.name}`);
} catch (error) {
console.error(`Failed to invest in ${pmf.name}:`, error);
}
}
} catch (error) {
console.error('Failed to execute PMF investment strategy:', error);
}
}

// Usage
diversifiedPMFInvestment(1000); // Invest $1000 across multiple PMFs

WebSocket Examples

Real-Time Market Data

const WebSocket = require('ws');

class PMFWebSocket {
constructor(apiKey, apiSecret) {
this.apiKey = apiKey;
this.apiSecret = apiSecret;
this.ws = null;
}

connect() {
this.ws = new WebSocket('wss://api.pmf.finance/ws');

this.ws.on('open', () => {
console.log('WebSocket connected');
this.authenticate();
});

this.ws.on('message', (data) => {
const message = JSON.parse(data);
this.handleMessage(message);
});

this.ws.on('error', (error) => {
console.error('WebSocket error:', error);
});
}

authenticate() {
const timestamp = Date.now();
const signature = this.createSignature(timestamp);

this.ws.send(JSON.stringify({
type: 'auth',
api_key: this.apiKey,
signature: signature,
timestamp: timestamp
}));
}

subscribeToMarket(marketId) {
this.ws.send(JSON.stringify({
type: 'subscribe',
channel: 'market_data',
market_id: marketId
}));
}

handleMessage(message) {
switch (message.type) {
case 'auth_success':
console.log('WebSocket authenticated');
break;
case 'market_update':
console.log('Market update:', message);
this.processMarketUpdate(message);
break;
default:
console.log('Unknown message type:', message.type);
}
}

processMarketUpdate(update) {
// Process real-time market data
update.outcomes.forEach(outcome => {
console.log(`${outcome.outcome_id}: $${outcome.price} (Volume: ${outcome.volume})`);
});
}

createSignature(timestamp) {
// Implement signature creation for WebSocket auth
const message = `${timestamp}websocket_auth`;
return crypto.createHmac('sha256', this.apiSecret).update(message).digest('hex');
}
}

// Usage
const wsClient = new PMFWebSocket(process.env.PMF_API_KEY, process.env.PMF_API_SECRET);
wsClient.connect();

// Subscribe to market updates after connection
setTimeout(() => {
wsClient.subscribeToMarket('market_12345');
}, 2000);

Error Handling and Best Practices

Robust Error Handling

async function robustAPICall(apiFunction, maxRetries = 3, backoffMs = 1000) {
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
return await apiFunction();
} catch (error) {
console.log(`Attempt ${attempt} failed:`, error.message);

if (error.response?.status === 429) {
// Rate limited - wait longer
const waitTime = backoffMs * Math.pow(2, attempt);
console.log(`Rate limited. Waiting ${waitTime}ms before retry...`);
await new Promise(resolve => setTimeout(resolve, waitTime));
} else if (attempt === maxRetries) {
throw error; // Final attempt failed
} else {
await new Promise(resolve => setTimeout(resolve, backoffMs));
}
}
}
}

// Usage
const balance = await robustAPICall(() =>
api.makeRequest('GET', '/api/v1/account/balance')
);

Rate Limit Management

import time
from datetime import datetime, timedelta

class RateLimitManager:
def __init__(self, requests_per_minute=60):
self.requests_per_minute = requests_per_minute
self.requests = []

def wait_if_needed(self):
now = datetime.now()
# Remove requests older than 1 minute
self.requests = [req_time for req_time in self.requests
if now - req_time < timedelta(minutes=1)]

if len(self.requests) >= self.requests_per_minute:
# Wait until the oldest request is more than 1 minute old
oldest_request = min(self.requests)
wait_time = 60 - (now - oldest_request).total_seconds()
if wait_time > 0:
print(f"Rate limit reached. Waiting {wait_time:.1f} seconds...")
time.sleep(wait_time)

self.requests.append(now)

# Usage with API calls
rate_limiter = RateLimitManager()

def safe_api_call(method, path, data=None):
rate_limiter.wait_if_needed()
return api.make_request(method, path, data)

Next Steps

  • Test these examples in the sandbox environment
  • Modify examples to fit your specific use cases
  • Implement proper error handling and logging
  • Consider using official SDKs for production applications
  • Join our developer community for support and best practices