添加动能理论chanmacd,顶底分型5隐形形态
This commit is contained in:
+6
-8
@@ -1,7 +1,7 @@
|
||||
import copy
|
||||
from typing import Dict, Optional
|
||||
|
||||
from ChanEnum import Chan_FX_TYPE, Chan_KLINE_DIR, Chan_BI_DIR, Chan_KLC_FX, Chan_K_DIR
|
||||
from ChanEnum import Chan_FX_TYPE, Chan_KLINE_DIR, Chan_BI_DIR, Chan_KLC_FX, Chan_K_DIR, Chan_MACD_STATE
|
||||
import ChanKLU
|
||||
import ChanCTime
|
||||
|
||||
@@ -78,17 +78,15 @@ class ChanKLC():
|
||||
self.klc_fx_type = Chan_KLC_FX.BOTTOM4
|
||||
if self.fx == Chan_FX_TYPE.TOP:
|
||||
#print(self.end_time, self.fx, self.macd, self.macdhist, len(self.klus))
|
||||
if self.macd > 0:
|
||||
self.bb_out = True
|
||||
if self.macdhist < 0:
|
||||
if self.macdhist < 0 and self.macd > 0 and self.macd > self.pre.macd and self.macd > self.next.macd:
|
||||
self.klc_fx_type = Chan_KLC_FX.TOP5
|
||||
self.bb_out = True
|
||||
else:
|
||||
if self.fx == Chan_FX_TYPE.BOTTOM:
|
||||
if self.macd < 0:
|
||||
self.bb_out = True
|
||||
if self.macdhist > 0:
|
||||
if self.macdhist > 0 and self.macd < 0 and self.macd < self.pre.macd and self.macd < self.next.macd:
|
||||
self.klc_fx_type = Chan_KLC_FX.BOTTOM5
|
||||
#self.bb_out = True
|
||||
self.bb_out = True
|
||||
|
||||
def cal_macd_state(self, dir):
|
||||
macd_state = 0
|
||||
return macd_state
|
||||
|
||||
@@ -17,6 +17,7 @@ from technical.util import resample_to_interval
|
||||
from decimal import Decimal
|
||||
import xgboost as xgb
|
||||
import numpy as np
|
||||
from ChanMACD import ChanMACD
|
||||
|
||||
class ChanLun():
|
||||
timeframes = ["5m", "15m", "30m", "60m", "4h"]
|
||||
@@ -1155,6 +1156,8 @@ class ChanLun():
|
||||
klu_list = self.get_klu_list(dataframe)
|
||||
klc_list = []
|
||||
last_klu = None
|
||||
macd = ChanMACD(klu_list)
|
||||
klu_list = macd.cal_macd()
|
||||
for klu in klu_list:
|
||||
if len(klc_list) > 0:
|
||||
last_klc = klc_list[-1]
|
||||
|
||||
+3
-1
@@ -16,6 +16,7 @@ class ChanMACD():
|
||||
self.return_zero_list = [] # 归零轴列表
|
||||
self.cross0_up_list = [] # 向上穿越零轴列表
|
||||
self.cross0_down_list = [] # 向下穿越零轴列表
|
||||
# 计算段 / UnitTF / HistSet 及状态标记
|
||||
self.cal_macd()
|
||||
def cal_macd(self):
|
||||
last_seg = None
|
||||
@@ -139,4 +140,5 @@ class ChanMACD():
|
||||
last_seg.add_histset(histset)
|
||||
if last_unittf:
|
||||
last_unittf.add_histset(histset)
|
||||
last_klu = klu
|
||||
last_klu = klu
|
||||
return self.klu_list
|
||||
+16
-1
@@ -1,4 +1,4 @@
|
||||
|
||||
from ChanEnum import Chan_MACDHISTSET_DIR
|
||||
|
||||
class ChanMACDHistSet():
|
||||
def __init__(self, start_time, start_klu, pre_histset, dir):
|
||||
@@ -10,11 +10,26 @@ class ChanMACDHistSet():
|
||||
self.histset_dir = dir
|
||||
self.next = None
|
||||
self.pre = pre_histset
|
||||
self.high_klu = start_klu
|
||||
self.low_klu = start_klu
|
||||
def set_next(self, next_histset):
|
||||
self.next = next_histset
|
||||
def add_klu(self, klu):
|
||||
self.klu_list.append(klu)
|
||||
klu.set_histset(self)
|
||||
if self.histset_dir == Chan_MACDHISTSET_DIR.ABOVE:
|
||||
if klu.macdhist > self.high_klu.macdhist:
|
||||
self.high_klu = klu
|
||||
else:
|
||||
if klu.macdhist < self.low_klu.macdhist:
|
||||
self.low_klu = klu
|
||||
else:
|
||||
if klu.macdhist < self.high_klu.macdhist:
|
||||
self.high_klu = klu
|
||||
else:
|
||||
if klu.macdhist > self.low_klu.macdhist:
|
||||
self.low_klu = klu
|
||||
def set_end_klu(self, end_klu):
|
||||
self.add_klu(end_klu)
|
||||
self.end_klu = end_klu
|
||||
self.end_time = end_klu.time
|
||||
+15
-5
@@ -14,7 +14,9 @@ class ChanMACDSeg():
|
||||
self.seg_dir = seg_dir
|
||||
self.pre = pre_seg
|
||||
self.next = None
|
||||
self.peak_klu = start_klu
|
||||
self.high_klu = start_klu
|
||||
self.low_klu = start_klu
|
||||
self.ref_klu = None
|
||||
def set_next(self, next_seg):
|
||||
self.next = next_seg
|
||||
def add_klu(self, klu):
|
||||
@@ -22,11 +24,19 @@ class ChanMACDSeg():
|
||||
self.klu_list.append(klu)
|
||||
klu.set_seg(self)
|
||||
if self.seg_dir == Chan_MACDSEG_DIR.ABOVE:
|
||||
if klu.high > self.peak_klu.high:
|
||||
self.peak_klu = klu
|
||||
if klu.macdhist > self.high_klu.macdhist:
|
||||
self.high_klu = klu
|
||||
else:
|
||||
if klu.macdhist < self.low_klu.macdhist:
|
||||
self.low_klu = klu
|
||||
else:
|
||||
if klu.low < self.peak_klu.low:
|
||||
self.peak_klu = klu
|
||||
if klu.macdhist < self.high_klu.macdhist:
|
||||
self.high_klu = klu
|
||||
else:
|
||||
if klu.macdhist > self.low_klu.macdhist:
|
||||
self.low_klu = klu
|
||||
if self.high_klu.index != self.start_klu.index:
|
||||
self.ref_klu = self.high_klu
|
||||
def add_unittf(self, unittf):
|
||||
self.unittf_list.append(unittf)
|
||||
unittf.set_next(self)
|
||||
|
||||
+15
-4
@@ -1,4 +1,4 @@
|
||||
from ChanEnum import Chan_MACD_STATE
|
||||
from ChanEnum import Chan_MACD_STATE, Chan_MACDUNITTF_DIR
|
||||
|
||||
|
||||
class ChanMACDUnitTF():
|
||||
@@ -15,8 +15,9 @@ class ChanMACDUnitTF():
|
||||
self.unittf_dir = dir
|
||||
self.start_type = start_type
|
||||
self.end_type = None
|
||||
self.peak_hist = start_klu.macdhist
|
||||
self.near0_count = 1
|
||||
self.high_klu = start_klu
|
||||
self.low_klu = start_klu
|
||||
def set_next(self, next_unittf):
|
||||
self.next = next_unittf
|
||||
def add_histset(self, histset):
|
||||
@@ -26,8 +27,18 @@ class ChanMACDUnitTF():
|
||||
if klu:
|
||||
self.klu_list.append(klu)
|
||||
klu.set_unittf(self)
|
||||
if klu.macdhist > self.peak_hist:
|
||||
self.peak_hist = klu.macdhist
|
||||
if self.unittf_dir == Chan_MACDUNITTF_DIR.ABOVE:
|
||||
if klu.macdhist > self.high_klu.macdhist:
|
||||
self.high_klu = klu
|
||||
else:
|
||||
if klu.macdhist < self.low_klu.macdhist:
|
||||
self.low_klu = klu
|
||||
else:
|
||||
if klu.macdhist < self.high_klu.macdhist:
|
||||
self.high_klu = klu
|
||||
else:
|
||||
if klu.macdhist > self.low_klu.macdhist:
|
||||
self.low_klu = klu
|
||||
if klu.macd_state == Chan_MACD_STATE.NEAR0 and len(self.histset_list) > 1:
|
||||
#print(self.start_time, klu.time, self.near0_count)
|
||||
self.near0_count += 1
|
||||
|
||||
+1
-1
@@ -138,7 +138,7 @@ MACD黄白线在零轴之下第一个单位调整周期 + 分立跳空背离(
|
||||
如果在单位调整周期内发生了跳空的形态,当跳空能量堆的高度高于前一个能量堆的高度,此时的跳空则为非背离跳空。非背离跳空可以理解为单位周期的单边行情,前一个能量堆失效,以新的最高的能量堆作为后续行情的1号参考点。不管是连续跳空还是分立跳空都遵守这个法则。
|
||||
|
||||
单位调整周期之间的背离
|
||||
单位调整周期之间的背离,是指两个或者两个以上的单位调整周期相比较而建立的关系,相比较的周期必须在同一个线段周期内,不可跨线段比较。当K线在某个时间级别的线段中,MACD经过了一个单位调整周期的运行,黄白线在此回零轴后,由于零轴的支撑反弹或压力反抽的作用,因此出现第二个单位调整周期,当第二个单位调整周期的黄白线这里特指白线离开零轴的距离小于第一个单位调整周期黄白线离开零轴的距离时,单位调整周期之间就产生了相悖的关系,即价格穿新高或新低,而白线能量去出现了减弱或增强,这种背离称为单位调整周期之间的背离,单位调整周期之间的背离也叫区间背离。
|
||||
单位调整周期之间的背离,是指两个或者两个以上的单位调整周期相比较而建立的关系,相比较的周期必须在同一个线段周期内,不可跨线段比较。当K线在某个时间级别的线段中,MACD经过了一个单位调整周期的运行,黄白线在此回零轴后,由于零轴的支撑反弹或压力反抽的作用,因此出现第二个单位调整周期,当第二个单位调整周期的黄白线这里特指白线离开零轴的距离小于第一个单位调整周期黄白线离开零轴的距离时,单位调整周期之间就产生了相悖的关系,即价格穿新高或新低,而白线能量区出现了减弱或增强,这种背离称为单位调整周期之间的背离,单位调整周期之间的背离也叫区间背离。
|
||||
|
||||
上涨线段单位调整周期之间的顶背离为卖点(前提:长级别MACD在高位)
|
||||
下跌线段单位调整周期之间的底背离为买点(前提:长级别MACD在高位)
|
||||
|
||||
@@ -919,7 +919,7 @@
|
||||
</div>
|
||||
<div class="form-check form-check-inline">
|
||||
<input class="form-check-input" type="checkbox" id="showMacd" checked>
|
||||
<label class="form-check-label" for="showMacd">MACD</label>
|
||||
<label class="form-check-label" for="showMacd">ChanMACD</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="d-flex align-items-center mt-2">
|
||||
@@ -2160,6 +2160,9 @@
|
||||
if (tvWidget.macdChart) {
|
||||
tvWidget.macdChart.timeScale().setVisibleLogicalRange(logicalRange);
|
||||
}
|
||||
if (tvWidget.chanMacdChart) {
|
||||
tvWidget.chanMacdChart.timeScale().setVisibleLogicalRange(logicalRange);
|
||||
}
|
||||
} else if (visibleRange) {
|
||||
// 如果没有逻辑范围,使用时间戳范围
|
||||
tvWidget.mainChart.timeScale().setVisibleRange(visibleRange);
|
||||
@@ -2477,6 +2480,16 @@
|
||||
chanMacdChartContainer.style.right = '0';
|
||||
chanMacdChartContainer.style.borderTop = '1px solid #e0e0e0';
|
||||
chanMacdChartContainer.style.zIndex = '10';
|
||||
// 水印:便于区分是新的 ChanMACD 子图
|
||||
const chanMacdWatermark = document.createElement('div');
|
||||
chanMacdWatermark.textContent = 'ChanMACD';
|
||||
chanMacdWatermark.style.position = 'absolute';
|
||||
chanMacdWatermark.style.top = '4px';
|
||||
chanMacdWatermark.style.left = '8px';
|
||||
chanMacdWatermark.style.fontSize = '11px';
|
||||
chanMacdWatermark.style.color = '#888';
|
||||
chanMacdWatermark.style.pointerEvents = 'none';
|
||||
chanMacdChartContainer.appendChild(chanMacdWatermark);
|
||||
|
||||
// 成交量位于 ChanMACD 之下
|
||||
volumeChartContainer.style.top = '70%';
|
||||
@@ -2887,11 +2900,12 @@
|
||||
isArray: Array.isArray(currentData.kline_data)
|
||||
});
|
||||
if (showMacd && chanMacdChart && currentData.macd && currentData.kline_data && Array.isArray(currentData.kline_data)) {
|
||||
console.log('✅ 开始创建 ChanMACD 系列');
|
||||
// 创建ChanMACD线系列
|
||||
const chanMacdLineSeries = chanMacdChart.addLineSeries({
|
||||
color: '#2962FF',
|
||||
lineWidth: 1,
|
||||
title: 'MACD',
|
||||
title: 'ChanMACD',
|
||||
lastValueVisible: false,
|
||||
priceLineVisible: false,
|
||||
});
|
||||
@@ -2900,7 +2914,7 @@
|
||||
const chanMacdSignalSeries = chanMacdChart.addLineSeries({
|
||||
color: '#FF6B6B',
|
||||
lineWidth: 1,
|
||||
title: 'Signal',
|
||||
title: 'ChanSignal',
|
||||
lastValueVisible: false,
|
||||
priceLineVisible: false,
|
||||
});
|
||||
@@ -2908,7 +2922,7 @@
|
||||
// 创建ChanMACD柱状图系列
|
||||
const chanMacdHistSeries = chanMacdChart.addHistogramSeries({
|
||||
color: '#26a69a',
|
||||
title: 'Histogram',
|
||||
title: 'ChanHistogram',
|
||||
priceFormat: {
|
||||
type: 'price',
|
||||
precision: 4,
|
||||
@@ -5477,6 +5491,9 @@
|
||||
if (showMacd && macdChart) {
|
||||
macdChart.timeScale().setVisibleRange(visibleRange);
|
||||
}
|
||||
if (showMacd && chanMacdChart) {
|
||||
chanMacdChart.timeScale().setVisibleRange(visibleRange);
|
||||
}
|
||||
|
||||
console.log('🔧 最终时间轴对齐完成');
|
||||
}
|
||||
@@ -5676,6 +5693,53 @@
|
||||
tvWidget.series.histogramSeries.setData(histogramData);
|
||||
}
|
||||
|
||||
// 更新 ChanMACD 数据与自定义标注
|
||||
if (tvWidget.series.chanMacdLineSeries && currentData.macd && currentData.kline_data && Array.isArray(currentData.kline_data)) {
|
||||
const klineDataSource = useElementPeriod ? currentData.element_kline_data : currentData.kline_data;
|
||||
const macdDataSource = useElementPeriod ? (currentData.element_macd || currentData.macd) : currentData.macd;
|
||||
if (macdDataSource && macdDataSource.macd && macdDataSource.signal && macdDataSource.histogram) {
|
||||
const chanMacdData = [];
|
||||
const chanSignalData = [];
|
||||
const chanHistData = [];
|
||||
for (let i = 0; i < klineDataSource.length; i++) {
|
||||
const kline = klineDataSource[i];
|
||||
if (kline && kline.date && i < macdDataSource.macd.length && macdDataSource.macd[i] !== null && macdDataSource.macd[i] !== undefined) {
|
||||
const timestamp = Math.floor(new Date(kline.date).getTime() / 1000);
|
||||
chanMacdData.push({ time: timestamp, value: macdDataSource.macd[i] });
|
||||
chanSignalData.push({ time: timestamp, value: macdDataSource.signal[i] });
|
||||
chanHistData.push({ time: timestamp, value: macdDataSource.histogram[i], color: macdDataSource.histogram[i] >= 0 ? 'rgba(220, 53, 69, 0.5)' : 'rgba(40, 167, 69, 0.5)' });
|
||||
}
|
||||
}
|
||||
if (chanMacdData.length > 0) {
|
||||
tvWidget.series.chanMacdLineSeries.setData(chanMacdData);
|
||||
tvWidget.series.chanMacdSignalSeries.setData(chanSignalData);
|
||||
tvWidget.series.chanMacdHistSeries.setData(chanHistData);
|
||||
}
|
||||
}
|
||||
// 重新应用自定义标注(段/UnitTF/HistSet/状态点)
|
||||
try {
|
||||
if (typeof clearChanMacdMarkers === 'function') clearChanMacdMarkers();
|
||||
if (currentData.chan_macd) {
|
||||
addAllChanMacdMarkers(
|
||||
currentData.chan_macd.seg_list || [],
|
||||
currentData.chan_macd.unittf_list || [],
|
||||
currentData.chan_macd.histset_list || [],
|
||||
{
|
||||
high_position_list: currentData.chan_macd.high_position_list || [],
|
||||
high_empty_list: currentData.chan_macd.high_empty_list || [],
|
||||
low_position_list: currentData.chan_macd.low_position_list || [],
|
||||
low_empty_list: currentData.chan_macd.low_empty_list || [],
|
||||
return_zero_list: currentData.chan_macd.return_zero_list || [],
|
||||
cross0_up_list: currentData.chan_macd.cross0_up_list || [],
|
||||
cross0_down_list: currentData.chan_macd.cross0_down_list || []
|
||||
}
|
||||
);
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn('更新ChanMACD标注失败:', e);
|
||||
}
|
||||
}
|
||||
|
||||
// 重新显示笔、线段和中枢等图形
|
||||
redrawFractalElements();
|
||||
|
||||
@@ -7191,6 +7255,7 @@
|
||||
if (tvWidget.volumeChart) tvWidget.volumeChart.timeScale().setVisibleLogicalRange(logicalRange);
|
||||
if (tvWidget.atrChart) tvWidget.atrChart.timeScale().setVisibleLogicalRange(logicalRange);
|
||||
if (tvWidget.macdChart) tvWidget.macdChart.timeScale().setVisibleLogicalRange(logicalRange);
|
||||
if (tvWidget.chanMacdChart) tvWidget.chanMacdChart.timeScale().setVisibleLogicalRange(logicalRange);
|
||||
} else if (visibleRange) {
|
||||
tvWidget.mainChart.timeScale().setVisibleRange(visibleRange);
|
||||
if (tvWidget.volumeChart) tvWidget.volumeChart.timeScale().setVisibleRange(visibleRange);
|
||||
|
||||
Reference in New Issue
Block a user