Files
auctiora/docs/VALUATION.md
2025-12-09 12:32:30 +01:00

9.6 KiB

Auction Valuation Mathematics - Technical Reference

1. Fair Market Value (FMV) - Core Valuation Formula

The baseline valuation is calculated using a weighted comparable sales approach:


FMV = \frac{\sum_{i=1}^{n} \left( P_i \cdot \omega_c \cdot \omega_t \cdot \omega_p \cdot \omega_h \right)}{\sum_{i=1}^{n} \left( \omega_c \cdot \omega_t \cdot \omega_p \cdot \omega_h \right)}

Variables:

  • P_i = Final hammer price of comparable lot i (€)
  • \omega_c = Condition weight: \exp(-\lambda_c \cdot |C_{target} - C_i|)
  • \omega_t = Time weight: \exp(-\lambda_t \cdot |T_{target} - T_i|)
  • \omega_p = Provenance weight: 1 + \delta_p \cdot (P_{target} - P_i)
  • \omega_h = Historical weight: \left( \frac{1}{1 + e^{-kh \cdot (D_i - D_{median})}} \right)

Parameter Definitions:

  • C \in [0, 10] = Condition score (10 = perfect)
  • T = Manufacturing year
  • P \in \{0,1\} = Provenance flag (1 = documented history)
  • D_i = Days since comparable sale
  • \lambda_c = 0.693 = Condition decay constant (50% weight at 1-point difference)
  • \lambda_t = 0.048 = Time decay constant (50% weight at 15-year difference)
  • \delta_p = 0.15 = Provenance premium coefficient
  • kh = 0.01 = Historical relevance coefficient

2. Condition Adjustment Multiplier

Normalizes prices across condition states:


M_{cond} = \exp\left( \alpha_c \cdot \sqrt{C_{target}} - \beta_c \right)

Variables:

  • \alpha_c = 0.15 = Condition sensitivity parameter
  • \beta_c = 0.40 = Baseline condition offset
  • C_{target} = Target lot condition score

Interpretation:

  • C = 10 (mint): M_{cond} = 1.48 (48% premium over poor condition)
  • C = 5 (average): M_{cond} = 0.91

3. Time-Based Depreciation Model

For equipment/machinery with measurable lifespan:


V_{age} = V_{new} \cdot \left( 1 - \gamma \cdot \ln\left( 1 + \frac{Y_{current} - Y_{manu}}{Y_{expected}} \right) \right)

Variables:

  • V_{new} = Original market value (€)
  • \gamma = 0.25 = Depreciation aggressivity factor
  • Y_{current} = Current year
  • Y_{manu} = Manufacturing year
  • Y_{expected} = Expected useful life span (years)

Example: 10-year-old machinery with 25-year expected life retains 85% of value.


4. Provenance Premium Calculation


\Delta_{prov} = V_{base} \cdot \left( \eta_0 + \eta_1 \cdot \ln(1 + N_{docs}) \right)

Variables:

  • V_{base} = Base valuation without provenance (€)
  • N_{docs} = Number of verifiable provenance documents
  • \eta_0 = 0.08 = Base provenance premium (8%)
  • \eta_1 = 0.035 = Marginal document premium coefficient

5. Undervaluation Detection Score

Critical for identifying mispriced opportunities:


U_{score} = \frac{FMV - P_{current}}{FMV} \cdot \sigma_{market} \cdot \left( 1 + \frac{B_{velocity}}{B_{threshold}} \right) \cdot \ln\left( 1 + \frac{W_{watch}}{W_{bid}} \right)

Variables:

  • P_{current} = Current bid price (€)
  • \sigma_{market} \in [0,1] = Market volatility factor (from indices)
  • B_{velocity} = Bids per hour (bph)
  • B_{threshold} = 10 bph = High-velocity threshold
  • W_{watch} = Watch count
  • W_{bid} = Bid count

Trigger condition: U_{score} > 0.25 (25% undervaluation) with confidence > 0.70


