Initial commit: ASPEKTER — визуальный конструктор email-рассылок

- z51-pug-builder: Svelte 5 SPA, визуальный редактор Pug-писем
- email-gen: Node.js рендерер Pug→HTML через email-templates + Juice
- email-gen-api: HTTP сервер рендеринга (порт 8787)
- coin-scout: сервис подбора монет из фидов
- Docker Compose для dev/prod
- Nginx конфиг с SSL для app.aspekter.ru
This commit is contained in:
2026-04-13 11:36:39 +05:00
commit 718821fdd6
282 changed files with 64697 additions and 0 deletions

View File

@@ -0,0 +1,768 @@
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Coin Scout</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; background: #0f1117; color: #e1e4e8; }
a { color: #58a6ff; text-decoration: none; }
a:hover { text-decoration: underline; }
.header { background: #161b22; border-bottom: 1px solid #30363d; padding: 16px 24px; display: flex; align-items: center; gap: 16px; }
.header h1 { font-size: 20px; font-weight: 600; }
.header .stats { font-size: 13px; color: #8b949e; margin-left: auto; }
.toolbar { background: #161b22; border-bottom: 1px solid #30363d; padding: 12px 24px; display: flex; gap: 12px; align-items: center; flex-wrap: wrap; }
.toolbar label { font-size: 13px; color: #8b949e; }
.toolbar input, .toolbar select { background: #0d1117; border: 1px solid #30363d; color: #e1e4e8; padding: 6px 10px; border-radius: 6px; font-size: 13px; }
.toolbar input:focus, .toolbar select:focus { border-color: #58a6ff; outline: none; }
.toolbar input[type="number"] { width: 80px; }
.btn { background: #21262d; border: 1px solid #30363d; color: #e1e4e8; padding: 6px 14px; border-radius: 6px; cursor: pointer; font-size: 13px; }
.btn:hover { background: #30363d; }
.btn-primary { background: #238636; border-color: #238636; }
.btn-primary:hover { background: #2ea043; }
.btn-scan { background: #1f6feb; border-color: #1f6feb; }
.btn-scan:hover { background: #388bfd; }
.btn:disabled { opacity: 0.5; cursor: not-allowed; }
.tabs { display: flex; gap: 0; border-bottom: 1px solid #30363d; background: #161b22; padding: 0 24px; }
.tab { padding: 10px 16px; font-size: 14px; color: #8b949e; cursor: pointer; border-bottom: 2px solid transparent; }
.tab:hover { color: #e1e4e8; }
.tab.active { color: #e1e4e8; border-bottom-color: #f78166; }
.content { padding: 16px 24px; }
.coin-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(340px, 1fr)); gap: 12px; }
.coin-card { background: #161b22; border: 1px solid #30363d; border-radius: 8px; padding: 14px; display: flex; gap: 12px; transition: border-color 0.2s; }
.coin-card:hover { border-color: #58a6ff; }
.coin-card.top { border-color: #f0883e; }
.coin-img { width: 80px; height: 80px; border-radius: 6px; object-fit: cover; background: #0d1117; flex-shrink: 0; }
.coin-info { flex: 1; min-width: 0; }
.coin-name { font-size: 14px; font-weight: 500; margin-bottom: 4px; overflow: hidden; text-overflow: ellipsis; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; }
.coin-meta { font-size: 12px; color: #8b949e; display: flex; flex-wrap: wrap; gap: 6px; margin-top: 4px; }
.coin-meta .tag { background: #21262d; padding: 2px 6px; border-radius: 4px; }
.coin-meta .tag.silver { background: #1c3a5a; color: #79c0ff; }
.coin-meta .tag.gold { background: #3d2e00; color: #e3b341; }
.coin-meta .tag.grade-high { background: #1a4731; color: #56d364; }
.coin-meta .tag.grade-mid { background: #3d2e00; color: #e3b341; }
.coin-meta .tag.no-stock { background: #490202; color: #f85149; }
.coin-price { font-size: 16px; font-weight: 600; color: #56d364; margin-top: 6px; }
.coin-price .old { font-size: 12px; color: #8b949e; text-decoration: line-through; margin-left: 6px; font-weight: 400; }
.coin-score { font-size: 11px; color: #f0883e; font-weight: 600; margin-top: 4px; }
.coin-feed { font-size: 11px; color: #8b949e; }
.scan-bar { background: #1c2128; border: 1px solid #30363d; border-radius: 8px; padding: 14px; margin-bottom: 16px; display: flex; align-items: center; gap: 12px; }
.scan-bar .status { font-size: 13px; }
.scan-bar .dot { width: 8px; height: 8px; border-radius: 50%; display: inline-block; }
.dot.green { background: #56d364; }
.dot.yellow { background: #e3b341; animation: pulse 1s infinite; }
.dot.red { background: #f85149; }
@keyframes pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.4; } }
.settings-panel { max-width: 500px; }
.settings-panel .field { margin-bottom: 14px; }
.settings-panel .field label { display: block; font-size: 13px; color: #8b949e; margin-bottom: 4px; }
.settings-panel .field input, .settings-panel .field select { width: 100%; }
.empty { text-align: center; padding: 60px; color: #8b949e; }
.empty p { margin-top: 8px; }
.loading { text-align: center; padding: 40px; color: #8b949e; }
.modal-overlay { position: fixed; top: 0; left: 0; right: 0; bottom: 0; background: rgba(0,0,0,0.7); z-index: 1000; display: flex; align-items: center; justify-content: center; padding: 20px; }
.modal { background: #161b22; border: 1px solid #30363d; border-radius: 12px; max-width: 650px; width: 100%; max-height: 85vh; overflow-y: auto; padding: 24px; position: relative; }
.modal-close { position: absolute; top: 12px; right: 16px; background: none; border: none; color: #8b949e; font-size: 20px; cursor: pointer; }
.modal-close:hover { color: #e1e4e8; }
.modal h3 { color: #e1e4e8; margin-bottom: 12px; padding-right: 30px; }
.modal-score { font-size: 24px; font-weight: 700; color: #f0883e; margin-bottom: 16px; }
.analysis-section { margin-bottom: 4px; }
.analysis-section h4 { color: #58a6ff; font-size: 13px; margin: 12px 0 4px; }
.analysis-text { color: #c9d1d9; font-size: 13px; line-height: 1.6; white-space: pre-line; }
.analysis-tags { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 12px; }
.analysis-tags .tag { background: #21262d; padding: 3px 8px; border-radius: 4px; font-size: 11px; color: #8b949e; }
.coin-detail-btn { background: none; border: 1px solid #30363d; color: #58a6ff; font-size: 11px; padding: 2px 8px; border-radius: 4px; cursor: pointer; margin-top: 4px; }
.coin-detail-btn:hover { background: #21262d; }
.progress-panel { background: #1c2128; border: 1px solid #30363d; border-radius: 8px; padding: 16px; margin-bottom: 16px; display: none; }
.progress-panel.active { display: block; }
.progress-bar-wrap { background: #21262d; border-radius: 4px; height: 8px; margin: 8px 0; overflow: hidden; }
.progress-bar-fill { background: #1f6feb; height: 100%; border-radius: 4px; transition: width 0.3s; width: 0%; }
.progress-log { font-family: monospace; font-size: 12px; color: #8b949e; max-height: 200px; overflow-y: auto; margin-top: 8px; }
.progress-log div { padding: 2px 0; }
.progress-log .ok { color: #56d364; }
.progress-log .err { color: #f85149; }
.progress-log .info { color: #58a6ff; }
</style>
</head>
<body>
<div class="header">
<h1>Coin Scout</h1>
<div class="stats" id="stats"></div>
</div>
<div class="tabs">
<div class="tab active" data-tab="hot">Горячие</div>
<div class="tab" data-tab="new">Новые</div>
<div class="tab" data-tab="dashboard">Дашборд</div>
<div class="tab" data-tab="compare">Сравнение</div>
<div class="tab" data-tab="all">Все</div>
<div class="tab" data-tab="method">Методология</div>
<div class="tab" data-tab="settings">Настройки</div>
</div>
<div class="toolbar" id="toolbar">
<label>Макс. цена:
<input type="number" id="f-price" value="3000" step="100" min="0">
</label>
<label>Мин. грейд:
<select id="f-grade">
<option value="">Любой</option>
<option value="G">G</option>
<option value="VG">VG</option>
<option value="F">F</option>
<option value="VF" selected>VF</option>
<option value="XF">XF</option>
<option value="AU">AU</option>
<option value="UNC">UNC</option>
<option value="Proof">Proof</option>
</select>
</label>
<label>Материал:
<select id="f-material">
<option value="серебро,золото">Серебро/Золото</option>
<option value="любой">Любой</option>
<option value="серебро">Серебро</option>
<option value="золото">Золото</option>
</select>
</label>
<label>Магазин:
<select id="f-feed">
<option value="">Все</option>
<option value="AT">numizm.at</option>
<option value="KB">coinsbolhov.ru</option>
<option value="RU">numizmat.ru</option>
</select>
</label>
<label>
<input type="checkbox" id="f-stock" checked> В наличии
</label>
<label>
<input type="checkbox" id="f-dupes" checked> Без дублей
</label>
<button class="btn btn-primary" onclick="loadCoins()">Применить</button>
<button class="btn btn-scan" id="btn-scan" onclick="startScan()">Сканировать</button>
</div>
<div class="progress-panel" id="progress-panel">
<div style="font-size: 14px; font-weight: 500;" id="progress-title">Сканирование...</div>
<div class="progress-bar-wrap"><div class="progress-bar-fill" id="progress-bar"></div></div>
<div class="progress-log" id="progress-log"></div>
</div>
<div class="content" id="content">
<div class="loading">Загрузка...</div>
</div>
<script>
let currentTab = 'hot'
let settings = {}
const coinStore = new Map()
// Modal
document.addEventListener('click', (e) => {
const btn = e.target.closest('.coin-detail-btn')
if (btn) {
const coin = coinStore.get(btn.dataset.coinId)
if (coin) showAnalysisModal(coin)
return
}
if (e.target.classList.contains('modal-overlay')) {
e.target.remove()
}
})
document.addEventListener('keydown', (e) => {
if (e.key === 'Escape') {
const m = document.querySelector('.modal-overlay')
if (m) m.remove()
}
})
function showAnalysisModal(c) {
const overlay = document.createElement('div')
overlay.className = 'modal-overlay'
const tags = (c.reasons || []).map(r => `<span class="tag">${r}</span>`).join('')
overlay.innerHTML = `
<div class="modal">
<button class="modal-close" onclick="this.closest('.modal-overlay').remove()">&times;</button>
<h3>${c.name}</h3>
<div class="modal-score">Score: ${c.score}</div>
${c.image ? `<img src="${c.image}" style="width:120px;height:120px;object-fit:cover;border-radius:8px;margin-bottom:12px" onerror="this.style.display='none'">` : ''}
<div style="margin-bottom:8px">
<span style="color:#56d364;font-size:18px;font-weight:600">${c.price} ₽</span>
${c.old_price && c.old_price > c.price ? `<span style="color:#8b949e;text-decoration:line-through;margin-left:8px">${c.old_price} ₽</span>` : ''}
<span style="color:#8b949e;margin-left:12px;font-size:13px">${feedNames[c.feed] || c.feed}</span>
</div>
<div class="analysis-text">${c.analysis || ''}</div>
${tags ? `<div class="analysis-tags">${tags}</div>` : ''}
${c.emailCopy ? `
<div style="margin-top:20px;border-top:1px solid #30363d;padding-top:16px">
<div style="display:flex;align-items:center;gap:10px;margin-bottom:8px">
<h4 style="color:#f0883e;margin:0;font-size:14px">Текст для рассылки</h4>
<button class="btn" style="font-size:11px;padding:3px 10px" onclick="navigator.clipboard.writeText(this.closest('.modal').querySelector('.email-copy-text').innerText);this.textContent='Скопировано!';setTimeout(()=>this.textContent='Копировать',1500)">Копировать</button>
</div>
<div class="email-copy-text" style="background:#0d1117;border:1px solid #30363d;border-radius:8px;padding:14px;font-size:13px;color:#e1e4e8;line-height:1.7;white-space:pre-line">${c.emailCopy}</div>
</div>
` : ''}
<div style="margin-top:16px">
<a href="${c.url}" target="_blank" class="btn btn-primary" style="text-decoration:none;display:inline-block">Открыть на сайте</a>
</div>
</div>`
document.body.appendChild(overlay)
}
// Tabs
document.querySelectorAll('.tab').forEach(t => {
t.addEventListener('click', () => {
document.querySelectorAll('.tab').forEach(x => x.classList.remove('active'))
t.classList.add('active')
currentTab = t.dataset.tab
const noToolbar = ['settings', 'method', 'dashboard', 'compare']
document.getElementById('toolbar').style.display = noToolbar.includes(currentTab) ? 'none' : 'flex'
if (currentTab === 'settings') loadSettings()
else if (currentTab === 'method') loadMethodology()
else if (currentTab === 'dashboard') loadDashboard()
else if (currentTab === 'compare') loadCompare()
else if (currentTab === 'new') loadNew()
else if (currentTab === 'all') loadAll()
else loadCoins()
})
})
// Format helpers
const feedNames = { AT: 'numizm.at', KB: 'coinsbolhov.ru', RU: 'numizmat.ru' }
function materialClass(m) {
if (!m) return ''
const l = m.toLowerCase()
if (/золото|gold/.test(l)) return 'gold'
if (/серебро|silver|биллон/.test(l)) return 'silver'
return ''
}
function gradeClass(g) {
if (!g) return ''
const gs = ['G','AG','VG','F','VF','XF','EF','AU','UNC','BU','Proof']
const upper = g.toUpperCase()
for (let i = gs.length - 1; i >= 0; i--) {
if (upper.includes(gs[i])) return i >= 6 ? 'grade-high' : i >= 4 ? 'grade-mid' : ''
}
return ''
}
function coinCard(c, rank) {
const isTop = rank < 3
return `
<div class="coin-card ${isTop ? 'top' : ''}">
${c.image ? `<img class="coin-img" src="${c.image}" loading="lazy" onerror="this.style.display='none'">` : ''}
<div class="coin-info">
<div class="coin-name"><a href="${c.url}" target="_blank">${c.name}</a></div>
<div class="coin-meta">
${c.grade ? `<span class="tag ${gradeClass(c.grade)}">${c.grade}</span>` : '<span class="tag">? грейд</span>'}
${c.material ? `<span class="tag ${materialClass(c.material)}">${c.material}</span>` : ''}
${c.year_from ? `<span class="tag">${c.year_from}${c.year_to && c.year_to !== c.year_from ? '' + c.year_to : ''}</span>` : ''}
${c.in_stock === 0 ? '<span class="tag no-stock">Нет в наличии</span>' : ''}
</div>
<div class="coin-price">${c.price}${c.old_price && c.old_price > c.price ? `<span class="old">${c.old_price} ₽</span>` : ''}</div>
${c.score ? `<div class="coin-score">Score: ${c.score}</div>` : ''}
${c.summary ? `<div style="font-size:11px;color:#c9d1d9;margin-top:3px;line-height:1.4">${c.summary}</div>` : ''}
${c.analysis ? `<button class="coin-detail-btn" data-coin-id="${c.id}">Подробный анализ</button>` : ''}
<div class="coin-feed">${feedNames[c.feed] || c.feed}</div>
</div>
</div>`
}
async function loadCoins() {
const content = document.getElementById('content')
content.innerHTML = '<div class="loading">Загрузка...</div>'
const params = new URLSearchParams({
max_price: document.getElementById('f-price').value,
min_grade: document.getElementById('f-grade').value,
material: document.getElementById('f-material').value,
in_stock: document.getElementById('f-stock').checked ? '1' : '0',
hide_dupes: document.getElementById('f-dupes').checked ? '1' : '0',
feed: document.getElementById('f-feed').value,
})
try {
const res = await fetch('/api/coins?' + params)
const data = await res.json()
if (!data.coins.length) {
content.innerHTML = '<div class="empty"><h3>Ничего не найдено</h3><p>Попробуйте изменить фильтры или запустить сканирование</p></div>'
return
}
data.coins.forEach(c => coinStore.set(c.id, c))
content.innerHTML = `<div class="scan-bar"><span>Найдено: <b>${data.total}</b> монет</span></div>
<div class="coin-grid">${data.coins.map((c, i) => coinCard(c, i)).join('')}</div>`
} catch (e) {
content.innerHTML = `<div class="empty"><h3>Ошибка</h3><p>${e.message}</p></div>`
}
}
async function loadNew() {
const content = document.getElementById('content')
content.innerHTML = '<div class="loading">Загрузка...</div>'
try {
const res = await fetch('/api/coins/new?days=7')
const data = await res.json()
if (!data.coins.length) {
content.innerHTML = '<div class="empty"><h3>Новых поступлений нет</h3><p>Запустите сканирование или подождите</p></div>'
return
}
data.coins.forEach(c => coinStore.set(c.id, c))
content.innerHTML = `<div class="scan-bar"><span>Новых за 7 дней: <b>${data.total}</b></span></div>
<div class="coin-grid">${data.coins.map((c, i) => coinCard(c, i)).join('')}</div>`
} catch (e) {
content.innerHTML = `<div class="empty"><h3>Ошибка</h3><p>${e.message}</p></div>`
}
}
async function loadAll() {
const content = document.getElementById('content')
content.innerHTML = '<div class="loading">Загрузка...</div>'
try {
const res = await fetch('/api/coins/all?limit=200')
const data = await res.json()
data.coins.forEach(c => coinStore.set(c.id, c))
content.innerHTML = `<div class="scan-bar"><span>Всего: <b>${data.total}</b></span></div>
<div class="coin-grid">${data.coins.map((c, i) => coinCard(c, 999)).join('')}</div>`
} catch (e) {
content.innerHTML = `<div class="empty"><h3>Ошибка</h3><p>${e.message}</p></div>`
}
}
async function loadSettings() {
const content = document.getElementById('content')
try {
const res = await fetch('/api/settings')
settings = await res.json()
content.innerHTML = `
<div class="settings-panel">
<h3 style="margin-bottom: 16px;">Настройки Coin Scout</h3>
<div class="field">
<label>Максимальная цена по умолчанию (₽)</label>
<input type="number" id="s-price" value="${settings.max_price || 3000}" step="100">
</div>
<div class="field">
<label>Минимальный грейд</label>
<select id="s-grade">
${['G','VG','F','VF','XF','AU','UNC','Proof'].map(g =>
`<option value="${g}" ${g === settings.min_grade ? 'selected' : ''}>${g}</option>`
).join('')}
</select>
</div>
<div class="field">
<label>Предпочтительный материал</label>
<input type="text" id="s-material" value="${settings.preferred_material || 'серебро,золото'}">
</div>
<div class="field">
<label>Час автосканирования (0-23)</label>
<input type="number" id="s-hour" value="${settings.auto_scan_hour || 8}" min="0" max="23">
</div>
<div class="field">
<label><input type="checkbox" id="s-enabled" ${settings.scan_enabled === '1' ? 'checked' : ''}> Автосканирование включено</label>
</div>
<div class="field">
<label><input type="checkbox" id="s-dupes" ${settings.hide_dupes === '1' ? 'checked' : ''}> Скрывать дубликаты по умолчанию</label>
</div>
<button class="btn btn-primary" onclick="saveSettings()">Сохранить</button>
<span id="s-saved" style="color: #56d364; margin-left: 12px; display: none;">Сохранено!</span>
</div>`
} catch (e) {
content.innerHTML = `<div class="empty"><p>Ошибка: ${e.message}</p></div>`
}
}
async function saveSettings() {
await fetch('/api/settings', {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
max_price: document.getElementById('s-price').value,
min_grade: document.getElementById('s-grade').value,
preferred_material: document.getElementById('s-material').value,
auto_scan_hour: document.getElementById('s-hour').value,
scan_enabled: document.getElementById('s-enabled').checked ? '1' : '0',
hide_dupes: document.getElementById('s-dupes').checked ? '1' : '0',
}),
})
const el = document.getElementById('s-saved')
el.style.display = 'inline'
setTimeout(() => el.style.display = 'none', 2000)
}
async function startScan() {
const btn = document.getElementById('btn-scan')
btn.disabled = true
btn.textContent = 'Сканирование...'
const panel = document.getElementById('progress-panel')
const bar = document.getElementById('progress-bar')
const log = document.getElementById('progress-log')
const title = document.getElementById('progress-title')
panel.classList.add('active')
log.innerHTML = ''
bar.style.width = '0%'
function addLog(text, cls = '') {
const d = document.createElement('div')
d.className = cls
d.textContent = text
log.appendChild(d)
log.scrollTop = log.scrollHeight
}
// SSE
const es = new EventSource('/api/scan/progress')
es.onmessage = (e) => {
const data = JSON.parse(e.data)
title.textContent = data.message || 'Сканирование...'
if (data.stage === 'start') {
addLog(data.message, 'info')
} else if (data.stage === 'feed') {
addLog(data.message, 'info')
bar.style.width = ((data.feedIndex + 1) / (data.feedTotal * 2) * 100) + '%'
} else if (data.stage === 'feed_done') {
addLog(data.message, 'ok')
} else if (data.stage === 'feed_error') {
addLog(data.message, 'err')
} else if (data.stage === 'saving' || data.stage === 'details') {
if (data.total) bar.style.width = (50 + (data.current / data.total * 50)) + '%'
} else if (data.stage === 'done') {
addLog(data.message, 'ok')
bar.style.width = '100%'
es.close()
btn.disabled = false
btn.textContent = 'Сканировать'
setTimeout(() => { panel.classList.remove('active') }, 5000)
loadCoins()
loadStats()
} else if (data.stage === 'error') {
addLog(data.message, 'err')
es.close()
btn.disabled = false
btn.textContent = 'Сканировать'
}
}
es.onerror = () => {
es.close()
}
// Trigger scan
try {
await fetch('/api/scan', { method: 'POST' })
} catch (e) {
btn.disabled = false
btn.textContent = 'Сканировать'
addLog('Ошибка: ' + e.message, 'err')
}
}
async function loadStats() {
try {
const res = await fetch('/api/stats')
const data = await res.json()
document.getElementById('stats').textContent =
`${data.total} монет | ${data.withDetails} с деталями | ${data.feeds.map(f => `${feedNames[f.feed] || f.feed}: ${f.cnt}`).join(', ')}`
} catch (e) {}
}
// ─── Dashboard ───
async function loadDashboard() {
const content = document.getElementById('content')
content.innerHTML = '<div class="loading">Загрузка дашборда...</div>'
try {
const res = await fetch('/api/dashboard')
const d = await res.json()
const feedNames = { AT: 'numizm.at', KB: 'coinsbolhov.ru', RU: 'numizmat.ru' }
content.innerHTML = `
<div style="max-width:900px">
<h2 style="color:#e1e4e8;margin-bottom:16px">Дашборд</h2>
<div style="display:grid;grid-template-columns:repeat(3,1fr);gap:12px;margin-bottom:20px">
<div style="background:#161b22;border:1px solid #30363d;border-radius:8px;padding:16px;text-align:center">
<div style="font-size:28px;font-weight:700;color:#56d364">${d.total.toLocaleString()}</div>
<div style="color:#8b949e;font-size:13px">Всего монет</div>
</div>
<div style="background:#161b22;border:1px solid #30363d;border-radius:8px;padding:16px;text-align:center">
<div style="font-size:28px;font-weight:700;color:#58a6ff">${d.newThisWeek}</div>
<div style="color:#8b949e;font-size:13px">Новых за 7 дней</div>
</div>
<div style="background:#161b22;border:1px solid #30363d;border-radius:8px;padding:16px;text-align:center">
<div style="font-size:28px;font-weight:700;color:#f0883e">${d.priceDrops.length}</div>
<div style="color:#8b949e;font-size:13px">Снижения цен</div>
</div>
</div>
<div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:12px;margin-bottom:20px">
${d.feeds.map(f => `
<div style="background:#161b22;border:1px solid #30363d;border-radius:8px;padding:12px">
<div style="color:#e1e4e8;font-weight:600">${feedNames[f.feed] || f.feed}</div>
<div style="color:#8b949e;font-size:13px">${f.cnt.toLocaleString()} монет · средняя ${f.avg_price}₽</div>
</div>
`).join('')}
</div>
${d.priceDrops.length ? `
<h3 style="color:#f0883e;margin:20px 0 10px">Снижения цен</h3>
<table style="width:100%;border-collapse:collapse;font-size:13px">
<tr style="border-bottom:1px solid #30363d;color:#8b949e"><th style="text-align:left;padding:6px">Монета</th><th>Было</th><th>Стало</th><th>Δ</th><th>Магазин</th></tr>
${d.priceDrops.map(c => `
<tr style="border-bottom:1px solid #21262d">
<td style="padding:6px"><a href="${c.url}" target="_blank">${c.name.substring(0,50)}</a></td>
<td style="text-align:center;color:#8b949e">${c.prev_price}₽</td>
<td style="text-align:center;color:#56d364">${c.price}₽</td>
<td style="text-align:center;color:#f0883e">${c.drop_pct}%</td>
<td style="text-align:center;color:#8b949e">${feedNames[c.feed] || c.feed}</td>
</tr>
`).join('')}
</table>
` : ''}
${d.priceRises.length ? `
<h3 style="color:#f85149;margin:20px 0 10px">Повышения цен</h3>
<table style="width:100%;border-collapse:collapse;font-size:13px">
<tr style="border-bottom:1px solid #30363d;color:#8b949e"><th style="text-align:left;padding:6px">Монета</th><th>Было</th><th>Стало</th><th>Δ</th><th>Магазин</th></tr>
${d.priceRises.slice(0,10).map(c => `
<tr style="border-bottom:1px solid #21262d">
<td style="padding:6px"><a href="${c.url}" target="_blank">${c.name.substring(0,50)}</a></td>
<td style="text-align:center;color:#8b949e">${c.prev_price}₽</td>
<td style="text-align:center;color:#f85149">${c.price}₽</td>
<td style="text-align:center;color:#f85149">+${c.rise_pct}%</td>
<td style="text-align:center;color:#8b949e">${feedNames[c.feed] || c.feed}</td>
</tr>
`).join('')}
</table>
` : ''}
${d.disappeared.length ? `
<h3 style="color:#8b949e;margin:20px 0 10px">Исчезли за 7 дней (проданы?)</h3>
<div style="font-size:13px;color:#8b949e">
${d.disappeared.map(c => `<div style="padding:3px 0">${c.name.substring(0,60)} · ${c.price}₽ · ${feedNames[c.feed] || c.feed}</div>`).join('')}
</div>
` : ''}
<div style="display:grid;grid-template-columns:1fr 1fr;gap:16px;margin-top:20px">
<div>
<h3 style="color:#58a6ff;margin-bottom:8px">По материалу</h3>
<table style="width:100%;font-size:12px;border-collapse:collapse">
${d.materials.map(m => `<tr style="border-bottom:1px solid #21262d"><td style="padding:3px">${m.material}</td><td style="text-align:right">${m.cnt}</td><td style="text-align:right;color:#8b949e">~${m.avg_price}₽</td></tr>`).join('')}
</table>
</div>
<div>
<h3 style="color:#58a6ff;margin-bottom:8px">По грейду</h3>
<table style="width:100%;font-size:12px;border-collapse:collapse">
${d.grades.map(g => `<tr style="border-bottom:1px solid #21262d"><td style="padding:3px">${g.grade}</td><td style="text-align:right">${g.cnt}</td><td style="text-align:right;color:#8b949e">~${g.avg_price}₽</td></tr>`).join('')}
</table>
</div>
</div>
</div>`
} catch (e) {
content.innerHTML = `<div class="empty"><p>Ошибка: ${e.message}</p></div>`
}
}
// ─── Cross-store comparison ───
async function loadCompare() {
const content = document.getElementById('content')
content.innerHTML = '<div class="loading">Сравнение магазинов...</div>'
try {
const res = await fetch('/api/compare')
const d = await res.json()
const feedNames = { AT: 'numizm.at', KB: 'coinsbolhov.ru', RU: 'numizmat.ru' }
if (!d.comparisons.length) {
content.innerHTML = '<div class="empty"><h3>Совпадений не найдено</h3><p>Нужно больше сканов чтобы найти одинаковые монеты в разных магазинах</p></div>'
return
}
content.innerHTML = `
<div style="max-width:900px">
<h2 style="color:#e1e4e8;margin-bottom:16px">Сравнение магазинов</h2>
<p style="color:#8b949e;margin-bottom:16px;font-size:13px">Одинаковые монеты в разных магазинах, отсортированные по разнице в цене.</p>
<table style="width:100%;border-collapse:collapse;font-size:13px">
<tr style="border-bottom:1px solid #30363d;color:#8b949e">
<th style="text-align:left;padding:8px">Монета</th>
<th>Магазин 1</th><th>Цена 1</th>
<th>Магазин 2</th><th>Цена 2</th>
<th>Разница</th>
</tr>
${d.comparisons.map(c => {
const cheaper = c.price1 <= c.price2 ? 1 : 2
return `<tr style="border-bottom:1px solid #21262d">
<td style="padding:8px;max-width:250px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap">${c.name.substring(0,50)}</td>
<td style="text-align:center"><a href="${c.url1}" target="_blank">${feedNames[c.feed1] || c.feed1}</a></td>
<td style="text-align:center;${cheaper===1?'color:#56d364;font-weight:600':''}">${c.price1}₽</td>
<td style="text-align:center"><a href="${c.url2}" target="_blank">${feedNames[c.feed2] || c.feed2}</a></td>
<td style="text-align:center;${cheaper===2?'color:#56d364;font-weight:600':''}">${c.price2}₽</td>
<td style="text-align:center;color:#f0883e">${c.diff_pct}%</td>
</tr>`
}).join('')}
</table>
</div>`
} catch (e) {
content.innerHTML = `<div class="empty"><p>Ошибка: ${e.message}</p></div>`
}
}
function loadMethodology() {
document.getElementById('content').innerHTML = `
<div style="max-width:800px;line-height:1.7;font-size:14px">
<div style="display:flex;align-items:center;gap:16px;margin-bottom:16px">
<h2 style="margin:0;color:#e1e4e8">Методология оценки инвестиционной привлекательности монет</h2>
<a href="/methodology.html?print" target="_blank" class="btn btn-primary" style="text-decoration:none;white-space:nowrap">Скачать PDF</a>
</div>
<p style="color:#8b949e;margin-bottom:20px">Скоринг основан на анализе <b>40+ профессиональных источников</b> по нумизматике: PCGS, NGC, Forbes.ru, numizmatik.ru, coinweek.com, zolotoy-zapas.ru, numisdon.com, raritetus.ru и др. Цена серебра: ~200₽/грамм (ЦБ РФ, апрель 2026).</p>
<h3 style="color:#f0883e;margin:24px 0 12px">1. Сохранность / Грейд (до 30 очков)</h3>
<p style="color:#8b949e;margin-bottom:8px">Каждый шаг грейда может увеличить цену в 2-50 раз. Переход AU→UNC — самый большой скачок.</p>
<table style="width:100%;border-collapse:collapse;margin-bottom:12px">
<tr style="border-bottom:1px solid #30363d"><td style="padding:4px 8px;color:#8b949e">Proof</td><td style="padding:4px 8px;color:#56d364">+28</td><td style="padding:4px 8px;color:#8b949e">Зеркальная поверхность, высшее качество</td></tr>
<tr style="border-bottom:1px solid #30363d"><td style="padding:4px 8px;color:#8b949e">UNC</td><td style="padding:4px 8px;color:#56d364">+25</td><td style="padding:4px 8px;color:#8b949e">Не была в обращении</td></tr>
<tr style="border-bottom:1px solid #30363d"><td style="padding:4px 8px;color:#8b949e">AU</td><td style="padding:4px 8px;color:#56d364">+20</td><td style="padding:4px 8px;color:#8b949e">Почти без следов обращения</td></tr>
<tr style="border-bottom:1px solid #30363d"><td style="padding:4px 8px;color:#8b949e">XF</td><td style="padding:4px 8px;color:#56d364">+15</td><td style="padding:4px 8px;color:#8b949e">Лёгкий износ на выступающих частях</td></tr>
<tr><td style="padding:4px 8px;color:#8b949e">VF</td><td style="padding:4px 8px;color:#56d364">+8</td><td style="padding:4px 8px;color:#8b949e">Умеренный износ, все детали читаемы</td></tr>
</table>
<p style="color:#8b949e">Бонус: VF+ для монет до 1800 г. (+8), XF для XIX века (+5) — исключительная сохранность для возраста.</p>
<h3 style="color:#f0883e;margin:24px 0 12px">2. Материал и стоимость металла (до 25 очков)</h3>
<p style="color:#8b949e;margin-bottom:8px">Драгоценный металл создаёт «пол» стоимости — монета не может стоить дешевле металла.</p>
<table style="width:100%;border-collapse:collapse;margin-bottom:12px">
<tr style="border-bottom:1px solid #30363d"><td style="padding:4px 8px;color:#8b949e">Золото</td><td style="padding:4px 8px;color:#56d364">+22</td><td style="padding:4px 8px;color:#8b949e">Надёжный актив, всегда ликвиден</td></tr>
<tr style="border-bottom:1px solid #30363d"><td style="padding:4px 8px;color:#8b949e">Серебро</td><td style="padding:4px 8px;color:#56d364">+14</td><td style="padding:4px 8px;color:#8b949e">+ бонус если цена близка к стоимости металла</td></tr>
<tr style="border-bottom:1px solid #30363d"><td style="padding:4px 8px;color:#8b949e">Серебро &lt; melt</td><td style="padding:4px 8px;color:#56d364">+10 доп.</td><td style="padding:4px 8px;color:#8b949e">Дешевле стоимости серебра — безрисковая покупка</td></tr>
<tr><td style="padding:4px 8px;color:#8b949e">Биллон</td><td style="padding:4px 8px;color:#56d364">+6</td><td style="padding:4px 8px;color:#8b949e">Сплав с серебром</td></tr>
</table>
<h3 style="color:#f0883e;margin:24px 0 12px">3. Возраст и историческая значимость (до 20 очков)</h3>
<p style="color:#8b949e;margin-bottom:8px">Античные монеты показывают 8-15% годового роста (numisdon.com). Возраст + сохранность = экспоненциальный рост ценности.</p>
<table style="width:100%;border-collapse:collapse;margin-bottom:12px">
<tr style="border-bottom:1px solid #30363d"><td style="padding:4px 8px;color:#8b949e">До н.э.</td><td style="padding:4px 8px;color:#56d364">+20</td><td style="padding:4px 8px;color:#8b949e">Античная монета</td></tr>
<tr style="border-bottom:1px solid #30363d"><td style="padding:4px 8px;color:#8b949e">500+ лет</td><td style="padding:4px 8px;color:#56d364">+18</td><td style="padding:4px 8px;color:#8b949e">Средневековье</td></tr>
<tr style="border-bottom:1px solid #30363d"><td style="padding:4px 8px;color:#8b949e">300+ лет</td><td style="padding:4px 8px;color:#56d364">+14</td><td style="padding:4px 8px;color:#8b949e">Раннее Новое время</td></tr>
<tr style="border-bottom:1px solid #30363d"><td style="padding:4px 8px;color:#8b949e">200+ лет</td><td style="padding:4px 8px;color:#56d364">+10</td><td style="padding:4px 8px;color:#8b949e"></td></tr>
<tr><td style="padding:4px 8px;color:#8b949e">100+ лет</td><td style="padding:4px 8px;color:#56d364">+6</td><td style="padding:4px 8px;color:#8b949e"></td></tr>
</table>
<h3 style="color:#f0883e;margin:24px 0 12px">4. Российские премиум-периоды (до 15 очков)</h3>
<p style="color:#8b949e;margin-bottom:8px">Царские монеты растут 10-15% в год (Forbes.ru). Особые периоды и правители:</p>
<table style="width:100%;border-collapse:collapse;margin-bottom:12px">
<tr style="border-bottom:1px solid #30363d"><td style="padding:4px 8px;color:#8b949e">СССР 1947, 1958</td><td style="padding:4px 8px;color:#56d364">+15</td><td style="padding:4px 8px;color:#8b949e">Не выпущены в обращение, раритет</td></tr>
<tr style="border-bottom:1px solid #30363d"><td style="padding:4px 8px;color:#8b949e">Пробные монеты</td><td style="padding:4px 8px;color:#56d364">+12</td><td style="padding:4px 8px;color:#8b949e">Коллекционная элита</td></tr>
<tr style="border-bottom:1px solid #30363d"><td style="padding:4px 8px;color:#8b949e">Смутное время (1610-1612)</td><td style="padding:4px 8px;color:#56d364">+10</td><td style="padding:4px 8px;color:#8b949e">Редчайший период русской нумизматики</td></tr>
<tr style="border-bottom:1px solid #30363d"><td style="padding:4px 8px;color:#8b949e">Перепутки</td><td style="padding:4px 8px;color:#56d364">+10</td><td style="padding:4px 8px;color:#8b949e">Монета на чужой заготовке</td></tr>
<tr style="border-bottom:1px solid #30363d"><td style="padding:4px 8px;color:#8b949e">Раннее СССР серебро (1921-31)</td><td style="padding:4px 8px;color:#56d364">+7</td><td style="padding:4px 8px;color:#8b949e">Малые тиражи серебра</td></tr>
<tr style="border-bottom:1px solid #30363d"><td style="padding:4px 8px;color:#8b949e">Николай II (1894-1917)</td><td style="padding:4px 8px;color:#56d364">+6</td><td style="padding:4px 8px;color:#8b949e">Культовый период, всегда в спросе</td></tr>
<tr style="border-bottom:1px solid #30363d"><td style="padding:4px 8px;color:#8b949e">Пётр I (1682-1725)</td><td style="padding:4px 8px;color:#56d364">+6</td><td style="padding:4px 8px;color:#8b949e">Реформатор, высокий спрос</td></tr>
<tr style="border-bottom:1px solid #30363d"><td style="padding:4px 8px;color:#8b949e">Медный бунт (1654-1656)</td><td style="padding:4px 8px;color:#56d364">+6</td><td style="padding:4px 8px;color:#8b949e">Историческое событие</td></tr>
<tr style="border-bottom:1px solid #30363d"><td style="padding:4px 8px;color:#8b949e">Сибирские монеты</td><td style="padding:4px 8px;color:#56d364">+6</td><td style="padding:4px 8px;color:#8b949e">Медь с примесью серебра и золота</td></tr>
<tr style="border-bottom:1px solid #30363d"><td style="padding:4px 8px;color:#8b949e">Георгий Победоносец</td><td style="padding:4px 8px;color:#56d364">+6</td><td style="padding:4px 8px;color:#8b949e">Максимальная ликвидность</td></tr>
<tr style="border-bottom:1px solid #30363d"><td style="padding:4px 8px;color:#8b949e">Александр II, III</td><td style="padding:4px 8px;color:#56d364">+5</td><td style="padding:4px 8px;color:#8b949e">Растущий спрос / короткое правление</td></tr>
<tr style="border-bottom:1px solid #30363d"><td style="padding:4px 8px;color:#8b949e">Павел I (1796-1801)</td><td style="padding:4px 8px;color:#56d364">+5</td><td style="padding:4px 8px;color:#8b949e">Короткое правление — мало монет</td></tr>
<tr style="border-bottom:1px solid #30363d"><td style="padding:4px 8px;color:#8b949e">1 рубль 1924 серебро</td><td style="padding:4px 8px;color:#56d364">+5</td><td style="padding:4px 8px;color:#8b949e">Недооценён относительно редкости</td></tr>
<tr style="border-bottom:1px solid #30363d"><td style="padding:4px 8px;color:#8b949e">Серебряный рубль Империи</td><td style="padding:4px 8px;color:#56d364">+5</td><td style="padding:4px 8px;color:#8b949e">Топ коллекционного спроса</td></tr>
<tr style="border-bottom:1px solid #30363d"><td style="padding:4px 8px;color:#8b949e">Екатерина II, Анна, Елизавета</td><td style="padding:4px 8px;color:#56d364">+4</td><td style="padding:4px 8px;color:#8b949e">Популярные периоды</td></tr>
<tr><td style="padding:4px 8px;color:#8b949e">Русская Финляндия серебро</td><td style="padding:4px 8px;color:#56d364">+4</td><td style="padding:4px 8px;color:#8b949e">Узкая серия</td></tr>
</table>
<h3 style="color:#f0883e;margin:24px 0 12px">5. Мировые монеты (до 10 очков)</h3>
<table style="width:100%;border-collapse:collapse;margin-bottom:12px">
<tr style="border-bottom:1px solid #30363d"><td style="padding:4px 8px;color:#8b949e">Древняя Греция</td><td style="padding:4px 8px;color:#56d364">+6</td><td style="padding:4px 8px;color:#8b949e">~15% годового роста</td></tr>
<tr style="border-bottom:1px solid #30363d"><td style="padding:4px 8px;color:#8b949e">Византия</td><td style="padding:4px 8px;color:#56d364">+5 (+4 золото)</td><td style="padding:4px 8px;color:#8b949e">Доступная античная империя</td></tr>
<tr style="border-bottom:1px solid #30363d"><td style="padding:4px 8px;color:#8b949e">Римская империя</td><td style="padding:4px 8px;color:#56d364">+5</td><td style="padding:4px 8px;color:#8b949e">Растущий глобальный рынок</td></tr>
<tr style="border-bottom:1px solid #30363d"><td style="padding:4px 8px;color:#8b949e">Боспорское царство</td><td style="padding:4px 8px;color:#56d364">+5</td><td style="padding:4px 8px;color:#8b949e">Крымская античность</td></tr>
<tr style="border-bottom:1px solid #30363d"><td style="padding:4px 8px;color:#8b949e">Сефевиды, Талеры, Панды</td><td style="padding:4px 8px;color:#56d364">+5</td><td style="padding:4px 8px;color:#8b949e">Недооценённые сегменты</td></tr>
<tr style="border-bottom:1px solid #30363d"><td style="padding:4px 8px;color:#8b949e">Османская империя</td><td style="padding:4px 8px;color:#56d364">+4</td><td style="padding:4px 8px;color:#8b949e">Недооценённый сегмент</td></tr>
<tr style="border-bottom:1px solid #30363d"><td style="padding:4px 8px;color:#8b949e">Соверены, Лунные серии</td><td style="padding:4px 8px;color:#56d364">+4</td><td style="padding:4px 8px;color:#8b949e">Стабильный глобальный спрос</td></tr>
<tr><td style="padding:4px 8px;color:#8b949e">Японские монеты 100+ лет</td><td style="padding:4px 8px;color:#56d364">+4</td><td style="padding:4px 8px;color:#8b949e">Бум азиатской нумизматики</td></tr>
</table>
<h3 style="color:#f0883e;margin:24px 0 12px">6. Ошибки чеканки и разновидности (до 15 очков)</h3>
<table style="width:100%;border-collapse:collapse;margin-bottom:12px">
<tr style="border-bottom:1px solid #30363d"><td style="padding:4px 8px;color:#8b949e">Мул / двойной аверс</td><td style="padding:4px 8px;color:#56d364">+15</td><td style="padding:4px 8px;color:#8b949e">Крайне редкий брак</td></tr>
<tr style="border-bottom:1px solid #30363d"><td style="padding:4px 8px;color:#8b949e">Брак чеканки (смещение, раскол, перечекан...)</td><td style="padding:4px 8px;color:#56d364">+12</td><td style="padding:4px 8px;color:#8b949e">Коллекционная редкость</td></tr>
<tr style="border-bottom:1px solid #30363d"><td style="padding:4px 8px;color:#8b949e">Ефимок / надчеканка</td><td style="padding:4px 8px;color:#56d364">+10</td><td style="padding:4px 8px;color:#8b949e">Нумизматическая элита</td></tr>
<tr style="border-bottom:1px solid #30363d"><td style="padding:4px 8px;color:#8b949e">Серия ЧЯП (10₽ биметалл)</td><td style="padding:4px 8px;color:#56d364">+10</td><td style="padding:4px 8px;color:#8b949e">Малотиражная, высокий спрос</td></tr>
<tr style="border-bottom:1px solid #30363d"><td style="padding:4px 8px;color:#8b949e">Без знака монетного двора</td><td style="padding:4px 8px;color:#56d364">+8</td><td style="padding:4px 8px;color:#8b949e">Редкий вариант</td></tr>
<tr><td style="padding:4px 8px;color:#8b949e">Широкий кант 1997/1998 ММД</td><td style="padding:4px 8px;color:#56d364">+8</td><td style="padding:4px 8px;color:#8b949e">Редкий производственный вариант</td></tr>
</table>
<h3 style="color:#f0883e;margin:24px 0 12px">7. Ценовая эффективность (до 12 очков)</h3>
<p style="color:#8b949e;margin-bottom:8px">Главное правило: покупай самую редкую монету в лучшем состоянии за доступную цену.</p>
<table style="width:100%;border-collapse:collapse;margin-bottom:12px">
<tr style="border-bottom:1px solid #30363d"><td style="padding:4px 8px;color:#8b949e">Скидка 30%+</td><td style="padding:4px 8px;color:#56d364">+8</td><td style="padding:4px 8px;color:#8b949e">Сильное снижение цены</td></tr>
<tr style="border-bottom:1px solid #30363d"><td style="padding:4px 8px;color:#8b949e">AU+ дешевле 500₽</td><td style="padding:4px 8px;color:#56d364">+6</td><td style="padding:4px 8px;color:#8b949e">Ниже рыночной стоимости</td></tr>
<tr style="border-bottom:1px solid #30363d"><td style="padding:4px 8px;color:#8b949e">Скидка 15%+</td><td style="padding:4px 8px;color:#56d364">+5</td><td style="padding:4px 8px;color:#8b949e"></td></tr>
<tr><td style="padding:4px 8px;color:#8b949e">UNC до 1000₽</td><td style="padding:4px 8px;color:#56d364">+4</td><td style="padding:4px 8px;color:#8b949e">Выгодная цена для грейда</td></tr>
</table>
<h3 style="color:#f85149;margin:24px 0 12px">8. Штрафы (негативные факторы)</h3>
<table style="width:100%;border-collapse:collapse;margin-bottom:12px">
<tr style="border-bottom:1px solid #30363d"><td style="padding:4px 8px;color:#8b949e">Копия / жетон / сувенир</td><td style="padding:4px 8px;color:#f85149">-20</td><td style="padding:4px 8px;color:#8b949e">Не оригинальная монета</td></tr>
<tr style="border-bottom:1px solid #30363d"><td style="padding:4px 8px;color:#8b949e">Массовые юбилейные СССР</td><td style="padding:4px 8px;color:#f85149">-12</td><td style="padding:4px 8px;color:#8b949e">Не Proof, не драгмет — нет вторичного рынка</td></tr>
<tr style="border-bottom:1px solid #30363d"><td style="padding:4px 8px;color:#8b949e">Чищеная монета</td><td style="padding:4px 8px;color:#f85149">-10</td><td style="padding:4px 8px;color:#8b949e">Потеря 50-90% коллекционной ценности (PCGS)</td></tr>
<tr style="border-bottom:1px solid #30363d"><td style="padding:4px 8px;color:#8b949e">Современные памятные ЦБ РФ</td><td style="padding:4px 8px;color:#f85149">-8</td><td style="padding:4px 8px;color:#8b949e">Слабый вторичный рынок</td></tr>
<tr style="border-bottom:1px solid #30363d"><td style="padding:4px 8px;color:#8b949e">Медно-никель после 1950</td><td style="padding:4px 8px;color:#f85149">-4</td><td style="padding:4px 8px;color:#8b949e">Массовый чекан, нет Proof</td></tr>
<tr><td style="padding:4px 8px;color:#8b949e">Проволочные монеты (чешуя)</td><td style="padding:4px 8px;color:#f85149">-2</td><td style="padding:4px 8px;color:#8b949e">Высокий риск подделки</td></tr>
</table>
<h3 style="color:#58a6ff;margin:24px 0 12px">Источники (40+)</h3>
<div style="color:#8b949e;font-size:12px;columns:2;column-gap:24px">
<p><a href="https://www.pcgs.com/prices/us" target="_blank">PCGS Price Guide</a></p>
<p><a href="https://www.ngccoin.com/price-guide/" target="_blank">NGC Price Guide</a></p>
<p><a href="https://www.forbes.ru/finansy-i-investicii/356677" target="_blank">Forbes.ru — Ценная мелочь</a></p>
<p><a href="https://www.numizmatik.ru/biblio/top-redkikh-monet-2025-2026" target="_blank">numizmatik.ru — Редкие монеты 2025-2026</a></p>
<p><a href="https://www.zolotoy-zapas.ru/why-gold-coins/useful/" target="_blank">Золотой Запас — гайды</a></p>
<p><a href="https://rarecoins.ru/stati/kriterii-ocenki-stoimosti-monet-v-numizmatike.html" target="_blank">Аукционный дом Редкие Монеты</a></p>
<p><a href="https://www.numisdon.com/ancient-coins-good-investment-2025/" target="_blank">NumisDon — Ancient coins 2025</a></p>
<p><a href="https://thebullionbank.com/blog/undervalued-silver-coins-2025" target="_blank">BullionBank — Undervalued Silver</a></p>
<p><a href="https://thecoinsexplorer.com/best-rare-coins-investment-2025/" target="_blank">CoinsExplorer — Best Rare Coins</a></p>
<p><a href="https://coinweek.com/patina-on-ancient-bronze-coins/" target="_blank">CoinWeek — Patina Guide</a></p>
<p><a href="https://www.raritetus.ru/stoimost-monet/" target="_blank">Raritetus — каталог цен</a></p>
<p><a href="https://www.cbr.ru/hd_base/metall/metall_base_new/" target="_blank">ЦБ РФ — цена серебра</a></p>
<p><a href="https://www.pcgs.com/news/how-to-determine-the-value-of-a-mint-error-coin" target="_blank">PCGS — Error Coin Guide</a></p>
<p><a href="https://www.numizmatik.ru/biblio/brak-na-monetakh" target="_blank">numizmatik.ru — Брак монет</a></p>
<p><a href="https://www.russian-money.ru/articles/1rub-1997-shirokii-kant" target="_blank">russian-money.ru — Широкий кант</a></p>
<p><a href="https://coins.tsbnk.ru/" target="_blank">ТрансСтройБанк — каталог</a></p>
<p><a href="https://www.usagold.com/gold-silver-ratio-guide/" target="_blank">USAGOLD — Gold/Silver Ratio</a></p>
<p><a href="https://www.rarecoins101.com/coin-investments.html" target="_blank">RareCoins101 — Returns</a></p>
<p><a href="https://lermontovgallery.ru/spravochnik-antikvariata/" target="_blank">Лермонтов — царские монеты</a></p>
<p><a href="https://www.numisdon.com/byzantine-coins-value/" target="_blank">NumisDon — Byzantine Value</a></p>
<p><a href="https://stonexbullion.com/en/blog/rise-of-asian-bullion-coins/" target="_blank">StoneX — Asian Bullion Coins</a></p>
<p><a href="https://www.greysheet.com/news/story/five-coin-collecting-investment-mistakes-to-avoid" target="_blank">Greysheet — 5 Mistakes to Avoid</a></p>
<p><a href="https://www.marketresearchfuture.com/reports/coin-collecting-market-22623" target="_blank">Market Research — 8% CAGR</a></p>
<p><a href="https://www.coingraderai.com/blog/natural-vs-artificial-coin-toning-grading" target="_blank">CoinGraderAI — Toning</a></p>
<p><a href="https://deigoldandsilvercoins.com/top-underappreciated-world-coins-with-hidden-long-term-value/" target="_blank">DEI — Underappreciated World Coins</a></p>
</div>
<h3 style="color:#58a6ff;margin:24px 0 12px">Статистика рынка</h3>
<ul style="color:#8b949e">
<li>Средний рост рынка монет: <b>8% в год</b> (CAGR, прогноз до 2035)</li>
<li>PCGS Key Dates Index: <b>4.8% годовых</b> за 25 лет (2000-2025)</li>
<li>Топовые монеты: <b>12-14% годовых</b> (PCGS3000 Index с 1971)</li>
<li>Царские монеты: <b>10-15% годовых</b> (Forbes.ru)</li>
<li>Античные монеты: <b>8-15% годовых</b> (numisdon.com)</li>
<li>Рекомендуемый горизонт инвестиций: <b>7-10 лет минимум</b></li>
<li>Дилерская наценка: 10-30% — монета должна вырасти на столько же для безубытка</li>
</ul>
<h3 style="color:#58a6ff;margin:24px 0 12px">Фильтрация</h3>
<p style="color:#8b949e">Из фидов автоматически исключаются: открытки, альбомы, капсулы, листы, подставки, футляры, лупы, пинцеты, рамки, планшеты, холдеры, книги.</p>
<p style="color:#8b949e;margin-top:24px;font-size:12px"><i>Disclaimer: скоринг является аналитическим инструментом, не финансовой рекомендацией. Всегда проверяйте монету лично перед покупкой.</i></p>
</div>`
}
// Init
loadStats()
loadCoins()
</script>
</body>
</html>

View File

@@ -0,0 +1,225 @@
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<title>Coin Scout — Методология</title>
<style>
@media print {
body { font-size: 11px; }
h1 { font-size: 20px; }
h2 { font-size: 15px; }
h3 { font-size: 13px; }
.no-break { page-break-inside: avoid; }
a { color: #333; }
}
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif; max-width: 750px; margin: 40px auto; padding: 0 20px; color: #1a1a1a; line-height: 1.6; }
h1 { text-align: center; margin-bottom: 4px; }
.subtitle { text-align: center; color: #666; margin-bottom: 30px; font-size: 13px; }
h2 { color: #c45500; border-bottom: 2px solid #c45500; padding-bottom: 4px; margin-top: 28px; }
h3 { color: #333; margin-top: 18px; }
table { width: 100%; border-collapse: collapse; margin: 8px 0 16px; font-size: 12px; }
th { background: #f5f5f5; text-align: left; padding: 6px 8px; border: 1px solid #ddd; font-weight: 600; }
td { padding: 5px 8px; border: 1px solid #ddd; }
.plus { color: #1a7f37; font-weight: 600; }
.minus { color: #cf222e; font-weight: 600; }
.note { color: #666; font-size: 12px; font-style: italic; }
.sources { font-size: 11px; columns: 2; column-gap: 20px; }
.sources a { color: #0969da; }
ul { margin: 4px 0; padding-left: 20px; }
li { margin-bottom: 3px; }
.stat-box { background: #f8f9fa; border: 1px solid #e1e4e8; border-radius: 6px; padding: 12px 16px; margin: 12px 0; }
.stat-box b { color: #c45500; }
</style>
</head>
<body>
<h1>Coin Scout — Методология оценки</h1>
<p class="subtitle">Инвестиционный скоринг монет на основе 40+ профессиональных источников<br>
PCGS · NGC · Forbes.ru · numizmatik.ru · coinweek.com · zolotoy-zapas.ru · numisdon.com · raritetus.ru<br>
Версия: апрель 2026 · Цена серебра: ~200₽/грамм (ЦБ РФ)</p>
<h2>1. Сохранность / Грейд (до 30 очков)</h2>
<p>Каждый шаг грейда может увеличить цену монеты в 250 раз. Переход AU→UNC — самый значительный скачок стоимости.</p>
<div class="no-break">
<table>
<tr><th>Грейд</th><th>Баллы</th><th>Описание</th></tr>
<tr><td>Proof</td><td class="plus">+28</td><td>Зеркальная поверхность, высшее качество чеканки</td></tr>
<tr><td>UNC (MS)</td><td class="plus">+25</td><td>Не была в обращении, без следов износа</td></tr>
<tr><td>AU</td><td class="plus">+20</td><td>Почти без следов обращения, минимальный износ</td></tr>
<tr><td>XF (EF)</td><td class="plus">+15</td><td>Лёгкий износ на выступающих частях рельефа</td></tr>
<tr><td>VF</td><td class="plus">+8</td><td>Умеренный износ, все основные детали читаемы</td></tr>
</table>
</div>
<p class="note">Бонусы: VF+ для монет до 1800 г. (+8) — исключительная сохранность для возраста. XF для монет XIX века (+5).</p>
<h2>2. Материал и стоимость металла (до 25 очков)</h2>
<p>Драгоценный металл создаёт «пол» стоимости — монета не может стоить дешевле содержащегося в ней металла.</p>
<div class="no-break">
<table>
<tr><th>Материал</th><th>Баллы</th><th>Описание</th></tr>
<tr><td>Золото</td><td class="plus">+22</td><td>Надёжный актив, всегда ликвиден</td></tr>
<tr><td>Серебро</td><td class="plus">+14</td><td>Базовый бонус за драгоценный металл</td></tr>
<tr><td>Серебро: цена &lt; melt value</td><td class="plus">+10 доп.</td><td>Монета дешевле стоимости содержащегося серебра — безрисковая покупка</td></tr>
<tr><td>Серебро: цена ≈ 70-100% melt</td><td class="plus">+5 доп.</td><td>Цена близка к стоимости металла</td></tr>
<tr><td>Биллон</td><td class="plus">+6</td><td>Сплав с содержанием серебра</td></tr>
</table>
</div>
<p class="note">Расчёт melt value: вес монеты (г) × 200₽ (цена серебра за грамм по ЦБ РФ, апрель 2026).</p>
<h2>3. Возраст и историческая значимость (до 20 очков)</h2>
<p>Античные монеты показывают 815% годового роста (numisdon.com). Комбинация возраста и хорошей сохранности создаёт экспоненциальный рост ценности.</p>
<div class="no-break">
<table>
<tr><th>Возраст</th><th>Баллы</th><th>Пример</th></tr>
<tr><td>До нашей эры</td><td class="plus">+20</td><td>Греческие, римские, боспорские</td></tr>
<tr><td>500+ лет</td><td class="plus">+18</td><td>Средневековье, ранний Ренессанс</td></tr>
<tr><td>300+ лет</td><td class="plus">+14</td><td>XVIIXVIII век</td></tr>
<tr><td>200+ лет</td><td class="plus">+10</td><td>Начало XIX века</td></tr>
<tr><td>100+ лет</td><td class="plus">+6</td><td>Начало XX века</td></tr>
<tr><td>50+ лет</td><td class="plus">+2</td><td>Середина XX века</td></tr>
</table>
</div>
<h2>4. Российские премиум-периоды (до 15 очков)</h2>
<p>Царские монеты растут на 1015% в год (Forbes.ru). Отдельные периоды и типы монет обладают повышенным инвестиционным потенциалом.</p>
<div class="no-break">
<table>
<tr><th>Период / Тип</th><th>Баллы</th><th>Почему</th></tr>
<tr><td>СССР 1947, 1958 годов</td><td class="plus">+15</td><td>Не выпущены в обращение, крайне редки</td></tr>
<tr><td>Пробные монеты</td><td class="plus">+12</td><td>Коллекционная элита, единичные экземпляры</td></tr>
<tr><td>Смутное время (16101612)</td><td class="plus">+10</td><td>Редчайший период русской нумизматики</td></tr>
<tr><td>Перепутки (чужие заготовки)</td><td class="plus">+10</td><td>Монета отчеканена на заготовке другого номинала</td></tr>
<tr><td>Раннее СССР серебро (19211931)</td><td class="plus">+7</td><td>Малые тиражи, серебро в обращении</td></tr>
<tr><td>Николай II (18941917)</td><td class="plus">+6</td><td>Культовый период, всегда востребован</td></tr>
<tr><td>Пётр I (16821725)</td><td class="plus">+6</td><td>Реформатор, высокий коллекционный спрос</td></tr>
<tr><td>Медный бунт (16541656)</td><td class="plus">+6</td><td>Историческое событие, Алексей Михайлович</td></tr>
<tr><td>Сибирские монеты (Сузун)</td><td class="plus">+6</td><td>Медь с примесью серебра и золота</td></tr>
<tr><td>Георгий Победоносец</td><td class="plus">+6</td><td>Максимальная ликвидность среди инвестиционных</td></tr>
<tr><td>Александр II (18551881)</td><td class="plus">+5</td><td>Растущий спрос коллекционеров</td></tr>
<tr><td>Александр III (18811894)</td><td class="plus">+5</td><td>Короткое правление — мало монет</td></tr>
<tr><td>Павел I (17961801)</td><td class="plus">+5</td><td>5 лет правления — ограниченная чеканка</td></tr>
<tr><td>1 рубль 1924, серебро</td><td class="plus">+5</td><td>Недооценён относительно редкости</td></tr>
<tr><td>Серебряный рубль Империи</td><td class="plus">+5</td><td>Топ коллекционного спроса</td></tr>
<tr><td>Полтина серебро</td><td class="plus">+4</td><td>Ликвидный крупный номинал</td></tr>
<tr><td>Екатерина II (17621796)</td><td class="plus">+4</td><td>Популярный период, много коллекционеров</td></tr>
<tr><td>Анна Иоанновна (17301740)</td><td class="plus">+4</td><td>Высокий инвестиционный потенциал</td></tr>
<tr><td>Елизавета Петровна (17411762)</td><td class="plus">+4</td><td>Редкие тиражи, дорогие монеты</td></tr>
<tr><td>Русская Финляндия, серебро</td><td class="plus">+4</td><td>Узкая серия, отдельный коллекционный спрос</td></tr>
</table>
</div>
<h2>5. Мировые монеты (до 10 очков)</h2>
<div class="no-break">
<table>
<tr><th>Регион / Тип</th><th>Баллы</th><th>Описание</th></tr>
<tr><td>Древняя Греция</td><td class="plus">+6</td><td>~15% годового роста, Афины, Коринф, Сиракузы</td></tr>
<tr><td>Византия</td><td class="plus">+5 (+4 золото)</td><td>Доступная античная империя, солиды</td></tr>
<tr><td>Римская империя</td><td class="plus">+5</td><td>Растущий глобальный рынок, денарии</td></tr>
<tr><td>Боспорское царство</td><td class="plus">+5</td><td>Крымская античность, Пантикапей</td></tr>
<tr><td>Сефевиды (Персия)</td><td class="plus">+5</td><td>Редкий исламский регион</td></tr>
<tr><td>Талеры</td><td class="plus">+5</td><td>Крупное серебро, всегда ликвидны</td></tr>
<tr><td>Китайские Панды</td><td class="plus">+5</td><td>Растущий азиатский рынок</td></tr>
<tr><td>Османская империя</td><td class="plus">+4</td><td>Недооценённый сегмент</td></tr>
<tr><td>Британские соверены</td><td class="plus">+4</td><td>Стабильный глобальный спрос</td></tr>
<tr><td>Лунные серии</td><td class="plus">+4</td><td>Австралия, Великобритания — коллекционный рост</td></tr>
<tr><td>Японские монеты 100+ лет</td><td class="plus">+4</td><td>Бум азиатской нумизматики, CAGR 7%</td></tr>
</table>
</div>
<h2>6. Ошибки чеканки и разновидности (до 15 очков)</h2>
<p>Монеты с ошибками чеканки образуют отдельную и высоко ценимую категорию коллекционирования (PCGS).</p>
<div class="no-break">
<table>
<tr><th>Тип</th><th>Баллы</th><th>Описание</th></tr>
<tr><td>Мул / двойной аверс / без реверса</td><td class="plus">+15</td><td>Крайне редкий брак, до 712 тыс. ₽</td></tr>
<tr><td>Брак чеканки</td><td class="plus">+12</td><td>Смещение, раскол, перечекан, двойной удар, выкус, залипуха, непрочекан, гурт на канте, двойной кант</td></tr>
<tr><td>Ефимок / надчеканка</td><td class="plus">+10</td><td>Нумизматическая элита, всегда высокий спрос</td></tr>
<tr><td>Серия ЧЯП (10₽ биметалл)</td><td class="plus">+10</td><td>Чечня, ЯНАО, Пермский край — малотиражные</td></tr>
<tr><td>Без знака монетного двора</td><td class="plus">+8</td><td>Редкий вариант, ценится выше обычного</td></tr>
<tr><td>Широкий кант 1997/1998 ММД</td><td class="plus">+8</td><td>Редкий производственный вариант</td></tr>
<tr><td>Ключевая дата серии</td><td class="plus">+6</td><td>Давление коллекционеров на завершение серии</td></tr>
</table>
</div>
<h2>7. Ценовая эффективность (до 12 очков)</h2>
<p><b>Главное правило:</b> покупай самую редкую монету в лучшем состоянии за доступную цену.</p>
<div class="no-break">
<table>
<tr><th>Фактор</th><th>Баллы</th><th>Описание</th></tr>
<tr><td>Скидка ≥30%</td><td class="plus">+8</td><td>Сильное снижение цены от старой</td></tr>
<tr><td>AU+ дешевле 500₽</td><td class="plus">+6</td><td>Ниже рыночной стоимости для грейда</td></tr>
<tr><td>Скидка ≥15%</td><td class="plus">+5</td><td>Заметное снижение цены</td></tr>
<tr><td>UNC до 1000₽</td><td class="plus">+4</td><td>Выгодная цена для не бывшей в обращении монеты</td></tr>
<tr><td>Общий бонус за дешевизну</td><td class="plus">до +7</td><td>Чем дешевле при VF+ — тем больше бонус</td></tr>
</table>
</div>
<h2>8. Штрафы — негативные факторы</h2>
<div class="no-break">
<table>
<tr><th>Фактор</th><th>Баллы</th><th>Почему</th></tr>
<tr><td>Копия / жетон / сувенир / новодел</td><td class="minus">20</td><td>Не оригинальная монета, нет инвестиционной ценности</td></tr>
<tr><td>Массовые юбилейные СССР (не Proof, не драгмет)</td><td class="minus">12</td><td>Нет вторичного рынка, не растут в цене</td></tr>
<tr><td>Чищеная монета</td><td class="minus">10</td><td>Потеря 5090% коллекционной ценности (данные PCGS)</td></tr>
<tr><td>Современные памятные ЦБ РФ (не драгмет)</td><td class="minus">8</td><td>Слабый вторичный рынок</td></tr>
<tr><td>Медно-никель после 1950 (массовый чекан)</td><td class="minus">4</td><td>Не Proof — нет коллекционной ценности</td></tr>
<tr><td>Проволочные монеты (чешуя)</td><td class="minus">2</td><td>Высокий риск подделки</td></tr>
</table>
</div>
<h2>Статистика рынка</h2>
<div class="stat-box">
<ul>
<li>Глобальный рынок монет: <b>CAGR 8%</b> до 2035 года (Market Research Future)</li>
<li>PCGS Key Dates Index: <b>4.8% годовых</b> за 25 лет (20002025)</li>
<li>PCGS3000 Index: <b>1214% годовых</b> с 1971 года (Penn State study)</li>
<li>Царские монеты: <b>1015% годовых</b> (Forbes.ru)</li>
<li>Античные монеты: <b>815% годовых</b> (numisdon.com, 20212025)</li>
<li>Азиатский рынок (Китай, Япония): <b>CAGR 67%</b></li>
<li>Рекомендуемый горизонт: <b>710 лет минимум</b> (ANA рекомендует 10+)</li>
<li>Дилерская наценка: <b>1030%</b> — учитывать при расчёте точки безубыточности</li>
</ul>
</div>
<h2>Источники (40+)</h2>
<div class="sources">
<p><a href="https://www.pcgs.com/prices/us">PCGS Price Guide</a></p>
<p><a href="https://www.ngccoin.com/price-guide/">NGC Price Guide</a></p>
<p><a href="https://www.forbes.ru/finansy-i-investicii/356677">Forbes.ru — Ценная мелочь</a></p>
<p><a href="https://www.numizmatik.ru/biblio/top-redkikh-monet-2025-2026">numizmatik.ru — Редкие монеты 20252026</a></p>
<p><a href="https://www.zolotoy-zapas.ru/why-gold-coins/useful/">Золотой Запас — гайды по монетам</a></p>
<p><a href="https://rarecoins.ru/stati/kriterii-ocenki-stoimosti-monet-v-numizmatike.html">Аукционный дом «Редкие Монеты»</a></p>
<p><a href="https://www.numisdon.com/ancient-coins-good-investment-2025/">NumisDon — Ancient Coins 2025</a></p>
<p><a href="https://thebullionbank.com/blog/undervalued-silver-coins-2025">BullionBank — Undervalued Silver</a></p>
<p><a href="https://thecoinsexplorer.com/best-rare-coins-investment-2025/">CoinsExplorer — Best Rare Coins 2025</a></p>
<p><a href="https://coinweek.com/patina-on-ancient-bronze-coins/">CoinWeek — Patina Guide</a></p>
<p><a href="https://www.raritetus.ru/stoimost-monet/">Raritetus — каталог цен</a></p>
<p><a href="https://www.cbr.ru/hd_base/metall/metall_base_new/">ЦБ РФ — цена драгметаллов</a></p>
<p><a href="https://www.pcgs.com/news/how-to-determine-the-value-of-a-mint-error-coin">PCGS — Error Coin Guide</a></p>
<p><a href="https://www.numizmatik.ru/biblio/brak-na-monetakh">numizmatik.ru — Брак на монетах</a></p>
<p><a href="https://www.russian-money.ru/articles/1rub-1997-shirokii-kant">russian-money.ru — Широкий кант</a></p>
<p><a href="https://coins.tsbnk.ru/">ТрансСтройБанк — каталог монет</a></p>
<p><a href="https://www.usagold.com/gold-silver-ratio-guide/">USAGOLD — Gold/Silver Ratio</a></p>
<p><a href="https://www.rarecoins101.com/coin-investments.html">RareCoins101 — Investment Returns</a></p>
<p><a href="https://lermontovgallery.ru/spravochnik-antikvariata/">Лермонтов — царские монеты</a></p>
<p><a href="https://www.numisdon.com/byzantine-coins-value/">NumisDon — Byzantine Coins</a></p>
<p><a href="https://stonexbullion.com/en/blog/rise-of-asian-bullion-coins/">StoneX — Asian Bullion Coins</a></p>
<p><a href="https://www.greysheet.com/news/story/five-coin-collecting-investment-mistakes-to-avoid">Greysheet — 5 Mistakes to Avoid</a></p>
<p><a href="https://www.marketresearchfuture.com/reports/coin-collecting-market-22623">Market Research Future — CAGR 8%</a></p>
<p><a href="https://www.coingraderai.com/blog/natural-vs-artificial-coin-toning-grading">CoinGraderAI — Toning Guide</a></p>
<p><a href="https://deigoldandsilvercoins.com/top-underappreciated-world-coins-with-hidden-long-term-value/">DEI — Underappreciated World Coins</a></p>
<p><a href="https://www.pcgs.com/news/toning-does-it-help/">PCGS — Toning Impact on Value</a></p>
<p><a href="https://www.monetnik.ru/obuchenie/numizmatika/monety-sibirskie/">Monetnik — Сибирские монеты</a></p>
<p><a href="https://www.blanchardgold.com/wp-content/uploads/2017/02/blanchard_lombra_report_2016.pdf">Blanchard — Lombra Report (Penn State)</a></p>
</div>
<p class="note" style="margin-top:30px;text-align:center">Coin Scout · Версия апрель 2026 · Скоринг является аналитическим инструментом, не финансовой рекомендацией.<br>Всегда проверяйте монету лично перед покупкой.</p>
<script>
// Auto-print for PDF generation
if (location.search.includes('print')) {
window.onload = () => window.print()
}
</script>
</body>
</html>