304 lines
9.6 KiB
Markdown
304 lines
9.6 KiB
Markdown
# 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)
|
|
|
|
```java
|
|
@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())
|
|
);
|
|
}
|
|
```
|
|
```sqlite
|
|
-- 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
|
|
);
|
|
|
|
``` |