Data models

Core entities and how trades, playbooks, and accounts relate.

Core entities

My Prop Journal's API exposes several core entities that represent your trading data:

1. Trade Groups

A trade group represents a complete trade from entry to exit. Each trade contains:

  • Entry and exit prices, dates, and times
  • Overall P&L calculations (gross and net)
  • Position size and direction (long/short)
  • Status (win/loss/breakeven/open)
  • Associated executions (fills)

2. Executions

Executions are individual buy/sell orders that make up a trade. Each execution includes:

  • Side (buy/sell)
  • Price and quantity
  • Timestamp
  • Commission/fees
  • Execution type (scale_in, scale_out, full)

A single trade can have multiple executions (e.g., scaling in/out of positions).

3. Accounts

Trading accounts represent your prop firm or retail broker accounts. Fields include:

  • Account type (prop or retail)
  • Firm/broker name
  • Account number
  • Balance or current value
  • Status (for prop accounts)

4. Playbooks

Playbooks are collections of trading strategies and rules. Each playbook contains:

  • Name and description
  • Entry criteria (conditions to enter trades)
  • Exit criteria (conditions to exit trades)
  • Associated strategies

5. Strategies

Strategies are specific trading approaches within playbooks. Each strategy has:

  • Name and description
  • Parent playbook reference
  • Creation timestamp

6. Future entities (not yet in API)

These entities exist in the product but are not yet exposed via API:

  • Trade writeups — Post-trade analysis and notes
  • Report cards — Daily trading performance reviews
  • Chart books — Saved chart screenshots and annotations

Entity relationships

Understanding how entities relate helps you build effective integrations:

Trade hierarchy

Account
  └─ Trade Group
       ├─ Execution 1 (entry)
       ├─ Execution 2 (scale in)
       ├─ Execution 3 (scale out)
       └─ Execution 4 (exit)

Example query pattern:

// Get all trades for a specific account
const trades = await fetch(
  `${BASE_URL}/trades?account_id=${accountId}`,
  { headers: { Authorization: `Bearer ${API_KEY}` } }
);

// Each trade includes its executions
trades.data.forEach(trade => {
  console.log(`Trade ${trade.symbol}: ${trade.executions.length} fills`);
});

Playbook hierarchy

Playbook
  ├─ Entry Criteria
  │    ├─ Criterion 1
  │    └─ Criterion 2
  ├─ Exit Criteria
  │    ├─ Criterion 1
  │    └─ Criterion 2
  └─ Strategies
       ├─ Strategy 1
       └─ Strategy 2

Example query pattern:

# Get playbooks with all nested data
playbooks = get_playbooks()

for playbook in playbooks['data']:
    print(f"\n{playbook['name']}")
    print(f"  Entry rules: {len(playbook['entry_criteria'])}")
    print(f"  Exit rules: {len(playbook['exit_criteria'])}")
    print(f"  Strategies: {len(playbook['strategies'])}")

Data ownership and isolation

User-scoped data

All API operations are automatically scoped to the authenticated user:

  • Users can only access their own data
  • Cross-user queries return empty results or 404 errors
  • Isolation is enforced at the database level

Example:

// User A's API key
const userA_key = "mpj_user_a_key";

// User B's API key  
const userB_key = "mpj_user_b_key";

// User A creates a trade
const trade = await createTrade(tradeData, userA_key);
console.log(`Created trade: ${trade.data.id}`);

// User B tries to access User A's trade
const response = await fetch(
  `${BASE_URL}/trades/${trade.data.id}`,
  { headers: { Authorization: `Bearer ${userB_key}` } }
);

// Returns 404 - trade doesn't "exist" for User B
console.log(response.status); // 404

ID formats

All entity IDs are UUIDs (version 4):

  • Format: a1b2c3d4-e5f6-7890-1234-567890abcdef
  • Globally unique
  • Safe to use in URLs and JSON

Field types and formats

Dates and times

  • Dates: ISO 8601 date format (YYYY-MM-DD)
  • Times: 24-hour format (HH:MM:SS)
  • Timestamps: ISO 8601 with timezone (2024-01-15T10:30:00Z)

Examples:

{
  "entry_date": "2024-01-15",
  "entry_time": "10:30:00",
  "created_at": "2024-01-15T10:30:00Z"
}

Monetary values

  • Type: Number (float)
  • Precision: Up to 2 decimal places for currencies
  • Format: No currency symbols, just numeric values

Examples:

{
  "entry_price": 245.50,
  "net_pnl": 158.25,
  "balance": 150000.00
}

Enumerations

Several fields use predefined string values:

Trade side:

  • "long" — Buy/long position
  • "short" — Sell/short position

Trade status:

  • "win" — Profitable trade
  • "loss" — Losing trade
  • "breakeven" — Zero P&L
  • "open" — Trade still in progress

Account type:

  • "prop" — Prop trading firm account
  • "retail" — Retail broker account

Execution side:

  • "buy" — Buy order
  • "sell" — Sell order

Complete example: Trade object

Here's a fully-annotated trade object showing all fields and their types:

{
  "id": "fd07b82a-164c-4c24-885a-7f4db54dab62",          // UUID
  "account_id": "f1588e0d-93fd-4a76-b876-b0753f93bc09",  // UUID (foreign key)
  "symbol": "NQ",                                         // string
  "side": "short",                                        // enum: "long" | "short"
  "quantity": 1,                                          // number (integer)
  "entry_price": 29298,                                   // number (float)
  "exit_price": 29290,                                    // number (float) | null
  "entry_time": "10:17:54",                              // string (HH:MM:SS)
  "exit_time": "10:18:29",                               // string (HH:MM:SS) | null
  "gross_pnl": 160,                                      // number (float)
  "net_pnl": 158,                                        // number (float)
  "total_commission": 2,                                 // number (float)
  "status": "win",                                       // enum: "win" | "loss" | "breakeven" | "open"
  "entry_date": "2026-02-05",                            // string (YYYY-MM-DD)
  "exit_date": "2026-02-05",                             // string (YYYY-MM-DD) | null
  "asset_class": "futures",                              // string
  "created_at": "2026-02-05T15:17:54+00:00",            // string (ISO 8601)
  "updated_at": "2026-02-05T15:18:29+00:00",            // string (ISO 8601)
  "executions": [                                        // array of execution objects
    {
      "id": "1ed21bd6-8ea2-42d0-b16e-142f9484ecb9",     // UUID
      "side": "sell",                                    // enum: "buy" | "sell"
      "price": 29298,                                    // number (float)
      "quantity": 1,                                     // number (integer)
      "commission": 1,                                   // number (float)
      "execution_time": "10:17:54",                      // string (HH:MM:SS)
      "execution_type": "scale_in",                      // string
      "execution_timestamp": "2026-02-05T15:17:54+00:00" // string (ISO 8601)
    }
  ]
}

Working with nested data

Accessing executions

// Get trades and analyze execution patterns
const trades = await getTrades();

trades.data.forEach(trade => {
  const numExecutions = trade.executions.length;
  const avgPrice = trade.executions.reduce((sum, exec) => 
    sum + exec.price, 0) / numExecutions;
  
  console.log(`${trade.symbol}: ${numExecutions} fills, avg price: ${avgPrice}`);
});

Filtering by nested properties

# Find all trades with more than 3 executions
trades = get_trades(limit=100)

complex_trades = [
    trade for trade in trades['data'] 
    if len(trade['executions']) > 3
]

print(f"Found {len(complex_trades)} trades with 3+ executions")