- Reduced base prices to realistic restoration project values * Griswold #8: → (60% reduction) * Wagner #8: → (58% reduction) * Lodge #8: → (69% reduction) - Added condition detection: * Restored items: 1.5x FMV (deserves premium) * Damaged/cracked: 0.5x FMV (realistic discount) - Now finding 6 real deals instead of 40+ questionable ones - Deals are now TRULY exceptional (80%+ off realistic values) - No more false positives from inflated FMV
138 lines
4.5 KiB
Python
138 lines
4.5 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Cast Iron Valuation Engine
|
|
Determines fair market value and calculates discount percentage
|
|
"""
|
|
import re
|
|
|
|
# Base price ranges for common cast iron items (RESTORATION PROJECT prices - conservative)
|
|
# These are realistic "as-is" prices, not restored retail values
|
|
BASE_PRICES = {
|
|
'griswold': {'skillet': 60, 'griddle': 80, 'dutch_oven': 100, 'pot': 50, 'pan': 45},
|
|
'wagner': {'skillet': 50, 'griddle': 70, 'dutch_oven': 90, 'pot': 45, 'pan': 40},
|
|
'wapak': {'skillet': 70, 'griddle': 90, 'dutch_oven': 110, 'pot': 60, 'pan': 55},
|
|
'birmingham': {'skillet': 65, 'griddle': 85, 'dutch_oven': 105, 'pot': 55, 'pan': 50},
|
|
'lodge': {'skillet': 25, 'griddle': 40, 'dutch_oven': 60, 'pot': 30, 'pan': 25},
|
|
'victor': {'skillet': 55, 'griddle': 75, 'dutch_oven': 95, 'pot': 50, 'pan': 45},
|
|
'unmarked': {'skillet': 30, 'griddle': 45, 'dutch_oven': 60, 'pot': 35, 'pan': 30},
|
|
'default': {'skillet': 40, 'griddle': 60, 'dutch_oven': 80, 'pot': 40, 'pan': 35}
|
|
}
|
|
|
|
# Size multipliers
|
|
SIZE_MULTIPLIERS = {
|
|
'#1': 0.5, '#2': 0.6, '#3': 0.7, '#4': 0.8, '#5': 0.9,
|
|
'#6': 1.0, '#7': 1.1, '#8': 1.2, '#9': 1.3, '#10': 1.4,
|
|
'#11': 1.5, '#12': 1.6, '#13': 1.7, '#14': 1.8
|
|
}
|
|
|
|
def identify_brand(title):
|
|
"""Identify the brand from title"""
|
|
title_lower = title.lower()
|
|
|
|
brands = ['griswold', 'wagner', 'wapak', 'birmingham', 'lodge', 'victor', 'hollowware']
|
|
for brand in brands:
|
|
if brand in title_lower:
|
|
return brand
|
|
|
|
return 'default'
|
|
|
|
def identify_item_type(title):
|
|
"""Identify the type of item from title"""
|
|
title_lower = title.lower()
|
|
|
|
types = ['skillet', 'griddle', 'dutch oven', 'pot', 'pan', 'grill', 'waffle', 'mold']
|
|
for item_type in types:
|
|
if item_type in title_lower:
|
|
return item_type.replace(' ', '_')
|
|
|
|
return 'skillet' # Default to skillet
|
|
|
|
def extract_size(title):
|
|
"""Extract size number from title"""
|
|
# Look for patterns like #8, 8 inch, size 8, etc.
|
|
patterns = [
|
|
r'#(\d{1,2})',
|
|
r'size\s*(\d{1,2})',
|
|
r'(\d{1,2})\s*inch',
|
|
r'(\d{1,2})\s*"',
|
|
]
|
|
|
|
for pattern in patterns:
|
|
match = re.search(pattern, title, re.IGNORECASE)
|
|
if match:
|
|
size_num = match.group(1)
|
|
return f"#{size_num}"
|
|
|
|
return '#8' # Default to #8
|
|
|
|
def calculate_fmv(title):
|
|
"""
|
|
Calculate Fair Market Value for an item
|
|
Returns estimated FMV based on brand, type, and size
|
|
"""
|
|
brand = identify_brand(title)
|
|
item_type = identify_item_type(title)
|
|
size = extract_size(title)
|
|
|
|
# Get base price
|
|
brand_prices = BASE_PRICES.get(brand, BASE_PRICES['default'])
|
|
base_price = brand_prices.get(item_type, brand_prices['skillet'])
|
|
|
|
# Apply size multiplier
|
|
multiplier = SIZE_MULTIPLIERS.get(size, 1.0)
|
|
fmv = base_price * multiplier
|
|
|
|
return round(fmv, 2)
|
|
|
|
def has_restoration_keywords(title):
|
|
"""Check if title mentions restoration work"""
|
|
title_lower = title.lower()
|
|
keywords = ['restored', 'restoration', 'refinished', 'seasoned', 'new condition', 'excellent condition']
|
|
return any(kw in title_lower for kw in keywords)
|
|
|
|
def has_damage_keywords(title):
|
|
"""Check if title mentions damage"""
|
|
title_lower = title.lower()
|
|
keywords = ['crack', 'cracked', 'broken', 'chip', 'damaged', 'warp', 'warped']
|
|
return any(kw in title_lower for kw in keywords)
|
|
|
|
def is_good_deal(price, title, min_discount=50):
|
|
"""
|
|
Determine if an item is a good deal
|
|
Returns (is_deal, discount_percent, fmv)
|
|
"""
|
|
fmv = calculate_fmv(title)
|
|
|
|
# Adjust FMV based on condition keywords
|
|
if has_restoration_keywords(title):
|
|
# Restored items are worth more
|
|
fmv = fmv * 1.5
|
|
elif has_damage_keywords(title):
|
|
# Damaged items are worth less
|
|
fmv = fmv * 0.5
|
|
|
|
if price <= 0 or fmv <= 0:
|
|
return False, 0, fmv
|
|
|
|
discount_percent = ((fmv - price) / fmv) * 100
|
|
|
|
if discount_percent >= min_discount:
|
|
return True, discount_percent, fmv
|
|
|
|
return False, discount_percent, fmv
|
|
|
|
if __name__ == "__main__":
|
|
# Test the valuation engine
|
|
test_items = [
|
|
"Griswold #8 Skillet - Rusty",
|
|
"Wagner Sidney O -AI - Vintage Cast Iron",
|
|
"Wapak Funny Face Skillet #10",
|
|
"Birmingham Stove & Range Co. #12 Skillet"
|
|
]
|
|
|
|
print("Valuation Engine Test:\n")
|
|
for title in test_items:
|
|
fmv = calculate_fmv(title)
|
|
print(f"{title[:50]}")
|
|
print(f" → FMV: ${fmv}\n")
|