# 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)