Deployment & System Requirements
Hardware Requirements
BidOptic is a CPU-bound simulation workload. No GPU is required at any stage.
The primary resource driver is your dataset size. RAM is the binding constraint for large datasets; CPU core count affects calibration speed but not correctness.
| Resource | Datasets up to 2M rows | Datasets up to 10M rows |
|---|---|---|
| RAM | 16 GB | 32 GB |
| CPU | 4+ cores (any modern processor) | 8+ cores recommended |
| Disk (free space) | 10 GB | 20 GB |
| Docker | Engine 20.10+ (Linux) or Docker Desktop 4.x+ (macOS / Windows) | Same |
On RAM. 16 GB is sufficient for datasets up to approximately 2 million rows. For larger datasets (up to the supported 10 million row ceiling), 32 GB is required to avoid out-of-memory errors during the high-dimensional model training phase.
On CPU. The calibration pipeline parallelises across all available cores. An 8-core machine completes calibration of a 3-million-row dataset in approximately 60–90 seconds. Simulation episode runtime scales with AUCTIONS_PER_STEP and SIMULATION_PERIOD_DAYS; the default 7-day configuration with 3 seed runs completes in under 2 minutes on any compliant machine.
On operating system. Three platforms are supported:
- Linux (x86-64): Fully supported for both development and production evaluation runs. Requires Docker Engine 20.10 or later.
- macOS (Apple Silicon or Intel): Supported via Docker Desktop. Recommended for development only; virtualisation overhead affects latency benchmarks and production evaluation results may not be representative.
- Windows 10 / 11 (x86-64): Supported via Docker Desktop. When using Git Bash, prefix all
docker runcommands withMSYS_NO_PATHCONV=1to prevent path mangling. Recommended for development only; virtualisation overhead affects latency benchmarks and production evaluation results may not be representative.
What You Will Receive
At the start of an Evaluation Agreement you will receive:
bidoptic.tar.gz— the encrypted Docker image archive containing the C-compiled BidOptic core engine.client/— the SDK directory containing:README.md— quick-start guide and observation key reference.license.bin— your licence token, scoped to your evaluation period and hardware-locked to your machine ID.contracts.py— the two abstract interfaces (Enricher,Strategy).config.yaml— your campaign parameter file.enricher.pyandstrategy.py— working baseline implementations that produce meaningful output immediately, ready for you to iterate on.NOTICE.txt— open-source attribution notices for third-party libraries included in the engine.data/— place your validated Parquet or CSV file here before running.output/— all results are written here after each run.- This documentation.
Loading and Running the Container
Step 1 — Load the image
docker load -i bidoptic.tar.gz
This registers the image locally. It does not start a container or open any network connections.
Step 2 — Run calibration and simulation
docker run --rm \
--network none \
-v /path/to/your/client:/app/client \
-v /etc/machine-id:/app/host/machine-id:ro \
bidoptic:latest \
--data /app/client/data/your_campaign_logs.parquet
Replace /path/to/your/client with the absolute path to the client/ folder you received. Place your data file inside client/data/ before running. On Windows with Git Bash, prefix the command with MSYS_NO_PATHCONV=1.
All outputs are written to client/output/ on your host filesystem.
Parameter reference
| Flag | Description |
|---|---|
--rm |
Removes the container automatically when it exits. |
--network none |
Disables all network interfaces. Required — the container will abort if a non-loopback interface is detected. |
-v .../client:/app/client |
Bind-mounts your client folder. Must contain license.bin, config.yaml, enricher.py, strategy.py, and your data file under data/. |
-v /etc/machine-id:/app/host/machine-id:ro |
Provides the host machine ID for hardware-lock validation. Required on Linux. On macOS and Windows, Docker Desktop supplies a stable synthetic machine ID automatically. |
--data |
Path inside the container to your input Parquet or CSV file. |
Plugging In Your Strategy
The Observation Dictionary (obs)
When the simulation calls your enrich(obs) and bid(enriched_obs) methods, you receive a dictionary of NumPy arrays. Each array has a shape of (batch_size,).
A complete observation key reference is included in the SDK bundle delivered at the start of an Evaluation Agreement
After calibration completes, the container immediately runs the simulation using your current enricher.py and strategy.py. You interact with the simulation by implementing two Python classes defined in client/contracts.py:
Enricher: Implement the enrich(obs) method. This is where your pCTR, pCVR, or LTV model runs. The method receives an auction observation dictionary and must return it with a predicted_value key added (a scalar float representing the expected value of the auction, e.g. pCVR × expected_payout).
Strategy: Implement the bid(enriched_obs) method. This receives the enriched observation and must return a NumPy array of bid prices in your campaign currency (one per auction). Return 0.0 to pass on an auction.
The SDK measures the wall-clock time consumed by your enrich and bid calls and feeds that measured latency directly into the simulation physics. Your latency is observed rather than estimated.
Each time you update your strategy or enricher, re-run the same Docker command. Calibration is cached, meaning the container detects that models already exist and skips straight to simulation, making iteration fast.
Campaign Configuration
Before running a simulation episode, edit client/config.yaml to reflect your campaign parameters:
# ================================================================
# CAMPAIGN TARGETS & BUDGET
# ================================================================
TOTAL_BUDGET:
value: 10000.0 # in your campaign currency
override: true
KPI_MODE:
value: roas # Options: roas | cpa | revenue
override: true
TARGET_ROAS:
value: 2.0
override: true
TARGET_CPA:
value: 15.0
override: true
MIN_SPEND_BEFORE_KILL:
value: 2000.0 # Spend threshold before early KPI kill engages
override: true
KPI_KILL_MULTIPLIER:
value: 5.0 # Kills episode if CPA > 5x target or ROAS < target/5
override: true
# ================================================================
# SIMULATION RUNTIME SETTINGS
# ================================================================
SIMULATION_PERIOD_DAYS:
value: 7 # Increase to 14 if conversion delays cause zero attribution
override: true
NUM_SIMULATION_SEEDS:
value: 3 # Default: 3. Higher = tighter variance estimates, longer runtime.
override: true
# ================================================================
# COUNTERFACTUAL SCENARIO: MARKET STRUCTURE
# ================================================================
EXPLICIT_ARCHETYPE_MARKET_SHARE:
value: 0.30 # 0.40-0.60: Consolidated market | 0.20-0.35: Average market midpoint | 0.05-0.15: Highly fragmented
AUCTION_TYPE_DISTRIBUTION:
value:
first_price: 1.0
second_price: 0.0
override: true
# ================================================================
# COUNTERFACTUAL SCENARIO: CREATIVE PERFORMANCE
# ================================================================
ACTIVE_CREATIVE_ID:
value: Premium_Video_Ad
override: true
CREATIVES:
value:
Premium_Video_Ad:
base_ctr_multiplier: 1.5 # 50% more clicks
fatigue_rate: 0.000002
appeal_segment: 2 # targets segment 2 specifically
appeal_multiplier: 4.0
override: true
Troubleshooting: Revenue = $0.00 & Early Terminations
Work through this checklist in order if your simulation is failing:
1. Win Rate = 0%: Bids are below every floor.
Check visible_floor range in your data (typical: 0.01–0.50 in your campaign currency). The baseline strategy already floors against visible_floor * 1.01.
2. Wins but zero clicks: Winning low-quality inventory with near-zero CTR.
Filter out auctions where pub_avg_cvr < 0.001.
3. Clicks but zero conversions: Conversions have realistic post-click delays (~2 days avg).
Check the Attribution Bridge line in the logs. If it also shows 0.00, try SIMULATION_PERIOD_DAYS: 14.
4. "BINARY CONVERSION MODE" warning: Your calibration data had no conversion_value variance.
each conversion is assigned a fixed value of 1.00 in your campaign currency. ROAS here equals conversions per unit of spend, not revenue ROAS. Add a conversion_value column to your training data and re-calibrate to unlock true ROAS.
5. Simulation terminates early: KPI kill guard firing before conversions accumulate.