Files
xiaobaifupan/app/frontend/shared/export.js
T

141 lines
5.8 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
function exportStocks() {
exportRows("涨停池", getVisibleStocks(), [
["股票代码", "code"], ["股票名称", "name"], ["连板", "streak"], ["涨幅%", "change"],
["价格", "price"], ["所属板块", "sector"], ["涨停原因", "reason"], ["首封", "first_time"],
["最后封板", "last_time"], ["开板次数", "open_times"], ["换手率%", "turnover_rate"],
["成交额亿", "amount_billion"], ["封单额万", "seal_amount_million"],
]);
}
function exportBroken() {
exportRows("炸板池", getVisibleBrokenRows(), [
["股票代码", "code"], ["股票名称", "name"], ["现价涨幅%", "change"], ["距涨停%", "limitGap"],
["价格", "price"], ["所属板块", "sector"], ["首次触板", "first_time"], ["开板次数", "open_times"],
["换手率%", "turnover_rate"], ["成交额亿", "amount_billion"],
]);
}
function exportDown() {
exportRows("跌停板", getVisibleDownRows(), [
["股票代码", "code"], ["股票名称", "name"], ["跌幅%", "change"], ["价格", "price"],
["所属板块", "sector"], ["换手率%", "turnover_rate"], ["成交额亿", "amount_billion"],
]);
}
function exportYesterday() {
exportRows("昨日涨停", getVisibleYesterdayRows(), [
["股票代码", "code"], ["股票名称", "name"], ["昨日高度", "prior_streak"],
["今日涨幅%", "current_change"], ["今日结果", "outcome"], ["当前高度", "current_streak"],
["所属板块", "sector"],
]);
}
function exportLadder() {
const rows = (state.dashboard?.ladders || []).flatMap((group) => (group.stocks || []).map((stock) => ({
level: group.label || group.level,
...stock,
})));
exportRows("市场天梯", rows, [
["梯队", "level"], ["股票代码", "code"], ["股票名称", "name"], ["所属板块", "sector"],
["封板时间", "first_time"], ["开板次数", "open_times"], ["封单额万", "seal_amount_million"], ["成交额亿", "amount_billion"],
]);
}
function exportRotation() {
const sectorMap = new Map((state.dashboard?.sectors || []).map((sector) => [sector.name, sector]));
const rows = (state.dashboard?.sector_rotation || []).map((row) => ({
...row,
average_change: sectorMap.get(row.name)?.change ?? 0,
}));
exportRows("板块轮动", rows, [
["排名", "rank"], ["板块", "name"], ["趋势", "trend"], ["今日涨停", "count"],
["昨日涨停", "previous_count"], ["变化", "delta"], ["强度", "strength"],
["最高板", "max_streak"], ["平均涨幅%", "average_change"],
["领涨股", "leader"], ["涨停股成交额亿", "amount_billion"],
]);
}
function exportSentimentHistory() {
const rows = state.sentimentHistory?.rows || [];
if (!rows.length) {
showToast("暂无可导出的情绪周期数据");
return;
}
const exportRowsData = rows.map((row) => ({
...row,
breadth_score: row.components?.breadth?.score,
limit_ecology_score: row.components?.limit_ecology?.score,
profit_effect_score: row.components?.profit_effect?.score,
ladder_structure_score: row.components?.ladder_structure?.score,
liquidity_score: row.components?.liquidity?.score,
}));
exportRows("情绪周期", exportRowsData, [
["交易日", "trade_date"], ["情绪温度", "score"], ["周期阶段", "phase"], ["方向", "direction"],
["涨停", "limit_up_count"], ["首板", "first_board_count"], ["二板", "second_board_count"],
["三板以上", "three_plus_count"], ["连板高度", "max_height"], ["炸板", "broken_count"],
["跌停", "limit_down_count"], ["昨日涨停", "previous_limit_count"],
["昨日涨停红盘", "previous_positive_count"], ["昨日涨停红盘率%", "previous_positive_rate"],
["市场宽度", "breadth_score"], ["涨停生态", "limit_ecology_score"],
["赚钱效应", "profit_effect_score"], ["连板结构", "ladder_structure_score"],
["成交活跃度", "liquidity_score"],
]);
}
function exportDragonTiger() {
const rows = (state.dragonTiger?.traders || []).flatMap((trader) => (
(trader.operations || []).map((operation) => ({
trader_name: trader.name,
identity_type: dragonIdentityLabel(trader.identity_type),
...operation,
}))
));
exportRows("游资龙虎榜", rows, [
["游资或席位", "trader_name"], ["身份", "identity_type"], ["股票代码", "code"],
["股票名称", "name"], ["方向", "direction"], ["涨幅%", "change"],
["买入百万元", "buy_million"], ["卖出百万元", "sell_million"], ["净额百万元", "net_buy_million"],
["关联席位", "seat_name"], ["上榜原因", "reason"],
]);
}
function exportHotMoneyProfiles() {
const rows = state.hotMoneyProfiles?.profiles || [];
if (!rows.length) {
showToast("暂无可导出的游资档案");
return;
}
downloadCsv(
`游资档案-${todayString()}.csv`,
["游资名称", "简介", "关联营业部", "席位数量"],
rows.map((profile) => [
profile.name,
profile.description,
(profile.organizations || []).join(""),
number(profile.organization_count),
]),
);
}
function exportRows(label, rows, columns) {
const headers = columns.map(([header]) => header);
const data = rows.map((row) => columns.map(([, key]) => row[key] ?? ""));
downloadCsv(`${label}-${state.dashboard.meta.trade_date}.csv`, headers, data);
}
function downloadCsv(filename, headers, rows) {
const lines = [headers, ...rows].map((row) => row.map(csvCell).join(","));
const blob = new Blob(["\ufeff", lines.join("\r\n")], { type: "text/csv;charset=utf-8" });
const url = URL.createObjectURL(blob);
const anchor = document.createElement("a");
anchor.href = url;
anchor.download = filename;
anchor.click();
URL.revokeObjectURL(url);
showToast(`已导出 ${rows.length} 条数据`);
}
function csvCell(value) {
let text = String(value ?? "");
if (/^[=+\-@]/.test(text)) text = `'${text}`;
return `"${text.replaceAll('"', '""')}"`;
}