Development of an AI-based dynamic pricing system for hotels Revenue Management
Revenue Management (RM) is revenue management through price optimization based on demand. The airline industry has been using RM since the 1980s. Hotels adopted it later, and most still operate under simplified rules. An AI system increases RevPAR (Revenue Per Available Room) by 5-15%.
Key concepts of Hotel RM
Key metrics:
- Occupancy Rate: % of occupied rooms
- ADR (Average Daily Rate): average price of a sold room
- RevPAR = Occupancy × ADR is a key KPI
- TRevPAR: Total Revenue per Available Room (F&B, SPA, парковка)
Оptimization objective:
Maximize RevPAR = Σ (price_t × occupancy_t) / total_rooms
Don't maximize occupancy (sell at a low price) or ADR (sell at a low price). Balance price and occupancy.
Demand forecast
Input data:
demand_features = {
# Исторические
'occupancy_lag_7d': occupancy_7_days_ago,
'occupancy_lag_365d': occupancy_same_date_last_year,
'revenue_lag_7d': revenue_7d_ago,
# Forward-looking (из OTA, direct booking)
'reservations_on_books': current_reservations,
'reservations_pace': reservations_vs_same_period_last_year,
'cancellation_rate_on_books': expected_cancellations,
# Внешние
'city_events': conference_concert_sports_score,
'holiday_flag': is_holiday,
'competitor_rates': compset_avg_rate, # из Rate Shopping tool
'flight_arrivals_forecast': airport_arrivals,
'weather': weather_forecast,
'day_of_week': dow,
'days_until_arrival': lead_time
}
Model: LightGBM for occupancy forecasts × 365 days ahead (each date → a separate forecast). Updated daily with new booking data.
Price optimization
Price Sensitivity model:
def estimate_demand(price, base_demand, elasticity):
"""
log(D) = log(D0) + ε × log(P/P0)
ε = price elasticity (обычно -0.5 до -2.0 для отелей)
"""
return base_demand * (price / baseline_price) ** elasticity
Revenue Optimization:
from scipy.optimize import minimize_scalar
def optimize_price(base_demand, elasticity, variable_cost=0):
def neg_revenue(price):
demand = estimate_demand(price, base_demand, elasticity)
return -(price - variable_cost) * demand
result = minimize_scalar(neg_revenue, bounds=(min_price, max_price), method='bounded')
return result.x
Segmentation by channels:
- OTA (Booking.com, Expedia): high commission of 15-20%, wide audience
- Direct (hotel website): no commission, loyal customers
- Corporate: fixed rates by agreement
- GDS: corporate agents
Different channels mean different optimal prices (net revenue = price - commission).
Length of Stay (LOS) optimization
Not just today's price, but also how many days are being booked. On the Friday before a free Sunday, only long-term bookings (Fri+Sat+Sun) are accepted, with a slightly lower price.
Minimum LOS restrictions:
def calculate_min_los(date, forecast, avg_los_by_segment):
"""
Если прогнозируется высокий спрос на период D+2/D+3 →
установить минимальное LOS = 2, чтобы не "дробить" инвентарь
"""
if forecast[date:date+timedelta(days=2)].mean() > occupancy_threshold:
return 2 # требуем минимум 2 ночи
return 1
Competitive Rate Intelligence
Real-time monitoring of competitors' prices:
Rate Shopping:
- OTA Insight, Duetto, RateGain: competitor price aggregators
- Direct parsing (legality depends on ToS)
- Rate parity: check if the OTA offers a lower price than the direct website
Competitive positioning:
def competitive_rate_recommendation(own_forecast, compset_rates, positioning='market'):
"""
positioning: 'premium' (+10% к compset), 'market' (паритет), 'value' (-5%)
"""
compset_avg = np.mean(compset_rates)
if positioning == 'premium':
target = compset_avg * 1.10
elif positioning == 'market':
target = compset_avg
else:
target = compset_avg * 0.95
# Если прогнозируем высокий собственный спрос — отклоняемся вверх
demand_premium = max(0, (own_forecast.occupancy - 0.8) * 50)
return target + demand_premium
Integration с PMS и Channel Manager
PMS (Property Management System):
- Opera Cloud, Protel, 1C:Hotel
- API for obtaining: reservations, occupancy, rate plans
- API for recording: rate updates
Channel Manager:
- SiteMinder, Wubook, Bnovo
- Synchronization of updated prices for all OTAs simultaneously
Pipeline:
- Daily 05:00: Import reservations from PMS
- Updating the demand forecast
- Launching the price optimizer for a 365-day horizon
- Checking price rules (min/max rates, rate parity)
- Record in Channel Manager → automatic update on Booking.com/Expedia
Metrics:
- RevPAR improvement: 5-15% vs. baseline (without AI RM)
- Forecast accuracy (MAPE occupancy): < 8%
- Price update frequency: daily for 365 days
Timeframe: Occupancy forecast + basic price optimizer – 6-8 weeks. A full-fledged system with LOS optimization, competitive intelligence, and PMS integration – 4-5 months.







