根据新的条件进行交易,添加交易规则

This commit is contained in:
Porter
2025-09-15 10:29:53 +08:00
parent 3c360ea35b
commit 0b9f63409c
8 changed files with 149 additions and 71 deletions
+1
View File
@@ -27,3 +27,4 @@ feature_meta
*.sqlite-shm
*.sqlite-wal
.DS_Store
交易记录/~$交易规则.docx
+2 -2
View File
@@ -79,12 +79,12 @@ class ChanKLC():
if self.fx == Chan_FX_TYPE.TOP:
#print(self.end_time, self.fx, self.macd, self.macdhist, len(self.klus))
if self.macdhist < 0 and self.macd > 0:
#self.klc_fx_type = Chan_KLC_FX.TOP5
self.klc_fx_type = Chan_KLC_FX.TOP5
self.bb_out = True
else:
if self.fx == Chan_FX_TYPE.BOTTOM:
if self.macdhist > 0 and self.macd < 0:
#self.klc_fx_type = Chan_KLC_FX.BOTTOM5
self.klc_fx_type = Chan_KLC_FX.BOTTOM5
self.bb_out = True
def cal_macd_state(self, dir):
+24 -5
View File
@@ -651,12 +651,31 @@ class ChanKLU:
if (self.macd == 0 and self.signal == 0 and self.macdhist == 0) or self.ema52 == 0:
self.macd_state = Chan_MACD_STATE.UNKNOWN
return self.macd_state
if self.macd > 0:
if self.macd < self.signal and self.close > self.ema52 and self.low < self.ema52:
self.near0_return = 0
# 归零轴判断
if self.signal > 0:
if self.macd < self.signal:
if 0 < self.low - self.ema52 < 100:
self.near0_return = 6
elif self.close > self.ema52 and self.low < self.ema52 and self.open > self.ema52:
self.near0_return = 7
elif self.close < self.ema52 and self.open > self.ema52 and self.high > self.ema52 and self.low < self.ema52:
self.near0_return = 8
elif self.close < self.ema52 and self.open < self.ema52 and self.high > self.ema52 and self.low < self.ema52:
self.near0_return = 9
elif self.close > self.ema52 and self.open > self.ema52 and self.high > self.ema52 and self.low < self.ema52:
self.near0_return = 10
else:
if self.macd > self.signal and self.close < self.ema52 and self.high > self.ema52:
self.near0_return = 0
if self.macd > self.signal:
if 0 < self.ema52 - self.high < 100:
self.near0_return = 61
elif self.close < self.ema52 and self.high > self.ema52 and self.open < self.ema52:
self.near0_return = 71
elif self.close < self.ema52 and self.open > self.ema52 and self.high > self.ema52 and self.low < self.ema52:
self.near0_return = 81
elif self.close > self.ema52 and self.open < self.ema52 and self.high > self.ema52 and self.low < self.ema52:
self.near0_return = 91
elif self.close > self.ema52 and self.high > self.ema52 and self.open > self.ema52 and self.low < self.ema52:
self.near0_return = 101
# CROSS0 仅以 Signal 穿越零轴判定
if self.pre.signal >= 0 and self.signal < 0:
self.macd_state = Chan_MACD_STATE.CROSS0_DOWN
+2 -2
View File
@@ -88,14 +88,14 @@ class ChanLun():
for klu in klu_list:
if klu.macd > 0:
if klu.separate_div:
state_list.append("20")
state_list.append("30")
elif klu.continue_div:
state_list.append("20")
else:
state_list.append("00")
else:
if klu.separate_div:
state_list.append("-20")
state_list.append("-30")
elif klu.continue_div:
state_list.append("-20")
else:
+1 -1
View File
@@ -82,7 +82,7 @@ class ChanMACDHistSet():
klu = self.peak_div_list[-1]
if klu.macd * klu.macdhist > 0:
end_klu.continue_div = True
print(end_klu.time, "Continue Div")
#print(end_klu.time, "Continue Div")
if self.start_klu.index == end_klu.index:
self.peak_klu = self.start_klu
if self.start_klu.index + 1 == end_klu.index:
+19 -15
View File
@@ -50,7 +50,7 @@ class ChanLun_BTC_30(IStrategy):
"240": 0
}
# 15m and 30m
minimal_roi_1 = {
minimal_roi = {
"0": 0.1,
"240": 0.05,
"480": 0.03,
@@ -220,9 +220,9 @@ class ChanLun_BTC_30(IStrategy):
new_entryprice = proposed_rate
if trade:
if trade.is_short:
new_entryprice = proposed_rate - 5
new_entryprice = proposed_rate - 50
else:
new_entryprice = proposed_rate + 5
new_entryprice = proposed_rate + 50
return new_entryprice
def custom_exit_price(self, pair: str, trade: Trade,
@@ -231,9 +231,9 @@ class ChanLun_BTC_30(IStrategy):
new_exitprice = proposed_rate
if trade:
if trade.is_short:
new_exitprice = proposed_rate + 5
new_exitprice = proposed_rate + 50
else:
new_exitprice = proposed_rate - 5
new_exitprice = proposed_rate - 50
return new_exitprice
def adjust_trade_position(self, trade: Trade, current_time: datetime,
@@ -319,32 +319,36 @@ class ChanLun_BTC_30(IStrategy):
#logger.info(f"保存开仓时ATR值: {entry_atr}")
return None
def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
shift_time = self.time60
state_str = 'resample_{}_state'.format(self.get_ticker_indicator()*shift_time)
shift60 = self.time60
state60 = 'resample_{}_state'.format(self.get_ticker_indicator()*shift60)
shift30 = self.time30
state30 = 'resample_{}_state'.format(self.get_ticker_indicator()*shift30)
dataframe.loc[
(
(dataframe[state_str].shift(shift_time) == "-20")
(dataframe[state30].shift(shift30) == "-20")
),
['enter_long', 'enter_tag']] = (1, 'long_30')
dataframe.loc[
(
(dataframe[state_str].shift(shift_time) == "20")
(dataframe[state30].shift(shift30) == "20")
),
['enter_short', 'enter_tag']] = (1, 'short_30')
return dataframe
def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
shift_time = self.time60
state_str = 'resample_{}_state'.format(self.get_ticker_indicator()*shift_time)
shift60 = self.time60
state60 = 'resample_{}_state'.format(self.get_ticker_indicator()*shift60)
shift30 = self.time30
state30 = 'resample_{}_state'.format(self.get_ticker_indicator()*shift30)
dataframe.loc[
(
(dataframe[state_str].shift(shift_time) == "20")
(dataframe[state30].shift(shift30) == "20") |
(dataframe[state30].shift(shift30) == "30")
),
['exit_long', 'exit_tag']] = (1, 'long_close_30')
dataframe.loc[
(
(dataframe[state_str].shift(shift_time) == "-20")
(dataframe[state30].shift(shift30) == "-20") |
(dataframe[state30].shift(shift30) == "-30")
),
['exit_short', 'exit_tag']] = (1, 'short_close_30')
return dataframe
+90 -36
View File
@@ -3054,62 +3054,114 @@
}
);
// 从 ChanMACD 的 klu_list 提取 continue_div / separate_div 标记,供主K线图显示
// 同时从主/次周期的 klu_list 提取 SD/CD 标记,分别使用不同样式
try {
const kluList = Array.isArray(cm.klu_list) ? cm.klu_list : [];
const kluDivMarkers = [];
kluList.forEach((item) => {
const mainCm = currentData.chan_macd || {};
const elementCm = currentData.element_chan_macd || {};
const mainMarkers = [];
const elementMarkers = [];
// 主周期 U 标记(蓝/橙,与原样式一致)
if ((typeof window.showUOnMain === 'undefined' ? true : window.showUOnMain) && Array.isArray(mainCm.klu_list)) {
mainCm.klu_list.forEach((item) => {
if (!item || !item.time) return;
const ts = Math.floor(new Date(item.time).getTime() / 1000);
if (isNaN(ts)) return;
// separate_div 为 true:上方蓝色箭头
if (item.separate_div === true) {
kluDivMarkers.push({
time: ts,
position: 'aboveBar',
color: '#03a9f4',
shape: 'arrowUp',
text: 'SD',
size: 0.6
});
mainMarkers.push({ time: ts, position: 'aboveBar', color: '#03a9f4', shape: 'arrowUp', text: 'SD', size: 0.6 });
}
// continue_div 为 true:下方橙色箭头
if (item.continue_div === true) {
kluDivMarkers.push({
time: ts,
position: 'belowBar',
color: '#ff9800',
shape: 'arrowDown',
text: 'CD',
size: 0.6
});
mainMarkers.push({ time: ts, position: 'belowBar', color: '#ff9800', shape: 'arrowDown', text: 'CD', size: 0.6 });
}
// near0_return > 0:在主图显示具体数值
if (item.near0_return && Number(item.near0_return) > 0) {
kluDivMarkers.push({
time: ts,
position: 'belowBar',
color: '#8bc34a',
shape: 'circle',
text: `N${Number(item.near0_return)}`,
size: 0.6
});
mainMarkers.push({ time: ts, position: 'belowBar', color: '#8bc34a', shape: 'circle', text: `N${Number(item.near0_return)}`, size: 0.6 });
}
});
window.kluDivMarkers = kluDivMarkers;
}
// 次周期 U 标记(使用不同配色以区分)
if ((typeof window.showUOnElement === 'undefined' ? true : window.showUOnElement) && Array.isArray(elementCm.klu_list)) {
elementCm.klu_list.forEach((item) => {
if (!item || !item.time) return;
const ts = Math.floor(new Date(item.time).getTime() / 1000);
if (isNaN(ts)) return;
if (item.separate_div === true) {
elementMarkers.push({ time: ts, position: 'aboveBar', color: '#9c27b0', shape: 'arrowUp', text: 'SD', size: 0.6 });
}
if (item.continue_div === true) {
elementMarkers.push({ time: ts, position: 'belowBar', color: '#4caf50', shape: 'arrowDown', text: 'CD', size: 0.6 });
}
if (item.near0_return && Number(item.near0_return) > 0) {
elementMarkers.push({ time: ts, position: 'belowBar', color: '#009688', shape: 'circle', text: `N${Number(item.near0_return)}`, size: 0.6 });
}
});
}
// 保存到全局,供主图合并标记使用
window.kluDivMarkersMain = mainMarkers;
window.kluDivMarkersElement = elementMarkers;
} catch (e) {
console.warn('处理 KLU 背驰标记出错:', e);
window.kluDivMarkers = [];
window.kluDivMarkersMain = [];
window.kluDivMarkersElement = [];
}
} else {
console.log('⚠️ 没有ChanMACD分析数据');
// 无数据时清空本次的 KLU 背驰标记
window.kluDivMarkers = [];
window.kluDivMarkersMain = [];
window.kluDivMarkersElement = [];
}
} else {
console.log('⚠️ ChanMACD图表创建条件不满足');
}
// 独立于当前显示周期:计算主/次周期 SD/CD 标记(用于主图合并显示)
try {
const mainCmAll = currentData.chan_macd || {};
const elementCmAll = currentData.element_chan_macd || {};
const mainMarkersAll = [];
const elementMarkersAll = [];
if ((typeof window.showUOnMain === 'undefined' ? true : window.showUOnMain) && Array.isArray(mainCmAll.klu_list)) {
mainCmAll.klu_list.forEach((item) => {
if (!item || !item.time) return;
const ts = Math.floor(new Date(item.time).getTime() / 1000);
if (isNaN(ts)) return;
if (item.separate_div === true) {
mainMarkersAll.push({ time: ts, position: 'aboveBar', color: '#03a9f4', shape: 'arrowUp', text: 'SD', size: 0.6 });
}
if (item.continue_div === true) {
mainMarkersAll.push({ time: ts, position: 'belowBar', color: '#ff9800', shape: 'arrowDown', text: 'CD', size: 0.6 });
}
if (item.near0_return && Number(item.near0_return) > 0) {
mainMarkersAll.push({ time: ts, position: 'belowBar', color: '#8bc34a', shape: 'circle', text: `N${Number(item.near0_return)}`, size: 0.6 });
}
});
}
if ((typeof window.showUOnElement === 'undefined' ? true : window.showUOnElement) && Array.isArray(elementCmAll.klu_list)) {
elementCmAll.klu_list.forEach((item) => {
if (!item || !item.time) return;
const ts = Math.floor(new Date(item.time).getTime() / 1000);
if (isNaN(ts)) return;
if (item.separate_div === true) {
elementMarkersAll.push({ time: ts, position: 'aboveBar', color: '#9c27b0', shape: 'arrowUp', text: 'SD', size: 0.6 });
}
if (item.continue_div === true) {
elementMarkersAll.push({ time: ts, position: 'belowBar', color: '#4caf50', shape: 'arrowDown', text: 'CD', size: 0.6 });
}
if (item.near0_return && Number(item.near0_return) > 0) {
elementMarkersAll.push({ time: ts, position: 'belowBar', color: '#009688', shape: 'circle', text: `N${Number(item.near0_return)}`, size: 0.6 });
}
});
}
window.kluDivMarkersMain = mainMarkersAll;
window.kluDivMarkersElement = elementMarkersAll;
} catch (e) {
console.warn('独立计算 KLU 背驰标记出错:', e);
window.kluDivMarkersMain = [];
window.kluDivMarkersElement = [];
}
// 实现三图联动滚动
// 同步图表的时间范围
@@ -5380,7 +5432,8 @@
const combinedMarkers = [
...(window.mainFxMarkers || []),
...allElementFxMarkers,
...(window.kluDivMarkers || [])
...(window.kluDivMarkersMain || []),
...(window.kluDivMarkersElement || [])
];
if (combinedMarkers.length > 0) {
console.log('合并设置', combinedMarkers.length, '个标记(主周期分型:', (window.mainFxMarkers || []).length, '个,小周期分型:', allElementFxMarkers.length, '个,UnitTF:', (window.unittfMarkers || []).length, '个)');
@@ -5403,7 +5456,8 @@
// 只设置主周期分型 + UnitTF 标记
const onlyMainAndU = [
...(window.mainFxMarkers || []),
...(window.kluDivMarkers || [])
...(window.kluDivMarkersMain || []),
...(window.kluDivMarkersElement || [])
];
if (onlyMainAndU.length > 0) {
console.log('仅设置', onlyMainAndU.length, '个主周期/UnitTF标记(主周期分型:', (window.mainFxMarkers || []).length, 'UnitTF:', (window.unittfMarkers || []).length, '');
Binary file not shown.