mirror of
https://github.com/velocitatem/PHANTOM.git
synced 2026-05-31 08:33:36 +00:00
chore: simple surge pricer
This commit is contained in:
@@ -79,7 +79,7 @@ def get_price(mode: Literal['hotel', 'airline'], productId: str, sessionId: Opti
|
|||||||
elasticity=None
|
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
|
# get elasticity if available
|
||||||
product_elasticity = None
|
product_elasticity = None
|
||||||
|
|||||||
@@ -12,4 +12,5 @@ graphviz
|
|||||||
python-dotenv>=1.0.0
|
python-dotenv>=1.0.0
|
||||||
requests>=2.31.0
|
requests>=2.31.0
|
||||||
typing-extensions>=4.8.0
|
typing-extensions>=4.8.0
|
||||||
pickle5>=0.0.11; python_version < '3.8'
|
pypickle
|
||||||
|
pymc
|
||||||
|
|||||||
@@ -292,12 +292,7 @@ async def get_products(
|
|||||||
# filter by exact date_index if provided
|
# filter by exact date_index if provided
|
||||||
# dateIndex from frontend is days from today, convert to days since epoch
|
# dateIndex from frontend is days from today, convert to days since epoch
|
||||||
if dateIndex is not None:
|
if dateIndex is not None:
|
||||||
from datetime import datetime
|
query = query.eq('date_index', dateIndex)
|
||||||
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)
|
|
||||||
|
|
||||||
response = query.execute()
|
response = query.execute()
|
||||||
results = response.data
|
results = response.data
|
||||||
|
|||||||
@@ -46,3 +46,51 @@ class RandomPricer(PricingFunction):
|
|||||||
if self.n_products is None:
|
if self.n_products is None:
|
||||||
self.n_products = len(state_space.demand)
|
self.n_products = len(state_space.demand)
|
||||||
return self.rng.uniform(self.price_min, self.price_max, size=self.n_products)
|
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
|
||||||
|
|||||||
Reference in New Issue
Block a user