144 lines
5.9 KiB
JavaScript
144 lines
5.9 KiB
JavaScript
/* PRESERVATION-SOURCE-BEGIN app.js:8905-9051 */
|
||
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('"', '""')}"`;
|
||
}
|
||
|
||
/* PRESERVATION-SOURCE-END app.js:8905-9051 */
|