"use strict";
const topStrategyGrid = document.getElementById("topStrategyGrid");
const rankingPreview = document.getElementById("rankingPreview");
const rankingDescription = document.getElementById("rankingDescription");
function escapeHtml(value) {
return String(value ?? "")
.replaceAll("&", "&")
.replaceAll("<", "<")
.replaceAll(">", ">")
.replaceAll('"', """)
.replaceAll("'", "'");
}
function formatNumber(value, digits = 0) {
const number = Number(value);
if (!Number.isFinite(number)) {
return "-";
}
return number.toLocaleString("ko-KR", {
minimumFractionDigits: digits,
maximumFractionDigits: digits,
});
}
function strategyName(strategy) {
return strategy.display_name
|| strategy.strategy_display_name_ko
|| strategy.strategy_name
|| strategy.public_strategy_code
|| strategy.strategy_code
|| "전략1 BTC 라이브";
}
function publicStrategiesOnly(strategies) {
return strategies.filter((strategy) => {
const code = strategy.actual_strategy_code || strategy.public_strategy_code || strategy.strategy_code;
return code === "live_strategy1_btc"
&& strategy.publish_status === "published"
&& strategy.visibility === "public"
&& strategy.is_public_simulation_visible === true
&& strategy.is_temp !== true
&& strategy.is_admin_only !== true;
});
}
function renderPreview(strategies) {
if (!rankingPreview) {
return;
}
if (!strategies.length) {
rankingPreview.innerHTML = '
공개 전략 정보가 없습니다.
';
return;
}
rankingPreview.innerHTML = strategies.map((strategy) => `
${escapeHtml(strategy.rank || 1)}
${escapeHtml(strategyName(strategy))}
${escapeHtml(strategy.market || "KRW-BTC")}
${formatNumber(strategy.recent_win_rate_pct, 1)}%
`).join("");
}
function renderCards(strategies) {
if (!topStrategyGrid) {
return;
}
if (!strategies.length) {
topStrategyGrid.innerHTML = `
공개 전략 정보가 없습니다.
라이브 퍼블리싱된 전략이 준비되면 이 영역에 표시됩니다.
`;
return;
}
topStrategyGrid.innerHTML = strategies.map((strategy) => {
const pnl = Number(strategy.recent_realized_pnl_krw) || 0;
const pnlClass = pnl > 0 ? "positive" : pnl < 0 ? "negative" : "neutral";
const code = strategy.public_strategy_code || strategy.strategy_code || "live_strategy1_btc";
return `
${escapeHtml(strategyName(strategy))}
${escapeHtml(strategy.strategy_description_ko || "전략1 BTC 라이브 공개 시뮬레이션 결과입니다.")}
- 최근 승률
- ${formatNumber(strategy.recent_win_rate_pct, 1)}%
- 최근 실현손익
- ${pnl > 0 ? "+" : ""}${formatNumber(pnl)} KRW
- 집계 거래
- ${formatNumber(strategy.recent_trade_count)}건
- 공개 태그
- 라이브 퍼블리싱
시뮬레이션 성과 보기
`;
}).join("");
}
async function loadTopStrategies() {
try {
const response = await fetch("/api/public/top-strategies?market_type=crypto&market=KRW-BTC", {
headers: {Accept: "application/json"},
cache: "no-store",
});
if (!response.ok) {
throw new Error(`HTTP ${response.status}`);
}
const payload = await response.json();
const strategies = publicStrategiesOnly(Array.isArray(payload.strategies) ? payload.strategies : []);
const tradeLimit = Number(payload.ranking?.recent_trade_limit) || 30;
if (rankingDescription) {
rankingDescription.textContent = `라이브 퍼블리싱된 공개 전략의 최근 청산 ${tradeLimit}건을 기준으로 표시합니다.`;
}
renderPreview(strategies);
renderCards(strategies);
} catch (error) {
console.error(error);
if (rankingPreview) {
rankingPreview.innerHTML = '공개 전략 정보를 불러오지 못했습니다.
';
}
if (topStrategyGrid) {
topStrategyGrid.innerHTML = `
공개 전략 정보를 불러오지 못했습니다.
잠시 후 다시 확인해 주세요.
`;
}
}
}
loadTopStrategies();