Whitepaper · MonetizeSlot Engine

MonetizeSlot Engine White Paper

Dynamic Pricing and Bet Configuration for iGaming Slots
Layered policy engine with online learning, governance, and simulation.

Executive Summary

MonetizeSlot Engine computes real-time pricing and bet configuration decisions for iGaming slot games, adapting to demand signals while enforcing explainable policies and regulatory guardrails.

The system routes requests through a Python "brain" that selects between capacity-based rules and Thompson Sampling bandits, optionally delegating capacity logic to a Go microservice under high load.

Operators configure policies in PostgreSQL, persist every decision for audit, stream events to Kafka, and run daily fairness audits using Gini coefficients—all while maintaining a simple integration contract via FastAPI endpoints.

Design principle: Separate forecasting, decisioning, learning, and governance so every action remains explainable and reversible.

The Challenge

iGaming operators face variable demand across games and hours, requiring dynamic pricing that maximizes ARPU without introducing excessive volatility or fairness risk.

Static pricing under-monetizes peaks, while uncontrolled optimization can violate regulatory constraints or create unequal player experiences.

MonetizeSlot solves this with a layered architecture: forecast → policy selection → optimization (capacity or bandit) → governance → persistence and events.

Architecture Overview

Architecture Overview
Client RequestFastAPI LayerPricing Core EngineThe Brain - Python PipelineLayer 1: ForecastLayer 2: CapacityLayer 3: Bandit AILayer 4: FairnessThe Muscle - Go RuntimeGo MicroservicePostgreSQL

MonetizeSlot separates concerns across explicit layers, with policy configuration stored in pricing_policies and loaded dynamically at runtime.

The core supports per-game demand disaggregation via game_share_dow_hour and policy resolution via experiment scopes or game mappings.

Every decision returns a unified structure: final_price, reason, bandit metadata (action_idx, multiplier, actions_hash), experiment metadata, and bet configuration (min_bet, max_bet, default_bet, bet_steps, rtp_profile_id).

Runtime Decision Modes

Operators select mode per request: capacity (rule-based) or bandit (online learning).

Capacity Mode (Layer 2)

  • Uses a PriceConfig (base/min/max price, soft/hard capacity) to compute recommended price from predicted players.
  • Supports game-specific baselines via game_capacity_baseline.
  • Optionally delegates to Go microservice /runtime/price for low-latency execution when enabled.
  • Example logic: raise price above soft capacity, cap above hard capacity, lower below utilization threshold.

Bandit Mode (Layer 3)

  • Selects a multiplier from discrete actions (default [0.8, 1.0, 1.2, 1.5]) via Thompson Sampling, where each action maintains a Normal posterior (mu, precision).
  • Bandits are per-game + demand-bucketed (p_high/p_mid/p_low or d_high/d_mid/d_low).
  • Bandits are keyed by (game_id:bucket:actions_hash) to prevent action remapping errors.
  • State persists via BanditState with load-from-DB bootstrap.

Bet Configuration Generation

Every decision builds a bet ladder from final_price using policy-provided bet_config factors (default: min 0.5x, max 1.5x, 5 steps) or simple heuristics.

Operators can specify rtp_profile_id per policy, enabling joint optimization of price and RTP.

This ensures consistent game configuration across capacity and bandit decisions.

Policy Resolution & Experimentation

Runtime resolves policies via resolve_policy_for_request: experiments first (via experiment_scopes), then game mappings (game_pricing_policies), filtered by type/time/segment/default.

Separate experiment bucketing uses stable MD5 hash (experiment_id:player_id) % 100 to assign deterministic variants from traffic_allocation.

Decisions record resolved_policy_id, experiment_id, and variant for full traceability.

Governance and Fairness (Layer 4)

Daily run_daily_fairness_audit computes the Gini coefficient over final_price distribution in price_decisions for the audit date, flagging if above a threshold (default 0.3).

Results upsert into fairness_audit with avg_price, gini_coefficient, alert_flag, and action_taken.

Gini measures inequality on a 0–1 scale where 0 indicates perfect equality and 1 indicates maximal inequality.

Persistence and Observability

Every runtime decision inserts into price_decisions with demand inputs, policy id, bandit metadata, bet config, and decision_mode.

Experiment assignments log to experiment_assignments; Kafka publishes pricing_decision or bandit_decision events keyed by decision_id for downstream analytics.

Structured logging captures full decision context via logger.info with rich extra payloads.

Offline Simulation

run_simulation_worker executes A/B comparisons between control/variant policies over horizon_days × n_players, persisting decisions to simulation_price_decisions and summarizing uplift in simulation_runs.

It supports capacity, bandit, and static policies with realistic revenue simulation and bet configuration generation.

This is designed for policy iteration and configuration validation, not production deployment.

Integration API (FastAPI)

Public endpoints use Pydantic models and structured responses.

/runtime/price (Primary)

Request
POST /runtime/price
{
  "game_id": "slots_gonzo_quest",
  "player_id": 12345,
  "base_price": 2.0,
  "mode": "bandit",
  "context": {"predicted_players": 150}
}
Response
{
  "price": 3.0,
  "policy_type": "bandit_ts",
  "reason": "thompson_sampling_action=1.5_idx=3",
  "action_id": 3,
  "multiplier": 1.5,
  "min_bet": 1.5,
  "max_bet": 4.5,
  "bet_steps": [1.5, 2.25, 3.0, 3.75, 4.5],
  "rtp_profile_id": "rtp_96",
  "experiment_id": 1,
  "variant": "treatment_2"
}

Other runtime endpoints

  • /price/decide-and-store — persist + event; derives forecast and p_game internally and supports capacity fallback.
  • /price/bandit-decide — bandit-only decision + persistence + event.
  • /price/recommendation — non-persisting capacity recommendation and demand breakdown.

Production Considerations

  • Multi-tenancy: Operator scoping via operator_id (currently hardcoded 1; planned tenant resolution).
  • Latency: Optional Go delegation for capacity; bandit selection is O(actions) with small action sets.
  • Persistence: In-memory bandits bootstrap from BanditState; decisions persist synchronously.
  • Scaling: Stateless runtime + Kafka decouples decisioning from analytics; Go runtime scales independently.

Appendix: Code-to-Feature Mapping

FeatureImplementation
Runtime orchestrationsrc/engine/pricing_core.py::compute_runtime_price
Policy resolutionsrc/engine/policy_resolution.py
Thompson Samplingsrc/layer3_rl/thompson_sampling.py
Contextual banditssrc/layer3_rl/contextual_bandits.py
Fairness auditsrc/layer4_execution/fairness_audit.py
Runtime APIsrc/api/routers/runtime.py
Schemassrc/api/schemas.py
Simulationsrc/engine/simulation.py
Batch capacitysrc/layer4_execution/price_generator.py

MonetizeSlot Engine v0.1

Production-ready pricing for iGaming operators. Deploy, simulate, roll out, measure.

References

  1. Internal MonetizeSlot Engine implementation (pricing core, runtime router, RL bandits, fairness audit, simulation).
  2. Open Graph protocol and usage guidance for social sharing metadata (og:type article recommended for articles). ogp.me
  3. Gini coefficient definition (0 = perfect equality, 1 = maximal inequality). Our World in Data
  4. Kafka event sourcing overview and practical patterns. Tinybird
  5. FastAPI response_model behavior and schema generation. FastAPI docs
  6. Open Graph best practices (title/description/type guidance). Ahrefs