From a38fac9d2bb084171c2cd976e5c4e8dc58d9fdb8 Mon Sep 17 00:00:00 2001 From: Daniel Rosel Date: Fri, 5 Dec 2025 12:44:21 +0100 Subject: [PATCH] chore: simple surge pricer --- backend/provider/app.py | 2 +- backend/provider/requirements.txt | 3 +- backend/server/app.py | 7 +--- experiments/procesing/pricers/simple.py | 48 +++++++++++++++++++++++++ 4 files changed, 52 insertions(+), 8 deletions(-) diff --git a/backend/provider/app.py b/backend/provider/app.py index 654aca3..fb72a9d 100644 --- a/backend/provider/app.py +++ b/backend/provider/app.py @@ -79,7 +79,7 @@ def get_price(mode: Literal['hotel', 'airline'], productId: str, sessionId: Opti elasticity=None ) - optimal_price = float(product_price_row['predicted_price'].iloc[0]) + optimal_price = float(product_price_row['optimal_price'].iloc[0]) # TODO: use optimal_price everywhere as aresult # get elasticity if available product_elasticity = None diff --git a/backend/provider/requirements.txt b/backend/provider/requirements.txt index 4169911..2b3c9ac 100644 --- a/backend/provider/requirements.txt +++ b/backend/provider/requirements.txt @@ -12,4 +12,5 @@ graphviz python-dotenv>=1.0.0 requests>=2.31.0 typing-extensions>=4.8.0 -pickle5>=0.0.11; python_version < '3.8' +pypickle +pymc diff --git a/backend/server/app.py b/backend/server/app.py index 7190b19..d338408 100644 --- a/backend/server/app.py +++ b/backend/server/app.py @@ -292,12 +292,7 @@ async def get_products( # filter by exact date_index if provided # dateIndex from frontend is days from today, convert to days since epoch if dateIndex is not None: - from datetime import datetime - epoch = datetime(1970, 1, 1) - today = datetime.now().replace(hour=0, minute=0, second=0, microsecond=0) - today_index = int((today - epoch).total_seconds() / 86400) - actual_date_index = today_index + dateIndex - query = query.eq('date_index', actual_date_index) + query = query.eq('date_index', dateIndex) response = query.execute() results = response.data diff --git a/experiments/procesing/pricers/simple.py b/experiments/procesing/pricers/simple.py index e98b9be..66558c6 100644 --- a/experiments/procesing/pricers/simple.py +++ b/experiments/procesing/pricers/simple.py @@ -46,3 +46,51 @@ class RandomPricer(PricingFunction): if self.n_products is None: self.n_products = len(state_space.demand) return self.rng.uniform(self.price_min, self.price_max, size=self.n_products) + + +class SimpleSurgePricer(PricingFunction): + """ + Rule-based surge pricer adjusting prices via demand thresholds. + Logic: if demand > high_threshold -> surge, if demand < low_threshold -> discount. + Simpler and more controllable than curve fitting approaches. + """ + + def __init__(self, + base_prices: np.ndarray = None, + high_threshold: int = 10, + low_threshold: int = 2, + surge_multiplier: float = 1.2, + discount_multiplier: float = 0.9): + self.base_prices = base_prices + self.high_threshold = high_threshold + self.low_threshold = low_threshold + self.surge_multiplier = surge_multiplier + self.discount_multiplier = discount_multiplier + + def fit(self, historical_data: pd.DataFrame): + """Extract base prices from product catalog or historical averages""" + if 'base_price' in historical_data.columns: + self.base_prices = historical_data['base_price'].values + elif 'price' in historical_data.columns: + self.base_prices = historical_data.groupby('productId')['price'].mean().values + else: + raise ValueError("historical_data must contain 'base_price' or 'price'") + return self + + def predict(self, state_space) -> np.ndarray: + """ + Adjust prices based on current demand using surge rules. + state_space.demand: demand counts per product + state_space.prices: current prices (fallback if base_prices not set) + """ + current_prices = self.base_prices if self.base_prices is not None else state_space.prices + demand = state_space.demand + new_prices = current_prices.copy() + + high_mask = demand >= self.high_threshold + new_prices[high_mask] *= self.surge_multiplier + + low_mask = demand <= self.low_threshold + new_prices[low_mask] *= self.discount_multiplier + + return new_prices