11 KiB
11 KiB
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
{
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
import marketPriceService from "./services/marketPrice.js";
Get Single Price
// 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)
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
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
// 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
// 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)
// 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
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
const topItems = await marketPriceService.getTopPriced("cs2", 10);
topItems.forEach((item, i) => {
console.log(`${i + 1}. ${item.name}: $${item.price}`);
});
Get Items by Price Range
// 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
# 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
# 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
# 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
// 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
// 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
// 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:
- safe (preferred) - Most reliable price
- median - Middle value price
- mean - Average price
- avg - Alternative average
- latest - Most recent transaction price
Maintenance
Update Schedule
Recommended: Run weekly or bi-weekly
# 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
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
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:
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:
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)
// 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)
// 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
# 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
# Re-import latest prices
node import-market-prices.js
Item not found
The item name must match exactly as it appears in Steam market:
// ❌ Wrong
"AK-47 Redline FT"
// ✅ Correct
"AK-47 | Redline (Field-Tested)"
Use the search() function to find correct names:
const results = await marketPriceService.search("AK-47 Redline", "cs2");
console.log(results.map(r => r.name));
Best Practices
1. Always Specify Game
// ✅ 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
// ✅ 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
// 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
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 managementPRICING_SYSTEM.md- Legacy pricing systemAPI_ENDPOINTS.md- API documentation
Last Updated: January 2025 Version: 1.0.0 Status: ✅ Production Ready (34,641 items)