6. Bid Velocity Indicator (Competition Heat)

Measures real-time competitive intensity:


\Lambda_b(t) = \frac{dB}{dt} \cdot \exp\left( -\lambda_{cool} \cdot (t - t_{last}) \right)

Variables:

  • \frac{dB}{dt} = Bid frequency derivative (bids/minute)
  • \lambda_{cool} = 0.1 = Cool-down decay constant
  • t_{last} = Timestamp of last bid (minutes)

Interpretation:

  • \Lambda_b > 5 = Hot lot (bidding war likely)
  • \Lambda_b < 0.5 = Cold lot (potential sleeper)

7. Final Price Prediction Model

Composite machine learning-style formula:


\hat{P}_{final} = FMV \cdot \left( 1 + \epsilon_{bid} + \epsilon_{time} + \epsilon_{comp} \right)

Error Components:

  • Bid momentum error:

    \epsilon_{bid} = \tanh\left( \phi_1 \cdot \Lambda_b - \phi_2 \cdot \frac{P_{current}}{FMV} \right)
  • Time-to-close error:

    \epsilon_{time} = \psi \cdot \exp\left( -\frac{t_{close}}{30} \right)
  • Competition error:

    \epsilon_{comp} = \rho \cdot \ln\left( 1 + \frac{W_{watch}}{50} \right)

Parameters:

  • \phi_1 = 0.15, \phi_2 = 0.10 = Bid momentum coefficients
  • \psi = 0.20 = Time pressure coefficient
  • \rho = 0.08 = Competition coefficient
  • t_{close} = Minutes until close

Confidence interval:


CI_{95\%} = \hat{P}_{final} \pm 1.96 \cdot \sigma_{residual}

8. Bidding Strategy Recommendation Engine

Optimal max bid and timing:


S_{max} =
\begin{cases}
FMV \cdot (1 - \theta_{agg}) & \text{if } U_{score} > 0.20 \\
FMV \cdot (1 + \theta_{cons}) & \text{if } \Lambda_b > 3 \\
\hat{P}_{final} - \delta_{margin} & \text{otherwise}
\end{cases}

Variables:

  • \theta_{agg} = 0.10 = Aggressive buyer discount target (10% below FMV)
  • \theta_{cons} = 0.05 = Conservative buyer overbid tolerance
  • \delta_{margin} = €50 = Minimum margin below predicted final

Timing function:


t_{optimal} = t_{close} - \begin{cases}
5 \text{ min} & \text{if } \Lambda_b < 1 \\
30 \text{ sec} & \text{if } \Lambda_b > 5 \\
10 \text{ min} & \text{otherwise}
\end{cases}

Variable Reference Table

Symbol Variable Unit Data Source
P_i Comparable sale price bid_history.final
C Condition score [0,10] Image analysis + text parsing
T Manufacturing year Year Lot description extraction
W_{watch} Number of watchers Count Page metadata
\Lambda_b Bid velocity bids/min bid_history.timestamp diff
t_{close} Time until close Minutes lots.closing_time - NOW()
\sigma_{market} Market volatility [0,1] market_indices.price_change_30d
N_{docs} Provenance documents Count PDF link analysis
B_{velocity} Bid acceleration bph² Second derivative of \Lambda_b

Backend Implementation (Quarkus Pseudo-Code)

@Inject
MLModelService mlModel;

