Pine Script笔记归档
1.简介
量化交易平台 TrendingView (opens new window)是一个支持多种资产的投资平台,很多人在上面分享对于股票,外汇,数据货币等资产的投资观点,难得的是在上面能找到很多人的交易策略。
TrendingView 使用的是自己开发的Pine 语言作为脚本,这一点和MT4 开发的mql4 很像。用户可以自己编写脚本和策略,并与其他人分享。Pine 直观给我的印象比Mql4 更加简单,更加关注于策略本身,而不是编程技巧。
此外,Pine语言编辑器没有那么强大的debug 功能,这对于一开始上手练习来说,不是那么方便。不过它一直在更新,发展的很快。
TrendingView 对接了很多经纪商,使得它支持的交易品种很丰富,而且它的图表功能很强大。
2.脚本结构
指明用的Pine 脚本版本
1 | //@version=4 |
Pine 可以分为study脚本 和 strategy 脚本(指标&策略) study 脚本必须包含 plot,plotshape,barcolor,line.new 等输出 strategy 脚本包含 strategy.* 即交易函数
3.换行
1 | //例子1 换行需要空格 |
4.运算符
算术: + - * / %
1
1/2 = 0 1/2.0 = 0.5
比较: == !=
逻辑: not and or
三元运算符:
1
2
3condition ? result1 : result2
iff(condition, result1, result2)
//有房?嫁:有车?: 嫁:帅?嫁: 不嫁
[] 运算符(History reference operator) close 代表最新的价格,close[1]代表了历史价格。
1 | close = close[0] //显示的是最新的收盘价 |
除此之外,Pine脚本里面还有一个变量 bar_index,记录着bar的数目,编号自左向右,从0开始。bar_index = (bar数量)N-1。
5.函数
Pine 脚本中包含了大量的自建函数,用户还可以自定义函数、
单行函数
1
f(x,y) => x+y
Pine Script 的函数不支持递归
即,不允许在函数中再次调用自己本身多行函数
1
2
3
4geom_average(x, y) =>
a = x*x
b = y*y
sqrt(a + b)- Pine Script 需要(一个Tab 或者4空格,TrendingView 会自动用4个空格来替换掉Tab)来划定函数的范围
- 最后一行的表达式或 变量作为函数的输出结果
5.1.函数的注意事项
当在函数块中使用函数或者历史数据信息的时候要注意。因为所使用的历史信息是每一次连续调用生成的。
如果函数并不是在每一根柱线上都调用,那么数据生成就会出现错误。
6.变量声明&语句statement
6.1.var
Pine 语言中变量定义的方式有两种: = 和 var
1
2
3
4
5a = 1 // a为整形
float a = 1 // a为浮点型
var a = 0
var int a = 0
b = na //出错变量定义的时候,需要指明变量的类型(或者 等式右侧表达式能指明类型亦可)
na 没有特定的类型,所以赋值时会出错var 关键词
var 是用于分配和一次性初始化变量的关键词。
不含var 关键词的变量在每次数据更新的时候都会覆盖变量的值。使用了var 关键词的变量,在数据更新中,可以“保持状态”。 举例
1 | //@version=4 |
变量 ‘a’ 保持系列中每个柱线的第一根柱线的收盘价。
变量 ‘b’保持系列中第一个“绿色”价格棒的收盘价。
变量 ‘c’保持系列中第十个“绿色”条的收盘价。
即a,b,c 都是一个常数。
去除var 的话,a,b,c 会随着价格变化而变化
6.2.if语句
1 | // This code compiles |
需要注意的是,与python不同,Pine要求,then 和 else语句返回的值的类型是相同的。在上面的第二个例子中,close 和 “open” 一个是float Series,另一个是string,不同类型的话,编译会出错。
1 | x = if close > open |
if 语句中可以忽略else,但是系统会默认赋值(na,false,””)
6.3.for语句
1 | for i = 1 to length-1 |
7.执行模型
Pine代码是根据价格信息计算的。但是价格信息并不是完整加载的,用户可以一直向左滑动图表,直到最早的一根柱子(Pro 用户可以在图表上加载10000左右,免费用户可以加载5000根柱子)
8.实时数据的计算
Pine指标计算实时数据的时候和计算历史数据略有不同,因为实时数据会有addtional commit(?)和rollback action(?)
在实时数据的处理过程中,柱线的每一次变动都会引起Pine 指标的计算
rollback : 在每一根柱线更新时发生
commit : 在每一根柱线关闭时发生
对于判断柱线的状态,Pine中有一系列的自建函数 barstate.* 来显示当前柱线的状态。
9.Context switching and the security function
security 函数可以用于按照特定要求请求数据
1 | //@version=4 |
- symbol (string)商品代码。
商品代码可以包含数据提供商信息,也可以不含
如 “NYSE:IBM”,”BATS:IBM”,”IBM”(如不提供,默认使用BATS)
syminfo.ticker (opens new window)and syminfo.tickerid (opens new window)是表示当前图标上的商品代码,syminfo.ticker是不含数据供应商信息,syminfo.tickerid是包含供应商信息。Pine教程建议使用后者,为了避免数据的模糊性
resolution (string)分辨率/timeframe时间周期
- 分钟级:1,5,10,21,60,120,等等
- 日级: D,1D,2D 等等
- 周级:W,1W,2W
- 月级:M,1M,2M
- timeframe.period 记录当前图标时间周期
expression (series)计数并从 security (opens new window)调用返回的表达式。
如果仅仅是获取收盘价数据,我们可以用security('EURUSD','D',close)
但是,expression能给我们提供更加丰富的操作,比如,我们需要知道,EURUSD相对于GBPUSD 上涨的幅度
1 | //@version=4 |
在security数据应用到当前图表上的时候,有两个控制,一个是gaps,另一个是lookahead
gaps (const bool)默认值为barmerge.gaps_off (opens new window)。可以理解为数据平滑的操作,因为数据中会存在空值(na),在gaps_off的情况下,na会被离它最近的非空值所替代,也就不会出现间隔(gap)的情况
lookahead (const bool)默认值为barmerge.lookahead_off (opens new window)。
合并所请求数据位置的策略。 请求的条形图与当前的条形图按照k线开盘时间合并。 这种合并策略可能导致从“未来”获取数据计算历史的不良影响。 这在回溯测试策略中不被接受,但在指标中可使用。1
2
3
4
5
6//@version=4
study('My Script', overlay=true)
a = security(syminfo.tickerid, '60', low, lookahead=barmerge.lookahead_off)
plot(a, color=color.red)
b = security(syminfo.tickerid, '60', low, lookahead=barmerge.lookahead_on)
plot(b, color=color.lime)
10.bar state.* 变量
barstate.isfirst 当前k线为k线组的第一条k线
barstate.islast 当前k线为k线组的最后一条k线
barstate.ishistory 当前k线为历史k线
batstate.isrealtime 当前k线为实时k线
barstate.isnew 新K线的第一次更新
batstate.isconfirmed =当前k线的最后(关闭)更新
不建议在security (opens new window)表达式中使用barstate.isconfirmed
所有的历史柱线都曾被认为是新的柱线,因为脚本是依次执行的。当柱线第一更开盘价生成的时候,认为此柱线是新的。
11.会话和时间信息
Pine 提供方法来生成 交易区间,时间和日期的信息。
time(变量): 返回的是时间戳格式
time(函数):time(resolution, session) → series 返回的是按照session 格式返回的时间,如果不在session时间段的话便会返回na值
1 | //@version=4 |
交易区间的格式有:
- 0000-0000:1234567 24小时交易,时间从午夜0点开始
- 0000-0000:23456 工作日24小时交易
- 1700-1700:24小时交易,时间从17点开始
- 0930-1700:146 交易时间为09:30~17:00,交易时间在周日(1),周三(4),周五(6)
- 24x7 等价于 0000-0000:1234567
1
2
3
4
5
6
7// 判断是否为30min的新柱线
//@version=4
study("new 30 min bar")
is_newbar(res) =>
t = time(res)
not na(t) and (na(t[1]) or t > t[1])
plot(is_newbar("30") ? 1 : 0)
用到的函数变量和类型:
- time:UNIX格式的当前k线时间
- timenow:UNIX格式的当前时间
- syminfo.timezone:时区
当前K线用到的变量:
- year/month/weekofyear
- dayofmonth
- dayofweek(sunday,monday 等)
- hour/minute/secondzh
创建时间:
12.策略编写
12.1backtesting & forwardtesting
strategy脚本是可以产生交易订单的Pine 脚本。利用strategy 可以做策略回测(backtesting)和 模拟交易(forwardtesting)
无论backtesting 还是forwardtesting,计算都是默认发生在K线收盘的时候,但是在forwardtesting 的时候,可以选择在每一个tick发生的时候,都运行一次。
做法一是调整strategy的 Setting/Properties,或者修改代码,添加strategy(... ,calc_on_every_tick=true )
,此外还可以选择在每笔订单完成之后计算strategy(... , calc_on_order_fills=true)
12.2.经纪商模拟
仅仅只有OHLC数据的话,K线内数据的生成有一套逻辑,如果最高价更接近开盘价,生成顺序是 open->high->low->close,此外还假设价格是没有gaps的
12.3.订单生成命令
12.3.1.strategy.entry 订单生成函数
这是进入市场的命令。 如果具有相同ID的订单已经挂起,则可修改订单。 如果没有指定ID的订单,则会发出新的订单。
要取消/停用预挂单,应使用命令strategy.cancel (opens new window)或strategy.cancel_all (opens new window)。
与函数strategy.order (opens new window)相比,strategy.entry (opens new window)功能受金字塔影响,可以正确反转市场位置。 如果“Limit”和“stop”参数均为“NaN”,则订单类型为市场订单。
1 | strategy.entry(id, long, qty, limit, stop, oca_name, oca_type, comment, when) → void |
12.3.2.strategy.exit 订单退出函数
1 | strategy.exit(id, from_entry, qty, qty_percent, profit, limit, loss, stop, trail_price, trail_points, trail_offset, oca_name, comment, when) → void |
这是一个退出指定进场或整个市场地位的命令,重点区分它和strategy.close 的不同
- id(string): 订单的标识符。
- from_entry(string): 这里填入要平仓的订单的标识符,默认为空。
- qty: 平仓手数(弄清楚合约的大小)
- qty_percent: 平台的比例
- profit: 获利点数(一定搞清楚单位是点还是步)
- limit: 与profit 相似,limit约定获利的价格
- loss:止损点数
- stop:与loss 相似,stop约定止损的价格
- tail.*: 指明跟踪指数
12.3.3.strategy.order
这条命令可以生成开仓也可以生成平仓命令,但是它不受金字塔影响。它的作用就是弥补strategy.entry 和 strategy.exit 函数的不灵活性。
12.4.风险管理
strategy.risk.* 一系列函数,可以帮助进行风险管理。当风险管理规则被激活的时候,没有订单会生成。
1 | //@version=4 |
- strategy.risk.max_intraday_filled_orders(2)
限制一天成交的最大的交易单数,一旦达到,所有未成交订单全部取消,成交订单关闭。并且一直关闭交易直到本交易日结束。
13.指标重绘
历史数据仅仅包含OHLC,不包含线内的运动。这会导致的问题是,历史数据上的回测和实时数据不一致的情况。
另外一个担心是,未来函数的使用。这里尤其要关注security 函数,此函数可能会错误的引入未来的信息。
14.绘图
Pine V4 中存在两种绘图类型:label 和 line。
注:用户的绘图和 编程绘图是不一样的,编程得到的绘图是不能用鼠标修改的。
和指标绘图函数(plot,plotshape,plotchar) 不一样的是,绘图函数可以在图表右侧没有K线的地方。
14.1.label
1 | label.new(x, y, text, xloc, yloc, color, style, textcolor, size) → series[label] |
1 | //@version=4 |
x的位置是用bar_index 标识的,此时xloc 的默认值为xloc.barindex
y的位置是最高价
xloc取值:xloc.bar_index(默认) 和 xloc.bar_time
yloc取值:
- yloc.price 传入此函数,需要输入y值
- yloc.abovebar,yloc.belowbar 启动时,y值会失效。标签在图表上部或者下部
style: 很多种,可能用到比较多的有label.style_none,无底色
14.2.line
1 | line.new(x1, y1, x2, y2, xloc, extend, color, style, width) → series[line] |
- extend: extend.none/extend.right/extend.left