Indicator运行报错‘Internal Server Study Error’,求代码排查指导
排查Pine Script v5「Internal Server Study Error」问题及修复方案
以下是导致错误的核心问题及对应的修复步骤:
1. 未初始化symbolList数组
代码中直接调用array.push(symbolList, ...)但从未创建该数组,这会触发运行时错误。
修复:在添加标的前初始化字符串数组:
// 自选列表初始化 var array<string> symbolList = array.new_string() array.push(symbolList,'BINANCE:ADAUSDT') array.push(symbolList,'BINANCE:ATOMUSDT') array.push(symbolList,'BINANCE:BNBUSDT') array.push(symbolList,'BINANCE:BTCUSDT') array.push(symbolList,'BINANCE:CHRUSDT') array.push(symbolList,'BINANCE:COCOSUSDT') array.push(symbolList,'BINANCE:COTIUSDT') array.push(symbolList,'BINANCE:DGBUSDT') array.push(symbolList,'BINANCE:DOGEUSDT') array.push(symbolList,'BINANCE:EOSUSDT')
2. 错误调用time_close
time_close是Pine Script内置变量(当前K线的收盘时间),并非可传入参数的函数。原代码中time_close(timeperiod, syminfo.session, syminfo.timezone)属于语法错误,会触发服务器异常。
修复:通过request.security获取目标标的对应时间框架的收盘时间:
// 替换原entry_time行 entry_time = str.format('{0,date,yyyy.MM.dd HH:mm:ss}', request.security(symbol, timeperiod, time_close))
3. 高频创建表格导致资源过载
print_table函数在barstate.islast时每次tick都创建新表格,会导致内存泄漏和服务器压力过大。
修复:使用var关键字创建持久化表格,仅初始化一次,后续更新内容即可:
// 全局定义持久化表格 var table t = na print_table() => // 仅在表格未初始化时创建 if na(t) t := table.new(position = tableLocation, columns = 5, rows = array.size(results), border_width = 1, border_color = color.black) // 先清除旧内容 table.clear(t) // 重新设置行数(如果结果数量变化) table.set_row_count(t, array.size(results)) // 遍历结果填充表格 for i = 0 to array.size(results)-1 eachResult = array.get(results, i) bg_color = i == array.size(results)-1 ? color.yellow : color.new(color.yellow,80) table.cell(table_id = t, column = 0, row = i, text = str.tostring(eachResult.s), bgcolor = bg_color) table.cell(table_id = t, column = 1, row = i, text = eachResult.sym, bgcolor = bg_color) table.cell(table_id = t, column = 2, row = i, text = str.tostring(eachResult.ent), bgcolor = bg_color) table.cell(table_id = t, column = 3, row = i, text = eachResult.rsn, bgcolor = bg_color) table.cell(table_id = t, column = 4, row = i, text = eachResult.dt, bgcolor = bg_color)
4. 其他逻辑优化(避免潜在错误)
- 冗余数组初始化:将
results数组的初始化简化为一行:var array<resultItem> results = array.new<resultItem>() - 结果序号错误:原代码中
resultNo仅在最后一根K线更新,导致所有信号序号相同。改为每次添加新结果时递增序号,并在每次筛选前重置:// 在calculate_rsi_div函数中创建resultItem时 resultNo += 1 ri = resultItem.new(resultNo, symbol, entryPrice, entry_reason, entry_time) array.push(results, ri) // 在barstate.islast中重置序号 resultNo := 0 - 数组无限增长:在每次执行筛选前清空
results数组,避免内存占用过高:if barstate.islast array.clear(results) // 清空旧结果 - 遍历自选列表:原代码仅调用了单个标的,修复后遍历整个
symbolList执行筛选:if screenerStrategy1 // 遍历所有自选标的 for sym in symbolList calculate_rsi_div(sym, timeframe)
完整修复后的代码
//@version=5 indicator(title = 'ps_screener', shorttitle = 'PS',overlay = true) var int resultNo = 0 // 初始化结果序号 var int prevResultNo = 0 // 上一次执行的结果数量 // 定义结果对象类型 type resultItem int s string sym float ent string rsn string dt // 初始化结果数组 var array<resultItem> results = array.new<resultItem>() // 筛选策略设置 screeningStrategy = '=====筛选策略===============' screenerStrategy1 = input.bool(title = 'RSI背离', defval = true, tooltip = '启用RSI背离筛选', group = screeningStrategy) // 时间框架设置 timeframeHeader = '=======时间框架=====================' timeframe = input.timeframe(defval = '15', title = '时间框架', options = ['5','15','30','60','D','W','M'], group = timeframeHeader) // 表格位置设置 tableLocationHeader = '=========表格位置===============' location = input.string(defval = '顶部', title = '表格位置', options = ['顶部', '中部','底部'], group = tableLocationHeader) tableLocation = location == '顶部' ? position.top_right : location == '中部' ? position.middle_right : position.bottom_right // 全局持久化表格 var table t = na // 打印表格函数 print_table() => if na(t) t := table.new(position = tableLocation, columns = 5, rows = array.size(results), border_width = 1, border_color = color.black) table.clear(t) table.set_row_count(t, array.size(results)) for i = 0 to array.size(results)-1 eachResult = array.get(results, i) bg_color = i == array.size(results)-1 ? color.yellow : color.new(color.yellow,80) table.cell(table_id = t, column = 0, row = i, text = str.tostring(eachResult.s), bgcolor = bg_color) table.cell(table_id = t, column = 1, row = i, text = eachResult.sym, bgcolor = bg_color) table.cell(table_id = t, column = 2, row = i, text = str.tostring(eachResult.ent), bgcolor = bg_color) table.cell(table_id = t, column = 3, row = i, text = eachResult.rsn, bgcolor = bg_color) table.cell(table_id = t, column = 4, row = i, text = eachResult.dt, bgcolor = bg_color) // 判断条件是否在指定K线范围内 inRange(cond) => rangeUpper = 60 rangeLower = 5 bars = ta.barssince(cond == true) not na(bars) and rangeLower <= bars and bars <= rangeUpper // RSI背离计算函数 calculate_rsi_div(symbol, timeperiod) => len = 14 src = request.security(symbol, timeperiod, close) lbR = 5 lbL = 5 osc = ta.rsi(src, len) plFound = not na(ta.pivotlow(osc, lbL, lbR)) phFound = not na(ta.pivothigh(osc, lbL, lbR)) entry_reason = "" // 常规看涨背离 oscHL = osc[lbR] > ta.valuewhen(plFound, osc[lbR], 1) and inRange(plFound[1]) priceLL = request.security(symbol, timeperiod, low[lbR]) < ta.valuewhen(plFound, request.security(symbol, timeperiod, low[lbR]), 1) bullCond = priceLL and oscHL and plFound // 隐藏看涨背离 oscLL = osc[lbR] < ta.valuewhen(plFound, osc[lbR], 1) and inRange(plFound[1]) priceHL = request.security(symbol, timeperiod, low[lbR]) > ta.valuewhen(plFound, request.security(symbol, timeperiod, low[lbR]), 1) hiddenBullCond = priceHL and oscLL and plFound // 常规看跌背离 oscLH = osc[lbR] < ta.valuewhen(phFound, osc[lbR], 1) and inRange(phFound[1]) priceHH = request.security(symbol, timeperiod, high[lbR]) > ta.valuewhen(phFound, request.security(symbol, timeperiod, high[lbR]), 1) bearCond = priceHH and oscLH and phFound // 隐藏看跌背离 oscHH = osc[lbR] > ta.valuewhen(phFound, osc[lbR], 1) and inRange(phFound[1]) priceLH = request.security(symbol, timeperiod, high[lbR]) < ta.valuewhen(phFound, request.security(symbol, timeperiod, high[lbR]), 1) hiddenBearCond = priceLH and oscHH and phFound if bullCond entry_reason := '看涨' else if hiddenBullCond entry_reason := '隐性看涨' else if bearCond entry_reason := '看跌' else if hiddenBearCond entry_reason := '隐性看跌' entryPrice = request.security(symbol, timeperiod, open, ignore_invalid_symbol = true) if bullCond or hiddenBullCond or bearCond or hiddenBearCond entry_time = str.format('{0,date,yyyy.MM.dd HH:mm:ss}', request.security(symbol, timeperiod, time_close)) resultNo += 1 ri = resultItem.new(resultNo, symbol, entryPrice, entry_reason, entry_time) array.push(results, ri) // 自选列表初始化 var array<string> symbolList = array.new_string() array.push(symbolList,'BINANCE:ADAUSDT') array.push(symbolList,'BINANCE:ATOMUSDT') array.push(symbolList,'BINANCE:BNBUSDT') array.push(symbolList,'BINANCE:BTCUSDT') array.push(symbolList,'BINANCE:CHRUSDT') array.push(symbolList,'BINANCE:COCOSUSDT') array.push(symbolList,'BINANCE:COTIUSDT') array.push(symbolList,'BINANCE:DGBUSDT') array.push(symbolList,'BINANCE:DOGEUSDT') array.push(symbolList,'BINANCE:EOSUSDT') // 仅在最后一根K线执行筛选和表格更新 if barstate.islast array.clear(results) // 清空旧结果 resultNo := 0 // 重置序号 if screenerStrategy1 // 遍历所有自选标的 for sym in symbolList calculate_rsi_div(sym, timeframe) // 处理结果数量变化 currentResultNo = array.size(results) if prevResultNo == 0 prevResultNo := currentResultNo else if currentResultNo - prevResultNo > 1 array.shift(results) prevResultNo := currentResultNo // 打印表格 print_table()
内容的提问来源于stack exchange,提问作者Partha Sarkar
相关产品推荐
相关产品推荐