public Valuation calculateFairMarketValue(Lot lot) {
    List<Comparable> comparables = db.findComparables(lot, minSimilarity=0.75, limit=20);
    
    double weightedSum = 0.0;
    double weightSum = 0.0;
    
    for (Comparable comp : comparables) {
        double wc = Math.exp(-0.693 * Math.abs(lot.getConditionScore() - comp.getConditionScore()));
        double wt = Math.exp(-0.048 * Math.abs(lot.getYear() - comp.getYear()));
        double wp = 1 + 0.15 * (lot.hasProvenance() ? 1 : 0 - comp.hasProvenance() ? 1 : 0);
        
        double weight = wc * wt * wp;
        weightedSum += comp.getFinalPrice() * weight;
        weightSum += weight;
    }
    
    double fm v = weightSum > 0 ? weightedSum / weightSum : lot.getEstimatedMin();
    
    // Apply condition multiplier
    fm v *= Math.exp(0.15 * Math.sqrt(lot.getConditionScore()) - 0.40);
    
    return new Valuation(fm v, calculateConfidence(comparables.size()));
}

public BiddingStrategy getBiddingStrategy(String lotId) {
    var lot = db.getLot(lotId);
    var bidHistory = db.getBidHistory(lotId);
    var watchers = lot.getWatchCount();
    
    // Analyze patterns
    boolean isSnipeTarget = watchers > 50 && bidHistory.size() < 5;
    boolean hasReserve = lot.getReservePrice() > 0;
    double bidVelocity = calculateBidVelocity(bidHistory);
    
    // Strategy recommendation
    String strategy = isSnipeTarget ? "SNIPING_DETECTED" : 
                    (hasReserve && lot.getCurrentBid() < lot.getReservePrice() * 0.9) ? "RESERVE_AVOID" : 
                    bidVelocity > 5.0 ? "AGGRESSIVE_COMPETITION" : "STANDARD";
    
    return new BiddingStrategy(
        strategy,
        calculateRecommendedMax(lot),
        isSnipeTarget ? "FINAL_30_SECONDS" : "FINAL_10_MINUTES",
        getCompetitionLevel(watchers, bidHistory.size())
    );
}
-- Core bidding intelligence
ALTER TABLE lots ADD COLUMN starting_bid DECIMAL(12,2);
ALTER TABLE lots ADD COLUMN estimated_min DECIMAL(12,2);
ALTER TABLE lots ADD COLUMN estimated_max DECIMAL(12,2);
ALTER TABLE lots ADD COLUMN reserve_price DECIMAL(12,2);
ALTER TABLE lots ADD COLUMN watch_count INTEGER DEFAULT 0;
ALTER TABLE lots ADD COLUMN first_bid_time TEXT;
ALTER TABLE lots ADD COLUMN last_bid_time TEXT;
ALTER TABLE lots ADD COLUMN bid_velocity DECIMAL(5,2);

-- Bid history (critical)
CREATE TABLE bid_history (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    lot_id TEXT REFERENCES lots(lot_id),
    bid_amount DECIMAL(12,2) NOT NULL,
    bid_time TEXT NOT NULL,
    is_winning BOOLEAN DEFAULT FALSE,
    is_autobid BOOLEAN DEFAULT FALSE,
    bidder_id TEXT,
    created_at TEXT DEFAULT CURRENT_TIMESTAMP
);

-- Valuation support
ALTER TABLE lots ADD COLUMN condition_score DECIMAL(3,2);
ALTER TABLE lots ADD COLUMN year_manufactured INTEGER;
ALTER TABLE lots ADD COLUMN provenance TEXT;

CREATE TABLE comparable_sales (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    lot_id TEXT REFERENCES lots(lot_id),
    comparable_lot_id TEXT,
    similarity_score DECIMAL(3,2),
    price_difference_percent DECIMAL(5,2)
);

CREATE TABLE market_indices (
    category TEXT NOT NULL,
    manufacturer TEXT,
    avg_price DECIMAL(12,2),
    price_change_30d DECIMAL(5,2),
    PRIMARY KEY (category, manufacturer)
);

-- Alert system
CREATE TABLE price_alerts (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    lot_id TEXT REFERENCES lots(lot_id),
    alert_type TEXT CHECK(alert_type IN ('UNDervalued', 'ACCELERATING', 'RESERVE_IN_SIGHT')),
    trigger_price DECIMAL(12,2),
    is_triggered BOOLEAN DEFAULT FALSE
);