Files
TurboTrades/MARKET_PRICES.md
2026-01-10 04:57:43 +00:00

551 lines
11 KiB
Markdown

# Market Price System Documentation
## Overview
The market price system stores **34,641 Steam market prices** (29,602 CS2 + 5,039 Rust) in MongoDB for instant price lookups when loading inventory or updating items.
---
## Database Structure
### Collection: `marketprices`
```javascript
{
name: "AK-47 | Redline (Field-Tested)",
game: "cs2",
appId: 730,
marketHashName: "AK-47 | Redline (Field-Tested)",
price: 12.50,
priceType: "safe",
image: "https://...",
borderColor: "#eb4b4b",
nameId: 123456,
lastUpdated: ISODate("2024-01-10T12:00:00Z")
}
```
### Indexes
- `{ marketHashName: 1 }` - Unique, for exact lookups
- `{ game: 1, name: 1 }` - For game-specific name searches
- `{ game: 1, marketHashName: 1 }` - For game-specific hash lookups
- `{ game: 1, price: -1 }` - For sorting by price
- `{ lastUpdated: -1 }` - For finding outdated data
---
## Current Status
```
📊 Market Prices Database:
CS2: 29,602 items
Rust: 5,039 items
Total: 34,641 items
Top CS2 Price: $2,103.21 (StatTrak™ Bayonet | Case Hardened)
Top Rust Price: $2,019.59 (Punishment Mask)
```
---
## Usage
### Import the Service
```javascript
import marketPriceService from "./services/marketPrice.js";
```
### Get Single Price
```javascript
// By exact market hash name
const price = await marketPriceService.getPrice(
"AK-47 | Redline (Field-Tested)",
"cs2"
);
console.log(price); // 12.50
```
### Get Multiple Prices (Batch)
```javascript
const names = [
"AK-47 | Redline (Field-Tested)",
"AWP | Asiimov (Field-Tested)",
"M4A4 | Howl (Factory New)"
];
const priceMap = await marketPriceService.getPrices(names, "cs2");
console.log(priceMap);
// {
// "AK-47 | Redline (Field-Tested)": 12.50,
// "AWP | Asiimov (Field-Tested)": 95.00,
// "M4A4 | Howl (Factory New)": 4500.00
// }
```
### Get Full Item Data
```javascript
const item = await marketPriceService.getItem(
"AK-47 | Redline (Field-Tested)",
"cs2"
);
console.log(item);
// {
// name: "AK-47 | Redline (Field-Tested)",
// game: "cs2",
// price: 12.50,
// image: "https://...",
// borderColor: "#eb4b4b",
// ...
// }
```
### Enrich Inventory with Prices
```javascript
// When loading Steam inventory
const inventoryItems = [
{ market_hash_name: "AK-47 | Redline (Field-Tested)", ... },
{ market_hash_name: "AWP | Asiimov (Field-Tested)", ... }
];
const enriched = await marketPriceService.enrichInventory(
inventoryItems,
"cs2"
);
console.log(enriched[0]);
// {
// market_hash_name: "AK-47 | Redline (Field-Tested)",
// marketPrice: 12.50,
// hasPriceData: true,
// ...
// }
```
### Search Items
```javascript
// Search by name (partial match)
const results = await marketPriceService.search("AK-47", "cs2", 10);
console.log(results.length); // Up to 10 results
```
### Get Suggested Price (with Markup)
```javascript
// Get price with 10% markup
const suggested = await marketPriceService.getSuggestedPrice(
"AK-47 | Redline (Field-Tested)",
"cs2",
1.10 // 10% markup
);
console.log(suggested); // 13.75
```
### Get Price Statistics
```javascript
const stats = await marketPriceService.getStats("cs2");
console.log(stats);
// {
// count: 29602,
// avgPrice: 15.50,
// minPrice: 0.03,
// maxPrice: 2103.21,
// totalValue: 458831.00
// }
```
### Get Top Priced Items
```javascript
const topItems = await marketPriceService.getTopPriced("cs2", 10);
topItems.forEach((item, i) => {
console.log(`${i + 1}. ${item.name}: $${item.price}`);
});
```
### Get Items by Price Range
```javascript
// Get items between $10 and $50
const items = await marketPriceService.getByPriceRange(10, 50, "cs2", 100);
console.log(`Found ${items.length} items`);
```
---
## Commands
### Import/Update All Prices
```bash
# Download latest prices from Steam API and import to database
node import-market-prices.js
# This will:
# 1. Fetch 29,602 CS2 items
# 2. Fetch 5,039 Rust items
# 3. Upsert into MongoDB (updates existing, inserts new)
# 4. Takes ~30-60 seconds
```
### Check Status
```bash
# Check how many items are in database
node -e "import('./services/marketPrice.js').then(async s => {
const cs2 = await s.default.getCount('cs2');
const rust = await s.default.getCount('rust');
console.log('CS2:', cs2);
console.log('Rust:', rust);
process.exit(0);
})"
```
### Test Price Lookup
```bash
# Test looking up a specific item
node -e "import('./services/marketPrice.js').then(async s => {
const price = await s.default.getPrice('AK-47 | Redline (Field-Tested)', 'cs2');
console.log('Price:', price);
process.exit(0);
})"
```
---
## Integration Examples
### Example 1: Sell Page Inventory Loading
```javascript
// routes/inventory.js
import marketPriceService from "../services/marketPrice.js";
fastify.get("/inventory/:game", async (request, reply) => {
const { game } = request.params;
// Fetch from Steam API
const steamInventory = await fetchSteamInventory(
request.user.steamId,
game
);
// Enrich with market prices
const enrichedInventory = await marketPriceService.enrichInventory(
steamInventory,
game
);
return reply.send({
success: true,
items: enrichedInventory
});
});
```
### Example 2: Admin Panel Price Override
```javascript
// routes/admin.js
fastify.put("/items/:id/price", async (request, reply) => {
const { id } = request.params;
const { price, marketHashName } = request.body;
// Get suggested price from market data
const marketPrice = await marketPriceService.getPrice(
marketHashName,
"cs2"
);
// Update item
await Item.findByIdAndUpdate(id, {
price: price,
marketPrice: marketPrice,
priceOverride: true
});
return reply.send({ success: true });
});
```
### Example 3: Auto-Price New Listings
```javascript
// When user lists item for sale
fastify.post("/sell", async (request, reply) => {
const { assetId, game } = request.body;
// Get item from inventory
const inventoryItem = await getInventoryItem(assetId);
// Get suggested price (with 5% markup)
const suggestedPrice = await marketPriceService.getSuggestedPrice(
inventoryItem.market_hash_name,
game,
1.05 // 5% markup
);
// Create listing
const item = await Item.create({
name: inventoryItem.market_hash_name,
price: suggestedPrice,
game: game,
seller: request.user._id
});
return reply.send({
success: true,
item,
suggestedPrice
});
});
```
---
## Price Types
The system uses the best available price from Steam API:
1. **safe** (preferred) - Most reliable price
2. **median** - Middle value price
3. **mean** - Average price
4. **avg** - Alternative average
5. **latest** - Most recent transaction price
---
## Maintenance
### Update Schedule
**Recommended**: Run weekly or bi-weekly
```bash
# Add to cron or Task Scheduler
# Every Sunday at 2 AM
0 2 * * 0 cd /path/to/TurboTrades && node import-market-prices.js
```
### Check if Data is Outdated
```javascript
const isOutdated = await marketPriceService.isOutdated("cs2", 168); // 7 days
if (isOutdated) {
console.log("⚠️ Price data is older than 7 days - consider updating");
}
```
### Get Last Update Time
```javascript
const lastUpdate = await marketPriceService.getLastUpdate("cs2");
console.log(`Last updated: ${lastUpdate.toLocaleString()}`);
```
---
## Performance
### Query Performance
-**Single lookup**: < 1ms (indexed)
-**Batch lookup** (100 items): < 10ms (indexed)
-**Search** (regex): < 50ms
-**Stats aggregation**: < 100ms
### Storage
- **CS2**: ~15MB (29,602 items)
- **Rust**: ~2.5MB (5,039 items)
- **Total**: ~17.5MB
---
## Error Handling
All service methods return `null` or empty arrays on error:
```javascript
const price = await marketPriceService.getPrice("Invalid Item", "cs2");
console.log(price); // null
const items = await marketPriceService.search("xyz", "cs2");
console.log(items); // []
```
Always check for null/empty:
```javascript
const price = await marketPriceService.getPrice(itemName, game);
if (price === null) {
console.log("Price not found - using fallback");
price = 0.00;
}
```
---
## API Comparison
### Old Method (Live API Call)
```javascript
// Slow: 500-2000ms per request
// Rate limited: 200 calls/minute
// Requires API key on every request
const price = await steamAPIsClient.getPrice(itemName);
```
### New Method (Database Lookup)
```javascript
// Fast: < 1ms per request
// No rate limits
// No API key needed
const price = await marketPriceService.getPrice(itemName, game);
```
**Benefits**:
- ✅ 500x faster
- ✅ No rate limits
- ✅ Works offline
- ✅ Batch lookups
- ✅ Full-text search
- ✅ Price statistics
---
## Troubleshooting
### No prices found
```bash
# Check if data exists
node -e "import('./services/marketPrice.js').then(async s => {
const count = await s.default.getCount();
console.log('Total items:', count);
if (count === 0) {
console.log('Run: node import-market-prices.js');
}
process.exit(0);
})"
```
### Prices outdated
```bash
# Re-import latest prices
node import-market-prices.js
```
### Item not found
The item name must match **exactly** as it appears in Steam market:
```javascript
// ❌ Wrong
"AK-47 Redline FT"
// ✅ Correct
"AK-47 | Redline (Field-Tested)"
```
Use the `search()` function to find correct names:
```javascript
const results = await marketPriceService.search("AK-47 Redline", "cs2");
console.log(results.map(r => r.name));
```
---
## Best Practices
### 1. Always Specify Game
```javascript
// ✅ Good - faster query
const price = await marketPriceService.getPrice(name, "cs2");
// ❌ Slower - searches all games
const price = await marketPriceService.getPrice(name);
```
### 2. Use Batch Lookups for Multiple Items
```javascript
// ✅ Good - single query
const prices = await marketPriceService.getPrices(names, game);
// ❌ Bad - multiple queries
for (const name of names) {
const price = await marketPriceService.getPrice(name, game);
}
```
### 3. Cache Frequently Accessed Prices
```javascript
// In-memory cache for hot items
const priceCache = new Map();
async function getCachedPrice(name, game) {
const key = `${game}:${name}`;
if (priceCache.has(key)) {
return priceCache.get(key);
}
const price = await marketPriceService.getPrice(name, game);
priceCache.set(key, price);
return price;
}
```
### 4. Handle Missing Prices Gracefully
```javascript
const price = await marketPriceService.getPrice(name, game) || 0.00;
```
---
## Future Enhancements
### Planned Features
- [ ] Price history tracking
- [ ] Price change alerts
- [ ] Trend analysis
- [ ] Auto-update scheduler
- [ ] Price comparison charts
- [ ] Volume data
- [ ] Market depth
---
## Support
**Files**:
- Model: `models/MarketPrice.js`
- Service: `services/marketPrice.js`
- Import Script: `import-market-prices.js`
**Related Docs**:
- `ADMIN_PANEL.md` - Admin price management
- `PRICING_SYSTEM.md` - Legacy pricing system
- `API_ENDPOINTS.md` - API documentation
---
**Last Updated**: January 2025
**Version**: 1.0.0
**Status**: ✅ Production Ready (34,641 items)