添加新的支撑和压力位显示
This commit is contained in:
+524
@@ -0,0 +1,524 @@
|
||||
//@version=6
|
||||
// 功能:智能支撑/压力位识别系统(优化版)
|
||||
//
|
||||
// 核心改进:
|
||||
// ✅ 强度评分系统:综合触碰次数、反应幅度、成交量、时间衰减
|
||||
// ✅ 突破检测:识别有效突破并标记
|
||||
// ✅ S/R 转换:自动检测支撑变压力、压力变支撑
|
||||
// ✅ 区域显示:支持显示价格区域而非单一线条
|
||||
// ✅ 智能排序:按强度和距离综合评分选择最重要的水平
|
||||
// ✅ 性能优化:改进标签管理、减少重复计算
|
||||
// ✅ 接近预警:可选的价格接近提醒
|
||||
//
|
||||
// 使用场景:
|
||||
// 1. 震荡交易:在强支撑附近做多,强压力附近做空
|
||||
// 2. 突破交易:关注"突破"标记的水平线,确认趋势延续
|
||||
// 3. S/R转换:关注"转换"标记,这些是关键的心理价位
|
||||
// 4. 风险管理:根据最近S/R和强度分数设置止损位
|
||||
|
||||
indicator("智能支撑/压力位 Pro", overlay=true, max_lines_count=250, max_labels_count=150, max_boxes_count=50)
|
||||
|
||||
// ========== 输入参数 ========== //
|
||||
// 枢轴检测
|
||||
pivotGroup = "枢轴检测"
|
||||
leftBars = input.int(4, "左侧K线数", minval=1, group=pivotGroup)
|
||||
rightBars = input.int(4, "右侧K线数", minval=1, group=pivotGroup)
|
||||
lookbackBars = input.int(500, "回溯周期", minval=50, maxval=5000, group=pivotGroup)
|
||||
|
||||
// 聚类与过滤
|
||||
clusterGroup = "聚类与过滤"
|
||||
atrLength = input.int(14, "ATR周期", minval=1, group=clusterGroup)
|
||||
clusterTolATR = input.float(0.3, "聚类容差 (×ATR)", step=0.05, minval=0.05, group=clusterGroup)
|
||||
minTouches = input.int(2, "最少触碰次数", minval=1, group=clusterGroup)
|
||||
minStrength = input.float(0, "最低强度分数", minval=0, maxval=100, step=5, group=clusterGroup, tooltip="0-100,越高要求越严格")
|
||||
|
||||
// 强度评分权重
|
||||
strengthGroup = "强度评分"
|
||||
weightTouches = input.float(40, "触碰次数权重 %", minval=0, maxval=100, group=strengthGroup)
|
||||
weightReaction = input.float(30, "反应强度权重 %", minval=0, maxval=100, group=strengthGroup)
|
||||
weightVolume = input.float(20, "成交量权重 %", minval=0, maxval=100, group=strengthGroup)
|
||||
weightRecency = input.float(10, "时效性权重 %", minval=0, maxval=100, group=strengthGroup)
|
||||
reactionBars = input.int(5, "反应检测K线数", minval=1, maxval=20, group=strengthGroup, tooltip="检测触碰后多少根K线的价格反应")
|
||||
|
||||
// 显示设置
|
||||
displayGroup = "显示设置"
|
||||
maxVisibleLevels = input.int(12, "最多显示水平数", minval=1, maxval=50, group=displayGroup)
|
||||
showAsZone = input.bool(false, "显示为区域", group=displayGroup, tooltip="用半透明区域代替线条")
|
||||
zoneWidthATR = input.float(0.15, "区域宽度 (×ATR)", step=0.05, minval=0.05, group=displayGroup)
|
||||
lineWidth = input.int(2, "线条宽度", minval=1, maxval=5, group=displayGroup)
|
||||
resistanceColor = input.color(#FF5252, "压力色", group=displayGroup)
|
||||
supportColor = input.color(#26A69A, "支撑色", group=displayGroup)
|
||||
breakoutColor = input.color(#FFA726, "突破色", group=displayGroup)
|
||||
flippedColor = input.color(#AB47BC, "转换色", group=displayGroup)
|
||||
|
||||
// 标签设置
|
||||
labelGroup = "标签设置"
|
||||
showLabels = input.bool(true, "显示标签", inline="lbl1", group=labelGroup)
|
||||
showStrength = input.bool(true, "显示强度", inline="lbl1", group=labelGroup)
|
||||
showTouches = input.bool(true, "显示触碰", inline="lbl2", group=labelGroup)
|
||||
showBreakout = input.bool(true, "标记突破", inline="lbl2", group=labelGroup)
|
||||
showFlipped = input.bool(true, "标记转换", inline="lbl3", group=labelGroup)
|
||||
labelSize = input.string("Small", "标签大小", options=["Tiny", "Small", "Normal", "Large"], group=labelGroup)
|
||||
labelOffset = input.int(2, "标签偏移", minval=0, maxval=100, group=labelGroup)
|
||||
|
||||
// 预警设置
|
||||
alertGroup = "预警设置"
|
||||
enableAlerts = input.bool(false, "启用接近预警", group=alertGroup)
|
||||
alertDistanceATR = input.float(0.5, "预警距离 (×ATR)", step=0.1, minval=0.1, group=alertGroup)
|
||||
|
||||
// ========== 全局变量 ========== //
|
||||
var float[] levelPrices = array.new_float()
|
||||
var int[] levelTouches = array.new_int()
|
||||
var int[] levelSupportTouches = array.new_int()
|
||||
var int[] levelResistTouches = array.new_int()
|
||||
var int[] levelLastTouchBar = array.new_int()
|
||||
var int[] levelFirstTouchBar = array.new_int()
|
||||
var float[] levelReactionSum = array.new_float() // 累积反应幅度
|
||||
var float[] levelVolumeSum = array.new_float() // 累积成交量
|
||||
var bool[] levelBrokenUp = array.new_bool() // 向上突破
|
||||
var bool[] levelBrokenDown = array.new_bool() // 向下突破
|
||||
var bool[] levelFlipped = array.new_bool() // S/R转换
|
||||
var line[] levelLines = array.new_line()
|
||||
var box[] levelBoxes = array.new_box()
|
||||
var label[] levelLabels = array.new_label()
|
||||
|
||||
// 计算
|
||||
atrValue = ta.atr(atrLength)
|
||||
clusterTolerance = atrValue * clusterTolATR
|
||||
avgVolume = ta.sma(volume, 50)
|
||||
|
||||
// ========== 辅助函数 ========== //
|
||||
|
||||
// 标签大小转换
|
||||
f_label_size(opt) =>
|
||||
switch opt
|
||||
"Tiny" => size.tiny
|
||||
"Small" => size.small
|
||||
"Normal" => size.normal
|
||||
"Large" => size.large
|
||||
=> size.small
|
||||
|
||||
// 查找相近价位索引
|
||||
f_find_level(price, tolerance) =>
|
||||
int foundIdx = -1
|
||||
int sz = array.size(levelPrices)
|
||||
if sz > 0
|
||||
for i = 0 to sz - 1
|
||||
if math.abs(array.get(levelPrices, i) - price) <= tolerance
|
||||
foundIdx := i
|
||||
break
|
||||
foundIdx
|
||||
|
||||
// 删除水平线
|
||||
f_remove_level(idx) =>
|
||||
if not na(array.get(levelLines, idx))
|
||||
line.delete(array.get(levelLines, idx))
|
||||
if not na(array.get(levelBoxes, idx))
|
||||
box.delete(array.get(levelBoxes, idx))
|
||||
if not na(array.get(levelLabels, idx))
|
||||
label.delete(array.get(levelLabels, idx))
|
||||
array.remove(levelPrices, idx)
|
||||
array.remove(levelTouches, idx)
|
||||
array.remove(levelSupportTouches, idx)
|
||||
array.remove(levelResistTouches, idx)
|
||||
array.remove(levelLastTouchBar, idx)
|
||||
array.remove(levelFirstTouchBar, idx)
|
||||
array.remove(levelReactionSum, idx)
|
||||
array.remove(levelVolumeSum, idx)
|
||||
array.remove(levelBrokenUp, idx)
|
||||
array.remove(levelBrokenDown, idx)
|
||||
array.remove(levelFlipped, idx)
|
||||
array.remove(levelLines, idx)
|
||||
array.remove(levelBoxes, idx)
|
||||
array.remove(levelLabels, idx)
|
||||
|
||||
// 清理过期水平
|
||||
f_cleanup_old_levels() =>
|
||||
int sz = array.size(levelPrices)
|
||||
if sz > 0
|
||||
for k = 0 to sz - 1
|
||||
i = sz - 1 - k
|
||||
if bar_index - array.get(levelLastTouchBar, i) > lookbackBars
|
||||
f_remove_level(i)
|
||||
|
||||
// 计算反应强度(触碰后的价格变化)
|
||||
f_calculate_reaction(price, isResistance, touchBar) =>
|
||||
float reaction = 0.0
|
||||
if bar_index >= touchBar + reactionBars
|
||||
// 检查触碰后的价格变化
|
||||
float maxMove = 0.0
|
||||
for j = 1 to reactionBars
|
||||
if touchBar + j <= bar_index
|
||||
barIdx = touchBar + j
|
||||
priceMove = isResistance ? (price - low[bar_index - barIdx]) : (high[bar_index - barIdx] - price)
|
||||
maxMove := math.max(maxMove, priceMove)
|
||||
reaction := maxMove
|
||||
reaction
|
||||
|
||||
// 计算强度分数 (0-100)
|
||||
f_calculate_strength(idx) =>
|
||||
touches = array.get(levelTouches, idx)
|
||||
reactionSum = array.get(levelReactionSum, idx)
|
||||
volumeSum = array.get(levelVolumeSum, idx)
|
||||
lastBar = array.get(levelLastTouchBar, idx)
|
||||
firstBar = array.get(levelFirstTouchBar, idx)
|
||||
|
||||
// 归一化各项指标
|
||||
touchScore = math.min(touches / 10.0, 1.0) * 100 // 10次触碰为满分
|
||||
|
||||
avgReaction = touches > 0 ? reactionSum / touches : 0
|
||||
reactionScore = math.min(avgReaction / (atrValue * 2), 1.0) * 100 // 2倍ATR反应为满分
|
||||
|
||||
avgVol = touches > 0 ? volumeSum / touches : 0
|
||||
volumeScore = avgVolume > 0 ? math.min(avgVol / avgVolume, 2.0) / 2.0 * 100 : 50
|
||||
|
||||
// 时效性:越近期越高分
|
||||
barsSinceTouch = bar_index - lastBar
|
||||
recencyScore = math.max(0, 100 - (barsSinceTouch / lookbackBars * 100))
|
||||
|
||||
// 加权计算总分
|
||||
totalWeight = weightTouches + weightReaction + weightVolume + weightRecency
|
||||
float strength = 50.0
|
||||
if totalWeight > 0
|
||||
strength := (touchScore * weightTouches + reactionScore * weightReaction + volumeScore * weightVolume + recencyScore * weightRecency) / totalWeight
|
||||
|
||||
strength
|
||||
|
||||
// 检测突破
|
||||
f_check_breakout(idx) =>
|
||||
price = array.get(levelPrices, idx)
|
||||
supTouches = array.get(levelSupportTouches, idx)
|
||||
resTouches = array.get(levelResistTouches, idx)
|
||||
wasResistance = resTouches >= supTouches
|
||||
|
||||
brokenUp = false
|
||||
brokenDown = false
|
||||
flipped = false
|
||||
|
||||
// 突破判断:收盘价显著突破水平(超过容差)
|
||||
if close > price + clusterTolerance and wasResistance
|
||||
brokenUp := true
|
||||
// S/R转换:突破后价格站稳,原压力变支撑
|
||||
if close > price and low < price + clusterTolerance * 2
|
||||
flipped := true
|
||||
else if close < price - clusterTolerance and not wasResistance
|
||||
brokenDown := true
|
||||
// S/R转换:跌破后,原支撑变压力
|
||||
if close < price and high > price - clusterTolerance * 2
|
||||
flipped := true
|
||||
|
||||
[brokenUp, brokenDown, flipped]
|
||||
|
||||
// 添加或更新水平
|
||||
f_add_or_update_level(price, isResistance) =>
|
||||
idx = f_find_level(price, clusterTolerance)
|
||||
|
||||
if idx == -1
|
||||
// 新建水平
|
||||
array.push(levelPrices, price)
|
||||
array.push(levelTouches, 1)
|
||||
array.push(levelSupportTouches, isResistance ? 0 : 1)
|
||||
array.push(levelResistTouches, isResistance ? 1 : 0)
|
||||
array.push(levelLastTouchBar, bar_index)
|
||||
array.push(levelFirstTouchBar, bar_index)
|
||||
array.push(levelReactionSum, 0.0)
|
||||
array.push(levelVolumeSum, volume)
|
||||
array.push(levelBrokenUp, false)
|
||||
array.push(levelBrokenDown, false)
|
||||
array.push(levelFlipped, false)
|
||||
array.push(levelLines, na)
|
||||
array.push(levelBoxes, na)
|
||||
array.push(levelLabels, na)
|
||||
else
|
||||
// 更新现有水平
|
||||
oldPrice = array.get(levelPrices, idx)
|
||||
touches = array.get(levelTouches, idx)
|
||||
newTouches = touches + 1
|
||||
|
||||
// 加权平均更新价格
|
||||
newPrice = (oldPrice * touches + price) / newTouches
|
||||
array.set(levelPrices, idx, newPrice)
|
||||
array.set(levelTouches, idx, newTouches)
|
||||
array.set(levelLastTouchBar, idx, bar_index)
|
||||
|
||||
// 更新支撑/压力计数
|
||||
if isResistance
|
||||
array.set(levelResistTouches, idx, array.get(levelResistTouches, idx) + 1)
|
||||
else
|
||||
array.set(levelSupportTouches, idx, array.get(levelSupportTouches, idx) + 1)
|
||||
|
||||
// 累积成交量
|
||||
array.set(levelVolumeSum, idx, array.get(levelVolumeSum, idx) + volume)
|
||||
|
||||
// 计算并累积反应强度(需要等待几根K线)
|
||||
touchBar = array.get(levelLastTouchBar, idx)
|
||||
reaction = f_calculate_reaction(price, isResistance, touchBar - newTouches + 1)
|
||||
if reaction > 0
|
||||
array.set(levelReactionSum, idx, array.get(levelReactionSum, idx) + reaction)
|
||||
|
||||
// 绘制水平线
|
||||
f_draw_levels() =>
|
||||
int sz = array.size(levelPrices)
|
||||
|
||||
// 收集有效候选
|
||||
var int[] candidates = array.new_int()
|
||||
array.clear(candidates)
|
||||
|
||||
if sz > 0
|
||||
for i = 0 to sz - 1
|
||||
touches = array.get(levelTouches, i)
|
||||
lastBar = array.get(levelLastTouchBar, i)
|
||||
strength = f_calculate_strength(i)
|
||||
|
||||
if touches >= minTouches and bar_index - lastBar <= lookbackBars and strength >= minStrength
|
||||
array.push(candidates, i)
|
||||
|
||||
// 综合评分排序选择(距离×强度)
|
||||
var int[] selected = array.new_int()
|
||||
array.clear(selected)
|
||||
|
||||
int candSz = array.size(candidates)
|
||||
if candSz > 0
|
||||
int selectCount = math.min(maxVisibleLevels, candSz)
|
||||
|
||||
for _ = 0 to selectCount - 1
|
||||
if array.size(candidates) == 0
|
||||
break
|
||||
|
||||
int bestPos = -1
|
||||
float bestScore = -1
|
||||
|
||||
int curSz = array.size(candidates)
|
||||
if curSz > 0
|
||||
for pos = 0 to curSz - 1
|
||||
idx = array.get(candidates, pos)
|
||||
price = array.get(levelPrices, idx)
|
||||
strength = f_calculate_strength(idx)
|
||||
|
||||
// 距离因素(归一化)
|
||||
distance = math.abs(close - price)
|
||||
maxDistance = high - low > 0 ? high - low : atrValue
|
||||
distanceFactor = 1.0 - math.min(distance / (maxDistance * 5), 1.0)
|
||||
|
||||
// 综合评分:强度占70%,距离占30%
|
||||
score = strength * 0.7 + distanceFactor * 100 * 0.3
|
||||
|
||||
if score > bestScore
|
||||
bestScore := score
|
||||
bestPos := pos
|
||||
|
||||
if bestPos != -1
|
||||
array.push(selected, array.get(candidates, bestPos))
|
||||
array.remove(candidates, bestPos)
|
||||
|
||||
// 标记选中的水平
|
||||
var bool[] isSelected = array.new_bool()
|
||||
array.clear(isSelected)
|
||||
if sz > 0
|
||||
for _ = 0 to sz - 1
|
||||
array.push(isSelected, false)
|
||||
|
||||
int selSz = array.size(selected)
|
||||
if selSz > 0 and sz > 0
|
||||
for j = 0 to selSz - 1
|
||||
idx = array.get(selected, j)
|
||||
if idx >= 0 and idx < sz
|
||||
array.set(isSelected, idx, true)
|
||||
|
||||
// 绘制或更新图形
|
||||
if sz > 0
|
||||
for i = 0 to sz - 1
|
||||
price = array.get(levelPrices, i)
|
||||
supTouches = array.get(levelSupportTouches, i)
|
||||
resTouches = array.get(levelResistTouches, i)
|
||||
isRes = resTouches >= supTouches
|
||||
|
||||
// 检测突破和转换
|
||||
[brokenUp, brokenDown, flipped] = f_check_breakout(i)
|
||||
array.set(levelBrokenUp, i, brokenUp)
|
||||
array.set(levelBrokenDown, i, brokenDown)
|
||||
if flipped
|
||||
array.set(levelFlipped, i, true)
|
||||
|
||||
// 确定颜色
|
||||
color col = supportColor
|
||||
if array.get(levelFlipped, i) and showFlipped
|
||||
col := flippedColor
|
||||
else if (brokenUp or brokenDown) and showBreakout
|
||||
col := breakoutColor
|
||||
else if isRes
|
||||
col := resistanceColor
|
||||
else
|
||||
col := supportColor
|
||||
|
||||
if array.get(isSelected, i)
|
||||
// 绘制水平线
|
||||
int xRight = bar_index
|
||||
int xLeft = math.max(0, bar_index - lookbackBars)
|
||||
|
||||
if showAsZone
|
||||
// 绘制区域
|
||||
float zoneWidth = atrValue * zoneWidthATR
|
||||
float top = price + zoneWidth / 2
|
||||
float bottom = price - zoneWidth / 2
|
||||
|
||||
bx = array.get(levelBoxes, i)
|
||||
if na(bx)
|
||||
bx := box.new(left=xLeft, top=top, right=xRight, bottom=bottom,
|
||||
border_color=col, bgcolor=color.new(col, 90),
|
||||
border_width=1, border_style=line.style_dashed)
|
||||
array.set(levelBoxes, i, bx)
|
||||
else
|
||||
box.set_lefttop(bx, xLeft, top)
|
||||
box.set_rightbottom(bx, xRight, bottom)
|
||||
box.set_border_color(bx, col)
|
||||
box.set_bgcolor(bx, color.new(col, 90))
|
||||
else
|
||||
// 绘制线条
|
||||
ln = array.get(levelLines, i)
|
||||
if na(ln)
|
||||
ln := line.new(x1=xLeft, y1=price, x2=xRight, y2=price,
|
||||
color=col, width=lineWidth, style=line.style_dashed)
|
||||
array.set(levelLines, i, ln)
|
||||
else
|
||||
line.set_xy1(ln, xLeft, price)
|
||||
line.set_xy2(ln, xRight, price)
|
||||
line.set_color(ln, col)
|
||||
line.set_width(ln, lineWidth)
|
||||
|
||||
// 绘制标签
|
||||
if showLabels
|
||||
touches = array.get(levelTouches, i)
|
||||
strength = f_calculate_strength(i)
|
||||
|
||||
// 构建标签文本
|
||||
string lblText = isRes ? "R" : "S"
|
||||
lblText += " " + str.tostring(price, format.price)
|
||||
|
||||
if showStrength
|
||||
lblText += " [" + str.tostring(math.round(strength), "#") + "]"
|
||||
|
||||
if showTouches
|
||||
lblText += " ×" + str.tostring(touches)
|
||||
|
||||
if array.get(levelFlipped, i) and showFlipped
|
||||
lblText += " 🔄"
|
||||
else if brokenUp and showBreakout
|
||||
lblText += " ⬆️"
|
||||
else if brokenDown and showBreakout
|
||||
lblText += " ⬇️"
|
||||
|
||||
lb = array.get(levelLabels, i)
|
||||
// 只在文本或位置变化时重建
|
||||
bool needsUpdate = na(lb)
|
||||
if not needsUpdate and not na(lb)
|
||||
oldY = label.get_y(lb)
|
||||
if math.abs(oldY - price) > syminfo.mintick
|
||||
needsUpdate := true
|
||||
|
||||
if needsUpdate
|
||||
if not na(lb)
|
||||
label.delete(lb)
|
||||
|
||||
lblX = bar_index + labelOffset
|
||||
lb := label.new(x=lblX, y=price, text=lblText,
|
||||
style=label.style_label_left,
|
||||
color=color.new(col, 85),
|
||||
textcolor=color.white,
|
||||
size=f_label_size(labelSize))
|
||||
array.set(levelLabels, i, lb)
|
||||
else if not na(lb)
|
||||
label.set_text(lb, lblText)
|
||||
label.set_x(lb, bar_index + labelOffset)
|
||||
label.set_color(lb, color.new(col, 85))
|
||||
else
|
||||
// 删除未选中的图形
|
||||
if not na(array.get(levelLines, i))
|
||||
line.delete(array.get(levelLines, i))
|
||||
array.set(levelLines, i, na)
|
||||
if not na(array.get(levelBoxes, i))
|
||||
box.delete(array.get(levelBoxes, i))
|
||||
array.set(levelBoxes, i, na)
|
||||
if not na(array.get(levelLabels, i))
|
||||
label.delete(array.get(levelLabels, i))
|
||||
array.set(levelLabels, i, na)
|
||||
|
||||
// ========== 主逻辑 ========== //
|
||||
|
||||
// 检测枢轴点
|
||||
pivotHigh = ta.pivothigh(high, leftBars, rightBars)
|
||||
pivotLow = ta.pivotlow(low, leftBars, rightBars)
|
||||
|
||||
// 添加水平
|
||||
if not na(pivotHigh)
|
||||
f_add_or_update_level(pivotHigh, true)
|
||||
|
||||
if not na(pivotLow)
|
||||
f_add_or_update_level(pivotLow, false)
|
||||
|
||||
// 清理和绘制
|
||||
f_cleanup_old_levels()
|
||||
f_draw_levels()
|
||||
|
||||
// 计算最近的支撑和压力
|
||||
var float nearestSupport = na
|
||||
var float nearestResistance = na
|
||||
float bestSup = na
|
||||
float bestRes = na
|
||||
int sz = array.size(levelPrices)
|
||||
|
||||
if sz > 0
|
||||
for i = 0 to sz - 1
|
||||
touches = array.get(levelTouches, i)
|
||||
lastBar = array.get(levelLastTouchBar, i)
|
||||
if touches >= minTouches and bar_index - lastBar <= lookbackBars
|
||||
price = array.get(levelPrices, i)
|
||||
if price < close
|
||||
bestSup := na(bestSup) ? price : math.max(bestSup, price)
|
||||
else if price > close
|
||||
bestRes := na(bestRes) ? price : math.min(bestRes, price)
|
||||
|
||||
nearestSupport := bestSup
|
||||
nearestResistance := bestRes
|
||||
|
||||
// 绘制最近S/R参考线
|
||||
plot(nearestSupport, "最近支撑", color=color.new(supportColor, 70), linewidth=1, style=plot.style_circles)
|
||||
plot(nearestResistance, "最近压力", color=color.new(resistanceColor, 70), linewidth=1, style=plot.style_circles)
|
||||
|
||||
// 接近预警
|
||||
if enableAlerts
|
||||
alertDistance = atrValue * alertDistanceATR
|
||||
if not na(nearestSupport) and math.abs(close - nearestSupport) < alertDistance
|
||||
alert("价格接近支撑位: " + str.tostring(nearestSupport, format.price), alert.freq_once_per_bar)
|
||||
if not na(nearestResistance) and math.abs(close - nearestResistance) < alertDistance
|
||||
alert("价格接近压力位: " + str.tostring(nearestResistance, format.price), alert.freq_once_per_bar)
|
||||
|
||||
// 在图表上显示统计信息
|
||||
if barstate.islast and sz > 0
|
||||
var table statsTable = table.new(position.top_right, 2, 4, border_width=1)
|
||||
|
||||
int validLevels = 0
|
||||
float avgStrength = 0.0
|
||||
for i = 0 to sz - 1
|
||||
touches = array.get(levelTouches, i)
|
||||
if touches >= minTouches
|
||||
validLevels += 1
|
||||
avgStrength += f_calculate_strength(i)
|
||||
|
||||
if validLevels > 0
|
||||
avgStrength := avgStrength / validLevels
|
||||
|
||||
table.cell(statsTable, 0, 0, "水平线数", text_color=color.white, bgcolor=color.gray)
|
||||
table.cell(statsTable, 1, 0, str.tostring(validLevels), text_color=color.white, bgcolor=color.gray)
|
||||
|
||||
table.cell(statsTable, 0, 1, "平均强度", text_color=color.white, bgcolor=color.gray)
|
||||
table.cell(statsTable, 1, 1, str.tostring(math.round(avgStrength), "#"), text_color=color.white, bgcolor=color.gray)
|
||||
|
||||
table.cell(statsTable, 0, 2, "最近支撑", text_color=color.white, bgcolor=supportColor)
|
||||
table.cell(statsTable, 1, 2, not na(nearestSupport) ? str.tostring(nearestSupport, format.price) : "—",
|
||||
text_color=color.white, bgcolor=supportColor)
|
||||
|
||||
table.cell(statsTable, 0, 3, "最近压力", text_color=color.white, bgcolor=resistanceColor)
|
||||
table.cell(statsTable, 1, 3, not na(nearestResistance) ? str.tostring(nearestResistance, format.price) : "—",
|
||||
text_color=color.white, bgcolor=resistanceColor)
|
||||
|
||||
Reference in New Issue
Block a user