Skip to content

Core Concepts

Understanding these core concepts will help you use qlcore effectively.

Design Philosophy

Pure Computation

qlcore is a pure computation library. It has:

  • ✅ Mathematical functions and domain models
  • ✅ Type definitions and validation
  • ❌ No network I/O
  • ❌ No database connections
  • ❌ No file system operations (except explicit save/load)
  • ❌ No external API calls

This makes qlcore:

  • Testable — Deterministic, no mocks needed
  • Portable — Works anywhere Python runs
  • Composable — Integrate with any data source or execution layer

Decimal Precision

All financial calculations use Python's Decimal type:

from decimal import Decimal

# qlcore accepts multiple input types
qc.Fill.create(
    quantity="0.1",           # String → Decimal internally
    price=Decimal("45000"),   # Decimal directly
    fee=4.5,                  # Float → converted to Decimal
    ...
)

Avoid Float Arithmetic

# ❌ Don't do this
0.1 + 0.2  # = 0.30000000000000004

# ✅ Do this
Decimal("0.1") + Decimal("0.2")  # = Decimal("0.3")

Immutability

Positions are immutable frozen dataclasses:

position = qc.SpotPosition(
    instrument_id="BTC-USD",
    side=qc.PositionSide.LONG,
    size=Decimal("1.0"),
    avg_entry_price=Decimal("45000"),
)

# Positions cannot be modified
position.size = Decimal("2.0")  # ❌ Raises error

# Instead, create a new position with evolve()
new_position = position.evolve(size=Decimal("2.0"))  # ✅

This design provides:

  • Thread safety — Share positions across threads
  • Audit trail — Every state is a separate snapshot
  • Debugging — Compare any two states easily

Position Types

qlcore supports three position types for different instruments:

SpotPosition

For spot markets and equities where you own the underlying asset.

position = qc.SpotPosition(
    instrument_id="BTC-USD",
    side=qc.PositionSide.LONG,
    size=Decimal("1.0"),
    avg_entry_price=Decimal("45000"),
)

Key characteristics:

  • No leverage
  • No funding payments
  • No expiration

PerpetualPosition

For perpetual futures contracts that never expire.

position = qc.PerpetualPosition(
    instrument_id="BTC-USDT-PERP",
    side=qc.PositionSide.LONG,
    size=Decimal("1.0"),
    avg_entry_price=Decimal("45000"),
    accumulated_funding=Decimal("-12.50"),  # Funding paid
)

Key characteristics:

  • Leveraged (margin required)
  • Funding payments every 8 hours (typically)
  • Tracks accumulated funding

FuturesPosition

For traditional futures with an expiration date.

position = qc.FuturesPosition(
    instrument_id="BTC-USD-MAR25",
    side=qc.PositionSide.SHORT,
    size=Decimal("0.5"),
    avg_entry_price=Decimal("46000"),
    expiry_ms=1711929600000,  # March 2025
)

Key characteristics:

  • Leveraged
  • Fixed expiration date
  • Settlement at expiry

Domain Events

Events represent things that happen to positions:

Fill

A trade execution:

fill = qc.Fill.create(
    order_id="order-001",
    instrument_id="BTC-USDT-PERP",
    side=qc.OrderSide.BUY,
    quantity="0.1",
    price="45000",
    fee="4.5",
    timestamp_ms=1701849600000,
)

FundingEvent

A funding payment on a perpetual:

funding = qc.FundingEvent(
    instrument_id="BTC-USDT-PERP",
    funding_rate=Decimal("0.0001"),  # 0.01%
    timestamp_ms=1701878400000,
)

LiquidationEvent

A forced position closure:

liquidation = qc.LiquidationEvent(
    instrument_id="BTC-USDT-PERP",
    quantity=Decimal("0.1"),
    price=Decimal("40000"),
    timestamp_ms=1701900000000,
)

SettlementEvent

A futures contract settling at expiry:

settlement = qc.SettlementEvent(
    instrument_id="BTC-USD-MAR25",
    settlement_price=Decimal("47000"),
    timestamp_ms=1711929600000,
)

Portfolio & Account

Account

Holds cash balances across currencies:

account = qc.Account(
    base_currency="USDT",
    balances={
        "USDT": Decimal("10000"),
        "BTC": Decimal("0.5"),
    },
)

Portfolio

Contains an account and positions:

portfolio = qc.Portfolio(account=account)

# Apply fills to update positions
portfolio = portfolio.apply_fill(fill)

# Access positions
btc_position = portfolio.positions.get("BTC-USDT-PERP")

Relationship

Portfolio
├── Account (balances)
└── Positions (dict)
    ├── "BTC-USDT-PERP" → PerpetualPosition
    ├── "ETH-USDT-PERP" → PerpetualPosition
    └── "BTC-USD" → SpotPosition

Type System

qlcore uses type aliases for clarity:

Type Meaning Base Type
Money Currency amounts Decimal
Price Asset prices Decimal
Quantity Position sizes Decimal
Rate Percentages/rates Decimal
TimestampMs Unix milliseconds int
from qlcore import Money, Price, Quantity, Rate, TimestampMs

price: Price = Decimal("45000")
size: Quantity = Decimal("0.1")
fee: Money = Decimal("4.5")
rate: Rate = Decimal("0.001")
ts: TimestampMs = 1701849600000

Error Handling

qlcore raises specific exceptions:

Exception When
ValidationError Invalid input (negative price, empty ID)
InvalidFillError Malformed fill data
MathError Impossible calculation
InsufficientMargin Not enough margin for trade
PositionNotFound Position doesn't exist
InstrumentNotFound Unknown instrument
try:
    fill = qc.Fill.create(
        quantity="-1",  # ❌ Negative quantity
        ...
    )
except qc.ValidationError as e:
    print(f"Validation failed: {e}")

Next Steps