refactor: 缠论引擎包化与 Web 分层(ECR-001)
将根目录引擎迁入 chanlun/ 并保留兼容 shim;拆分 TF_DF 与 web 服务; 前端模块化;strategies 改用 chanlun 导入;补充 ESS 文档与 golden 回归。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,258 @@
|
||||
/* macd_ui.js */
|
||||
function showMacdConfig() {
|
||||
$.get('/api/macd_config', function(data) {
|
||||
$('#macdFastPeriod').val(data.fast);
|
||||
$('#macdSlowPeriod').val(data.slow);
|
||||
$('#macdSignalPeriod').val(data.signal);
|
||||
$('#macdConfigModal').css('display', 'flex');
|
||||
});
|
||||
}
|
||||
|
||||
function hideMacdConfig() {
|
||||
$('#macdConfigModal').css('display', 'none');
|
||||
}
|
||||
|
||||
function resetMacdConfig() {
|
||||
$('#macdFastPeriod').val(24);
|
||||
$('#macdSlowPeriod').val(52);
|
||||
$('#macdSignalPeriod').val(9);
|
||||
}
|
||||
|
||||
function saveMacdConfig() {
|
||||
const fast = parseInt($('#macdFastPeriod').val());
|
||||
const slow = parseInt($('#macdSlowPeriod').val());
|
||||
const signal = parseInt($('#macdSignalPeriod').val());
|
||||
if (fast >= slow) {
|
||||
alert('快线周期必须小于慢线周期');
|
||||
return;
|
||||
}
|
||||
if (fast < 2 || slow < 2 || signal < 2) {
|
||||
alert('周期值必须大于等于2');
|
||||
return;
|
||||
}
|
||||
$.ajax({
|
||||
url: '/api/macd_config',
|
||||
method: 'POST',
|
||||
contentType: 'application/json',
|
||||
data: JSON.stringify({ fast: fast, slow: slow, signal: signal }),
|
||||
success: function() {
|
||||
hideMacdConfig();
|
||||
updateChart();
|
||||
},
|
||||
error: function() {
|
||||
alert('保存MACD参数失败');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
$(document).on('click', '#macdConfigModal', function(e) {
|
||||
if (e.target === this) hideMacdConfig();
|
||||
});
|
||||
|
||||
// 添加原始K线复选框变更事件
|
||||
$('#showOriginalKline').change(function() {
|
||||
updateChartDisplay();
|
||||
});
|
||||
|
||||
// 添加K线形态下拉变更事件(同步隐藏的原始K线开关并重绘)
|
||||
$('#klineType').change(function() {
|
||||
const type = $(this).val();
|
||||
$('#showOriginalKline').prop('checked', type === 'candlestick');
|
||||
updateChartDisplay();
|
||||
});
|
||||
|
||||
// 添加笔复选框变更事件
|
||||
$('#showMainBi').change(function() {
|
||||
updateChartDisplay();
|
||||
});
|
||||
|
||||
// 添加线段复选框变更事件
|
||||
$('#showMainSeg').change(function() {
|
||||
updateChartDisplay();
|
||||
});
|
||||
|
||||
// 添加中枢复选框变更事件
|
||||
$('#showMainZs').change(function() {
|
||||
updateChartDisplay();
|
||||
});
|
||||
// 添加主周期BI中枢复选框变更事件(委托绑定,避免DOM更新后失效)
|
||||
console.log('初始化BI中枢事件绑定');
|
||||
$(document).on('change', '#showMainBiZs', function() {
|
||||
console.log('主BI中枢切换为:', $('#showMainBiZs').is(':checked'));
|
||||
updateChartDisplay();
|
||||
});
|
||||
// 结构价值区复选框变更事件
|
||||
$(document).on('change', '#showMainStructureZone', function() {
|
||||
const on = $('#showMainStructureZone').is(':checked');
|
||||
console.log('结构区切换为:', on);
|
||||
// 勾选后才向服务器请求多周期结构区数据;取消勾选仅重绘,不重复拉取
|
||||
if (on) {
|
||||
updateChart();
|
||||
} else {
|
||||
updateChartDisplay();
|
||||
}
|
||||
});
|
||||
|
||||
// 添加趋势显示复选框变更事件(主/元素),变更后刷新主图
|
||||
$('#showMainTrend').change(function() {
|
||||
updateChartDisplay();
|
||||
});
|
||||
$('#showElementTrend').change(function() {
|
||||
updateChartDisplay();
|
||||
});
|
||||
|
||||
// 添加买卖点复选框变更事件
|
||||
$('#showElementBi').change(function() {
|
||||
updateChartDisplay();
|
||||
});
|
||||
|
||||
// 添加线段复选框变更事件
|
||||
$('#showElementSeg').change(function() {
|
||||
updateChartDisplay();
|
||||
});
|
||||
|
||||
// 添加中枢复选框变更事件
|
||||
$('#showElementZs').change(function() {
|
||||
updateChartDisplay();
|
||||
});
|
||||
// 添加次周期BI中枢复选框变更事件(委托绑定,避免DOM更新后失效)
|
||||
$(document).on('change', '#showElementBiZs', function() {
|
||||
console.log('次BI中枢切换为:', $('#showElementBiZs').is(':checked'));
|
||||
updateChartDisplay();
|
||||
});
|
||||
// 次次周期显示开关变更事件
|
||||
$('#showSubSubBi, #showSubSubSeg, #showSubSubZs, #showSubSubBiZs, #showSubSubKlcFxType, #showSubSubTrend, #showSubSubBsp').change(function() {
|
||||
updateChartDisplay();
|
||||
});
|
||||
$(document).on('change', '#toggleUOnSubSub', function() {
|
||||
window.showUOnSubSub = $('#toggleUOnSubSub').is(':checked');
|
||||
updateChartDisplay();
|
||||
});
|
||||
|
||||
// 买卖点复选框已移除
|
||||
|
||||
// 趋势开关已移除
|
||||
|
||||
// 添加K线周期切换事件监听器
|
||||
$('input[name="klinePeriod"]').change(function() {
|
||||
console.log('K线周期切换:', $(this).attr('id'), $(this).is(':checked'));
|
||||
updateChartDisplay();
|
||||
|
||||
// 更新数据源信息
|
||||
if (currentData) {
|
||||
setupDataSourceInfo(currentData);
|
||||
}
|
||||
});
|
||||
|
||||
// 当选择不同的元素时间周期时
|
||||
$('#elementTimeframe').change(function() {
|
||||
const elementTimeframe = $(this).val();
|
||||
const mainTimeframe = $('#timeframe').val();
|
||||
|
||||
// 检查选择的元素时间周期是否小于等于主周期
|
||||
if (compareTimeframes(elementTimeframe, mainTimeframe) > 0) {
|
||||
alert('元素时间周期必须小于或等于主图表时间周期。');
|
||||
setSmallerOrEqualTimeframe(); // 重置为最大的小于等于时间周期
|
||||
return;
|
||||
}
|
||||
// 次次周期必须小于等于次周期
|
||||
ensureSubSubLteElement();
|
||||
console.log(`当前选择的元素时间周期: ${elementTimeframe},需要点击分析按钮来应用更改`);
|
||||
});
|
||||
// 次次周期变更时校验 <= 次周期
|
||||
$('#subSubTimeframe').change(function() {
|
||||
const subSub = $(this).val();
|
||||
const elementTf = $('#elementTimeframe').val();
|
||||
if (compareTimeframes(subSub, elementTf) > 0) {
|
||||
alert('次次周期必须小于或等于次周期。');
|
||||
ensureSubSubLteElement();
|
||||
return;
|
||||
}
|
||||
});
|
||||
function ensureSubSubLteElement() {
|
||||
const timeframes = window.AVAILABLE_TIMEFRAMES || [];
|
||||
const elementTf = $('#elementTimeframe').val();
|
||||
const subSubTf = $('#subSubTimeframe').val();
|
||||
if (compareTimeframes(subSubTf, elementTf) > 0) {
|
||||
const idxEl = timeframes.indexOf(elementTf);
|
||||
const validSubSub = idxEl > 0 ? timeframes[idxEl - 1] : timeframes[0];
|
||||
$('#subSubTimeframe').val(validSubSub || elementTf);
|
||||
}
|
||||
}
|
||||
|
||||
/** 应用 /api/chart_metadata 返回的周期列表(切换 crypto / A股 时拉取) */
|
||||
function applyChartMetadata(meta) {
|
||||
if (!meta || meta.error || !Array.isArray(meta.timeframe_keys) || meta.timeframe_keys.length === 0) {
|
||||
return;
|
||||
}
|
||||
window.AVAILABLE_TIMEFRAMES = meta.timeframe_keys;
|
||||
window.DEFAULT_MAIN_TIMEFRAME = meta.default_main;
|
||||
window.DEFAULT_ELEMENT_TIMEFRAME = meta.default_element;
|
||||
window.DEFAULT_SUB_SUB_TIMEFRAME = meta.default_sub_sub;
|
||||
const labels = meta.timeframes || {};
|
||||
function refill(selId, preferredVal) {
|
||||
const $el = $(selId);
|
||||
const cur = $el.val();
|
||||
$el.empty();
|
||||
meta.timeframe_keys.forEach(function(k) {
|
||||
$el.append($('<option>', { value: k, text: labels[k] || k }));
|
||||
});
|
||||
const pick = (cur && meta.timeframe_keys.indexOf(cur) >= 0) ? cur : preferredVal;
|
||||
if (pick && meta.timeframe_keys.indexOf(pick) >= 0) {
|
||||
$el.val(pick);
|
||||
} else {
|
||||
$el.val(meta.timeframe_keys[0]);
|
||||
}
|
||||
}
|
||||
refill('#timeframe', meta.default_main);
|
||||
refill('#elementTimeframe', meta.default_element);
|
||||
refill('#subSubTimeframe', meta.default_sub_sub);
|
||||
const mainTf = $('#timeframe').val();
|
||||
if (compareTimeframes($('#elementTimeframe').val(), mainTf) > 0) {
|
||||
setSmallestLargerTimeframe(mainTf);
|
||||
}
|
||||
ensureSubSubLteElement();
|
||||
}
|
||||
|
||||
// 比较两个时间周期的大小
|
||||
function compareTimeframes(tf1, tf2) {
|
||||
const v1 = window.timeframeToMs(tf1);
|
||||
const v2 = window.timeframeToMs(tf2);
|
||||
if (v1 === null || v2 === null) {
|
||||
return 0;
|
||||
}
|
||||
return v1 - v2;
|
||||
}
|
||||
|
||||
// 设置比主周期小的最大周期
|
||||
function setSmallestLargerTimeframe(mainTimeframe) {
|
||||
const timeframes = window.AVAILABLE_TIMEFRAMES || [];
|
||||
const mainIndex = timeframes.indexOf(mainTimeframe);
|
||||
|
||||
if (mainIndex > 0) {
|
||||
$('#elementTimeframe').val(timeframes[mainIndex - 1]);
|
||||
} else {
|
||||
$('#elementTimeframe').val(timeframes[0]);
|
||||
}
|
||||
}
|
||||
|
||||
// 设置小于或等于主周期的时间周期
|
||||
function setSmallerOrEqualTimeframe(mainTimeframe) {
|
||||
const timeframes = window.AVAILABLE_TIMEFRAMES || [];
|
||||
const mainIndex = timeframes.indexOf(mainTimeframe);
|
||||
|
||||
// 默认选择相同的时间周期
|
||||
$('#elementTimeframe').val(mainTimeframe);
|
||||
}
|
||||
|
||||
// 当主时间周期变更时,确保分形元素时间周期、次次周期正确
|
||||
$('#timeframe').change(function() {
|
||||
const mainTimeframe = $(this).val();
|
||||
const elementTimeframe = $('#elementTimeframe').val();
|
||||
|
||||
if (compareTimeframes(elementTimeframe, mainTimeframe) > 0) {
|
||||
setSmallerOrEqualTimeframe(mainTimeframe);
|
||||
}
|
||||
ensureSubSubLteElement();
|
||||
});
|
||||
let _lastKlinePeriod = 'main';
|
||||
Reference in New Issue
Block a user