我目前正在将ThinkScript指示器转换为C#,但是,我遇到了这个CompoundValue
函数,并且不确定如何隐蔽它。
文档显示为:
根据以下规则计算复合值: 如果数字大于长度,则返回可见数据值, 否则,返回历史数据值。使用此功能 用递归初始化研究。
示例用法:
declare lower;
def x = CompoundValue(2, x[1] + x[2], 1);
plot FibonacciNumbers = x;
我的解释:
基于描述和示例。看来我们正在x[1] + x[2]
中传递计算,并且它在当前柱和上一个柱上执行此计算(基于2
的第一个参数)。我不确定参数1
的用途。
我的问题:
请解释该功能的实际作用。如有可能,请使用伪代码说明此方法的工作原理。
答案 0 :(得分:1)
请让我在thinkscript本身中提供两个等效的代码工作版本。我们通过相互减去等效输出来证明等效性-结果应该为0。
# The original Fibonacci code with a parameter "length" added.
# That parameter is the first parameter of the CompoundValue function.
declare lower;
def length = 2;
def x = CompoundValue(length, x[1] + x[2], 1);
# plot FibonacciNumbers = x;
# Equivalent code using the `if` statement:
def y;
if(BarNumber() > length){
# Visible data. This is within the guarded branch of the if statement.
# Historical data y[1] (1 bar back) and y[2] (2 bars back) is available
y = y[1] + y[2];
}else{
# Not enough historical data so we use the special case satisfying the
# original rule.
y = 1;
}
plot FibonacciNumbersDiff = y - x;
思维脚本“递归”是一个有点夸张的术语。函数名称CompoundValue
并不是很有帮助,因此可能会造成混乱。
使用if
语句的版本通常更有用,因为在遍历时间条形时,我们通常需要一个带有多个嵌套if
语句的程序结构-这不能通过CompoundValue
功能。请参阅我在扫描环境中利用此功能的其他文章。
在Java中,使用相同的结构,如下所示:
int size = 100;
int length = 2;
int[] values = new int[size];
for(int index = 1; index < size; index++){
if(index > length){
values[index] = values[index - 1] + values[index - 2];
}else{
values[index] = 1;
}
}
基本区别是for
循环,它在thinkscript代码中不存在。 thinkscript提供了一种控制反转形式的循环,其中它多次执行用户代码,每条执行一次。
答案 1 :(得分:1)
对于 TLDR;人群,一些简单的代码,希望能解释 CompoundValue()
函数试图做什么,这可能有助于转换它的功能:
# from: Chapter 12. Past/Future Offset and Prefetch
# https://tlc.thinkorswim.com/center/reference/thinkScript/tutorials/Advanced/Chapter-12---Past-Offset-and-Prefetch
# According to this tutorial, thinkScript uses the highest offset, overriding
# all lower offsets in the script - WOW
declare lower;
# recursive addition using x[1] is overridden by 11 in the plot for
# Average(close, 11) below; SO `x = x[1] + 1` becomes `x = x[11] + 1`
def x = x[1] + 1;
# using CompoundValue, though, we can force the use of the *desired* value
# arguments are:
# - length: the number of bars for this variable's offset (`1` here)
# - "visible data": value to use IF VALUES EXIST for a bar (a calculation here)
# - "historical data": value to use IF NO VALUE EXISTS for a bar (`1` here)
def y = CompoundValue(1, y[1] + 1, 1);
# *plotting* this Average statement will change ALL offsets to 11!
plot Average11 = Average(close, 11);
# `def`ing the offset DOES NOT change other offsets, so no issue here
# (if the `def` setup DID change the offsets, then `x[1]` would
# become `x[14]`, as 14 is higher than 11. However, `x[1]` doesn't change.
def Average14 = Average(close, 14);
plot myline = x;
plot myline2 = y;
# add some labels to tell us what thinkScript calculated
def numBars = HighestAll(BarNumber());
AddLabel(yes, "# Bars on Chart: " + numBars, Color.YELLOW);
AddLabel(yes, "x @ bar 1: " + GetValue(x, numBars), Color.ORANGE);
AddLabel(yes, "x @ bar " + numBars + ": " + x, Color.ORANGE);
AddLabel(yes, "y @ bar 1: " + GetValue(y, numBars), Color.LIGHT_ORANGE);
AddLabel(yes, "y @ bar " + numBars + ": " + y, Color.ORANGE);
现在,一些,呃,很多细节......
首先,关于“偏移”值的快速说明:
thinkScript 与其他交易相关语言一样,使用内部循环系统。这就像一个 for
循环,遍历图表上的所有“周期”或“柱”(例如,1 柱 = 日线图上的 1 天;1 柱 = 1 分钟日内图表上的 1 分钟,等等)。 thinkScript 中的每一行代码都针对每个柱形或脚本中指定的时间长度运行。
正如 OP 所指出的,x[1]
表示循环正在处理的当前柱线之前一个柱线的偏移量。 x[2]
代表当前柱之前的两个柱,依此类推。此外,可以使用负数抵消未来:例如,x[-1]
表示当前柱线超前一个柱线。
这些偏移的工作方式与 C# 中的 for
循环类似,只是它们是向后的:C# 中的 x[0]
表示当前的 x
值,就像在 thinkScript 中一样;但是,在循环中向前移动,x[1]
将是 next 值,而 x[-1]
将不存在,因为在 0 之前没有过去的值。(在一般,当然!在 C# 中绝对可以使用负数循环。重点是 thinkScript 中的正偏移索引代表 过去 柱,而 thinkScript 中的负偏移索引代表 未来条形 - 在 C# 中不是这种情况。)
“长度”的概念在这里也很重要:在 thinkScript 中,length
参数表示您想要走的距离 - 就像偏移量一样,但是一个范围而不是一个特定的条形。在我上面的示例代码中,我使用了语句 plot Average11 = Average(close, 11);
在这种情况下,11
参数表示绘制 11 根柱线的收盘价,即偏移量 x[0]
到 {{1} }.
现在,解释CompoundValue() 函数的用途:
Chapter 12. Past/Future Offset and Prefetch thinkScript 教程解释了 thinkScript 实际上覆盖较小的偏移量或长度值,并具有脚本中的最高值。这意味着如果你有两个项目定义如下:
x[10]
thinkScript 实际上会用在 Average 语句中使用的更长的长度覆盖 def x = x[1] + 1;
plot Average11 = Average(close, 11);
偏移量 - 因此导致 x[1]
变成 x[1]
!
哎呀!这意味着指定的偏移量,除了最高偏移量,对 thinkScript 没有任何意义!那么,等一下 - 是否有人 必须 对所有内容使用所有相同的偏移量,然后呢?不!这就是 CompoundValue() 的用武之地...
同一章解释了 CompoundValue() 允许为变量指定偏移量即使存在更高的偏移量也不会改变。
带有参数标签的 CompoundValue() 函数如下所示:
x[11]
正如 OP 所指出的,这并不是特别清楚。以下是参数代表的含义:
length:此变量的柱形偏移量。
在我们的示例 CompoundValue(length, "visible data", "historical data")
中,有 1 个柱的偏移量,因此我们的语句以 def x = x[1] + 1
开头。如果相反,它是一个更大的偏移量,比如 14 个柱,我们会放 CompoundValue(length=1, ...)
“可见数据”:thinkScript 应该执行的值或计算如果当前柱的数据可用。
同样,在我们的示例中,我们使用 CompoundValue(length=14, ...)
的计算,所以 x[1] + 1
。 (等式周围的括号不是必需的,但可能有助于清晰。)
“历史数据”:如果当前柱没有可用数据时使用的值。
在我们的示例中,如果没有可用数据,我们将使用值 CompoundValue(length=1, "visible data"=(x[1] + 1), ...)
。
现在,在 thinkScript 中,如果参数按顺序排列和/或提供了默认值,则不需要参数标签。所以,我们可以像这样编写这个 CompoundValue 语句,没有标签:
1
或者像这样带有标签:
def y = CompoundValue(1, y[1] + 1, 1);
(请注意,包含空格的参数名称必须用双引号括起来。单字参数名称不需要引号。另外,为了清楚起见,我在等式周围放置了括号;这不是必填。)
总结:需要 CompoundValue(...) 以确保变量使用系统 (thinkScript) 中实际所需的偏移量/柱线数量,否则覆盖指定的偏移量(如果存在)具有更高的数字。
如果脚本中的所有偏移量都相同,或者使用不同的编程系统,则 CompoundValue() 可以简单地分解为适当的计算或值,例如 def y = CompoundValue(length=1, "visible data"=(y[1] + 1), "historical data"=1);
或者,一个 def x = x[1] + 1
语句,在任何需要的柱线或条件下填充所需的值。