e(“rb888”) # 获取本次轮询的时间戳,即一个毫秒的时间戳。用来确定写入到图表的X轴的位置 now_time = int(time.time() * 1000) # 获取行情数据 r = exchange.GetRecords() # 五日均线 ave_5 = TA.MA(r, 5) # 十日均线 ave_10 = TA.MA(r, 10) # 用时间戳作为 X 值,均价作为 Y 值传入索引 0 的数据序列 obj_chart.add(0, [now_time, ave_5[-1]]) # 同上 obj_chart.add(1, [now_time, ave_10[-1]])
首先,通过```Chart(chart)```函数初始化了一个图表对象ObjChart,其中chart是一个选项配置对象,用于配置图表的各项属性。然后,通过```obj_chart.reset()```函数清空了图表中已经存在的数据。接下来,通过一个无限循环```while True```来实现不断获取并更新行情数据。在每次循环中,调用```exchange.GetRecords()```函数获取当前品种的K线行情数据,并用```TA.MA()```计算出五日和十日均线的值。
然后,通过```int(time.time() * 1000)```获取当前时间戳作为X值,将五日和十日均线的值作为Y值,调用```obj_chart.add()```函数把这些数据加入到图表中。其中,第一个参数0和1分别对应了选项配置对象中的两个数据序列,即五日均线和十日均线。第二个参数是一个包含X值(也就是时间)和Y值(就是最新时刻的均线值)的数组。
总之,这段代码通过数据配置对象和选项配置对象来定义图表,然后不断获取K线数据,计算均线,将计算结果添加到图表上,最终实现了两条均线的效果。
![image](https://www.youquant.com![img](/upload/asset/2b06ea2c9caab99c02e96.png))
### 4.6.5 KLineChart()
使用 Python 编写策略时,设计策略图表的显示是非常重要的。对编程不熟练或者对优宽量化平台使用的图表库不熟悉的小伙伴,经常会苦恼于自定义图表上画图的代码设计。我们在上个阶段,使用Chart函数进行图表设置的时候,在图表参数设置,数据导入等阶段,都需要编写复杂的代码。那么有没有一种画图方法,结构更加清晰,而且只用编写少量的代码,又可以画出丰富内容的策略图表呢?
Pine语言相信大家都听说过,它是一门高度封装的专门为交易而生的语言。Pine语言有丰富画图功能,它的画图方式非常的简单,并且功能也十分的强大。如果可以把Pine语言的画图接口接入到Python语言的策略中进行使用,那么就极大得方便了我们设计策略的画图功能。于是优宽量化平台基于这种需求,升级了自定义画图功能,扩展了使用`KLineChart`函数进行自定义图表画图的方式。大家可以对比一下chart函数,`KLineChart`对于编程基础薄弱的我们,确实是一个更为友好地选择。
```Python
def main():
c = KLineChart()
while True:
if exchange.IO("status"):
exchange.SetContractType("rb888")
bars = exchange.GetRecords()
if not bars:
Sleep(1000)
continue
for bar in bars:
c.begin(bar)
c.plot(bar.Volume, "volume")
c.close()
Sleep(1000)
话不多说,让我们来尝试一下。可以看到下面的代码,相对于chart函数需要先设置一系列选项和参数的配置选项的图表对象,KLineChart非常简单和直观。你只需要在主函数中调用KLineChart()
函数创建一个图表对象c就可以了。接着,你可以利用while循环不断地获取交易数据并绘制图表。
画图操作要从begin()
函数开始,close()
函数结束。begin、close函数都是图表对象的方法。我们还使用plot()
方法将成交量指标画在图表上。其中,第一个参数bar.Volume
表示成交量数据,第二个参数 volume 表示成交量指标的名称。在这个例子中,我们只绘制了一个成交量指标,但是你可以通过添加更多的plot方法来绘制其他的指标线。
最后,通过Sleep函数设置程序每隔1秒钟执行一次,以保证实时更新数据。我们看一下回测结果,可以看到,交易量图表呈现了出来。总之,利用KLineChart
函数,我们可以在不编写复杂的代码的情况下,轻松地创建自定义的策略图表。
函数KLineChart()
支持指标的主图和副图呈现,在具体指标画图函数里,需要添加参数overlay = True/False
,当设置为True
的时候,指标会同时呈现在主图上,否则会设置在副图上,可以可以更清晰的进行指标的呈现。与Chart
函数相比,KLineChart
更加简单、直观,也更加强大,支持绘制多种图形和指标线。需要注意的是策略自定义画图只能使用KLineChart()
方式或者Chart()
方式中的一种。
日志清除函数,该函数可以清除实盘或者模拟盘时实盘的日志数据。可以传入一个参数,指定保留最近多少条日志,清除其它日志。
def main():
LogReset(10)
打开或者关闭订单信息的日志记录。参数值:isEnable
为bool类型。IsEnable
设置为false则不打印订单日志,不写入实盘数据库。
def main():
EnableLog(False)
作为一个成熟的量化交易软件,优宽量化提供了很多方便易用的内置函数,节省了不少开发应用的时间,这里主要介绍常用内置函数及其用法。
Sleep()
函数在商品期货策略中使用并不是很多,由于商品期货行情是推送机制,并不需要在策略程序中使用Sleep()
函数强制等待一定时间,只需在必要的地方使用,例如在检测和期货公司前置机连接状态时(调用exchange.IO("status")
函数)使用Sleep()
函数,避免循环中无耗时引起设备CPU占用过高。Sleep()
函数的参数为毫秒数。
获取策略交互界面发来的命令并清空,没有命令则返回null,返回的命令格式为“按钮名称:参数”,如果没有参数,则命令就是按钮名称。
GetCommand()
函数是一个非常重要的函数,策略的交互设计依赖于此函数。后面我们将在策略优化中使用实例进行具体讲解。
IsVirtual()
函数用来判断当前策略运行为机器人运行还是回测运行。回测系统运行返回true,实盘或者模拟盘机器人运行返回false。
def main():
while True:
if exchange.IO("status"):
exchange.SetContractType("MA888") # 返回True
exchange.GetTicker()
LogStatus(_D(), "已经连接", "IsVirtual():", IsVirtual())
else:
LogStatus(_D(), "未连接", "IsVirtual():", IsVirtual())
Sleep(1000)
可以看到策略回测时,状态栏上打印的IsVirtual()
函数返回值为True。
可保存的全局字典,回测和实盘均支持,回测结束后,保存的数据被清除。KV表,永久保存在本地文件,每个机器人单独一个数据库,重启或者托管者退出后一直存在,K必须为字符串,不区分大小写,V可以为任何可以JSON序列化的内容。后面我们将在策略优化中使用实例进行具体讲解。
_D(Timestamp,Fmt)
函数在策略编写时也是经常用到的,例如打印当前时间字符串,就可以直接写作:Log(_D())
。参数值:Timestamp为数值类型,Fmt为string类型,Fmt默认为:yyyy-MM-dd hh:mm:ss
,返回值:string类型。
注意:不传任何参数就返回当前时间,例如:_D()
,传入参数_D(1478570053)
,返回指定时间戳的字符串,默认格式为yyyy-MM-dd hh:mm:ss
。
在使用Python编写策略时需要注意,Timestamp参数为秒级别时间戳。其它语言调用该函数时,Timestamp参数为毫秒级别时间戳。
_N(Num, Precision)
,格式化一个浮点数。参数Num为number类型,Precision为整型number。返回值:number类型。例如:_N(3.1415, 2)
返回3.14。
该函数会一直调用指定函数到成功返回,比如_C(exchange.GetTicker)
,默认重试间隔为3秒,可以调用_CDelay(...)
函数来控制重试间隔,比如_CDelay(1000)
,指改变_C
函数重试间隔为1秒。
注意:_C
函数可以对下面的函数进行容错调用。
def main():
ticker = _C(exchange.GetTicker)
_CDelay(2000)
depth = _C(exchange.GetDepth)
Log(ticker)
Log(depth)
对于有参数的函数,使用_C(...)
容错时:
def main():
records = _C(exchange.GetRecords, PERIOD_D1)
Log(records)
Cross函数可以判断2个数组的交叉状态,返回数组arr1与arr2的交叉周期数。正数为上穿周期,负数表示下穿的周期,0指当前价格一样。它需要传入两个参数,并且这两个参数都必须是数组。在实际应用中,这个函数可以很方便判断两条均线是否金叉死叉。
arr1 = [1,2,3,4,5,6,8,8,9]
arr2 = [2,3,4,5,6,7,7,7,7]
def main():
Log("_Cross(arr1, arr2): ", _Cross(arr1, arr2)) # 3
Log("_Cross(arr2, arr1): ", _Cross(arr2, arr1)) # -3
可以看到_Cross(arr1, arr2)
返回4,从序列中可以观察到,arr1上穿arr2已经3个BAR(倒数第3个位置”8>7“),所以返回3;与此相反,arr2下穿arr1已经3个BAR,返回-3。
技术指标是以原始数据(开盘价、最高价、最低价、收盘价、成交量等)为基础,通过一定的数学计算得出的结果。优宽量化把常用的技术指标封装成一个个函数,编写策略时无须重新计算,从而提高策略开发效率。
优宽量化 TA 指标库,优化了常用指标算法,支持 JavaScript、Python、C++。源码地址:https://www.youquant.com/bbs-topic/409。TA 库指标函数使用非常简单,以 TA.KDJ
指标为例:
def main():
exchange.SetContractType('rb888')
r = exchange.GetRecords(PERIOD_M15)
kdj = TA.KDJ(r, 9, 3, 3)
Log("k:", kdj[0][-1], "d:", kdj[1][-1], "j:", kdj[2][-1]) # k: 18.870677786625926 d: 38.1501384991229 j: -19.68824363836803
参数为 K 线数据,指标参数。因为 KDJ 指标是一个二维数组,所以这里我们首先第一维定义不同的指标,第二维选择具体的时刻,可以看到返回结果为最新的指标数据。
返回的指标数据根据不同指标有所不同。MACD,KDJ 这类多线组成的指标,指标数据是一个二维数组。RSI,ATR,MA 这类指标是一条线,返回的是一维数组。
与 TA 指标库类似,talib 指标库有众多交易指标,不过在使用之前需要首先进行引用。具体包含的指标可到进行查询优宽量化语法手册。
import talib
def main():
exchange.SetContractType('rb888')
records = exchange.GetRecords()
ret = talib.MACD(records.Close)
Log("dif:", ret[0][-1], "dea:", ret[1][-1], "macd:", ret[2][-1]) # dif: -71.44652041129393 dea: -46.58286138984912 macd: -24.86365902144481
俗话说站在巨人肩膀上,才能看得更远。有时候你想费尽精力实现一个功能,可能早已有极好的解决方法,如果可以用现成的,那么节省下来的时间是不是可以用在策略逻辑上呢?内置模板类库提供了大量的可复用的代码模块。
优宽量化交易平台支持把一些常用的、可复用的代码模块封装成独立的库(在优宽量化交易平台上叫做模板类库)。这样可以提高策略开发速度,不用编写重复的代码,降低策略交易部分和策略逻辑部分的耦合度,便于策略维护、优化、扩展。
创建一个模板类库和创建一个策略操作相同,在「策略库」中点击「新建策略」跳转到创建策略页面,区别是策略类型选择「模板类库」。然后给模板起个名字,保存即可。模板类库设计主要有两个方面:第一是需要设计导出函数,导出函数为模板类库的接口函数,即这个模板类库提供哪些功能,通过调用导出函数去使用这个模板类库提供的功能。第二是需要设计这个模板类库的参数,和普通策略一样,模板类库也可以设置参数,用于使用时动态设置一些数值等参数数据。
画线类库简化了策略图表画线的逻辑,使其更加简便易用。使用这个类库,可以直接调用封装好的函数来绘制图表上的各种线条。
主要特点包括:
这个类库的出现大大简化了策略编写过程中对图表的处理,使得开发者能够更加专注于策略逻辑的实现,提高了编程效率。
这里我们举例双均线画图的例子,ext.PlotLine
函数是 Python 版画线类库的画线函数, 用来在图表上画出一条曲线。
ext.PlotRecords
函数是画出 K 线,通过订阅合约,获取K线,计算均线,然后我们使用画线类库分别进行K线图,两条均线的画图。
def main():
while True:
exchange.SetContractType("MA888")
r = exchange.GetRecords()
if len(r) < 10 :
continue
ma1 = TA.MA(r, 5)
ma2 = TA.MA(r, 10)
Log("五周期均线", ma1[len(ma1)-1], '#FF0000')
Log("十周期均线", ma2[len(ma2)-1], '#00FF00')
ext.PlotRecords(r, "RB")
ext.PlotLine("五周期均线",ma1[len(ma1)-1])
ext.PlotLine("十周期均线",ma2[len(ma2)-1])
Sleep(1000 * 60 * 60)
Python 版商品期货交易类库,这个模板类库移植自优宽量化交易平台 JavaScript 版商品期货交易类库。 主要功能是对于商品期货交易开仓平仓的操作。 可以学习该模板的设计思路,模板地址: https://www.youquant.com/strategy/24288
在量化交易中,时间是至关重要的,因为市场瞬息万变。一个好的交易函数可以快速响应市场信号并执行交易操作,从而提高交易的效率和准确性。为了实现这一目标,优宽量化平台封装了一些常用功能,例如开仓平仓、CTA函数、判断交叉等,并推出了实盘交易类库,方便进行交易的操作。通过使用交易类库,大家可以从繁琐的交易参数设置细节中解脱出来,更加专注于策略本身的编写,提升策略的执行效率。交易类库的使用方法很简单,作为一个内置的模版类库,大家可以直接勾选使用。当然如果大家想更好的构建自己的交易类库,也可以从这个公开的类库源码开始,这份代码附有注释,大家都可以参考学习下。今天我们介绍下这个交易类库的使用方法。
首先我们介绍一下CTA函数。它相当于一个策略编写的整体框架。CTA函数用于实现基于交易所行情和持仓信息的自动交易策略。该函数可以根据一系列设定的规则和条件执行买入和卖出操作。该函数接受三个参数:contractType(合约类型)、onTick(回调函数)和interval(轮询间隔)。
这里面我们讲一下onTick(st),它是一个回调函数。当每次获取到行情时会调用该函数。回调函数接收一个包含以下属性的对象作为参数:
这里的回调函数应返回一个整数,表示需要执行的买卖操作数量,大于0表示买入,小于0表示卖出,等于0表示不进行任何操作。
def main():
# 测试CTA函数
def callBack_CTA(st):
if len(st["records"]) < 20:
return
emaSlow = TA.EMA(st["records"], 20)
emaFast = TA.EMA(st["records"], 5)
cross = ext.Cross(emaFast, emaSlow)
if st["position"]["amount"] <= 0 and cross > 2:
Log("金叉周期", cross, "当前持仓:", st["position"])
return 2 if st["position"]["amount"] < 0 else 1
elif st["position"]["amount"] >= 0 and cross < -2:
Log("死叉周期", cross, "当前持仓:", st["position"])
return -2 if st["position"]["amount"] > 0 else -1
ret = ext.CTA("FG888", callBack_CTA)
这样讲解可能不太直观,我们举例示范一下。这是使用CTA库来进行金叉和死叉信号进行交易的例子。首先,调用了$.CTA
函数,参数为玻璃主力期货合约,和一个回调函数。在我们的回测测试中,经常使用期货代码+888
,表示该品种的主力合约,如果我们不使用交易类库,直接将期货888代码,带入实盘运行,会出现找不到该合约的错误提示。交易类库经过内置函数的映射,可以直接匹配888代码,为当前策略周期具体的主力合约代码。另外,CTA函数也可以映射到别的合约,如果我们设置i000/rb888
,就是根据铁矿石的指数的K线,来交易螺纹钢的主力连续。另外,不同的主力合约是有一定的期限的,在策略运行的过程中,为确保策略长期的平稳运行,经常需要对主力合约进行更换。为解决移仓换月的麻烦,交易类库内置添加了,主力合约的自动移仓功能。
通过源码中可以看到,st包含了期货合约的综合数据,包括k线,账户和仓位等信息。通过st.records.length
判断市场数据的记录数量是否大于等于20,如果不满足条件,则直接返回,不进行后续的逻辑判断和操作。如果市场数据记录数量满足要求,接下来使用TA.EMA
函数计算了慢速(20周期)和快速(5周期)的指数移动平均线(EMA)。
通过$.Cross
函数判断快速EMA和慢速EMA是否发生交叉。cross
函数中需要两个数组进行交叉信号的判断,返回结果是上穿的周期数。正数为上穿周数,负数表示下穿的周数,0指当前价格一样。这里为了防止最新的k线没有走完,所以我们设定的阈值绝对值为2。如果快速EMA大于慢速EMA的时候交叉值大于2,则表示发生了金叉;如果快速EMA小于慢速EMA的时候交叉值小于-2,则表示发生了死叉。
大家也许会好奇,没有常规的开仓或者平仓语句,交易是怎样进行的呢,其实这就是我们刚才提到的return返回值进行下单。根据当前持仓情况和交叉的方向,通过return语句针对仓位进行不同的交易操作。CTA函数中交易的操作是通过return语句开展的,交易操作参数为n。如果当前持有的仓位st["position"]["amount"]
为0,n就直接代表着开多(n为正)或者开空(n为负)的手数。如果当前的仓位st["position"]["amount"]
不是0,进行的交易操作需要和持有的仓位进行比较,然后进行开平仓的操作。我们举例讲解下,比如现在st["position"]["amount"]
为-3,代表持有三手的空仓,如果这时候n为2,就意味着需要平掉2手的空仓,还剩下1手的空仓不进行操作;而如果n为4,则代表需要全部平掉3手的空仓,然后再开一手多仓。所以在本例中,我们使用的就是这样的方法来进行对应开平仓的操作。这里面的逻辑确实有点复杂,大家可以去源码中进行查阅,加深一下理解。
在我们的例子中,策略的开平仓的逻辑是这样的,针对于金叉,如果当前仓位是空头或者没有的仓位,st["position"]["amount"]
小于等于0,这个时候需要进行不同的交易操作。这里使用了一个三元表达式,如果是空头仓位(st["position"]["amount"]
小于0),金叉出现应该首先平掉空仓,然后开一手多仓,所以这里的数字要填写为2;如果没有仓位(st["position"]["amount"]
等于0),对应的数字是1,就是直接开一手多头仓位。针对于死叉也是一样,具有多头仓位的时候,首先需要平掉多头,然后再开一手空仓,数字填写为-2;没有仓位,直接开一手空头,填写数字为-1。
我们看一下回测结果,可以看到伴随金叉和死叉指标,多头和空头不断的对调开平仓,符合策略的交易逻辑。另外,CTA还很贴心的为我们添加了状态栏的展示,可以看到这里包括持仓状态和账户信息,方便实时了解策略的运行状态。状态栏的展示是使用LogStatus
函数设置的,后面会为大家进行讲解。
除此之外,CTA函数还可以进行多品种的操作,这里我们设置参数为三个品种,FG888,MA888,SA888
,注意品种之间不要有空格。可以看到这个策略对着三个品种实时运行了起来,状态栏可以实时显示这三个品种的持仓状态和盈亏。总体来说,这段代码使用了CTA函数进行了简单的均线交叉策略的编写,希望从这个例子中,大家可以学习认识下CTA函数。
交易类库具有2种模式,第一种是针对单品种的操作:
obj = ext.NewPositionManager()
这里的obj为创建的单品种控制对象。请注意哈,这里的单品种操作不是指的是只能针对于单一的期货品种,而是按顺序的操作。
通过使用NewPositionManager
对象提供的方法,可以方便地管理仓位和进行交易操作。可以传入一个可选的参数e,表示交易所对象,如果没有传入该参数,则默认使用当前交易所对象(exchange)。创建NewPositionManager
对象后,可以使用其提供的方法进行仓位和交易管理。
def main():
# 测试 IsTrading
Log("now time", _D(), "isTrading('MA405'): ", ext.IsTrading("MA405"))
Log("now time", _D(), "isTrading('SR405'): ", ext.IsTrading("SR405"))
Log("now time", _D(), "isTrading('jd2405'): ", ext.IsTrading("jd2405"))
# 测试 NewPositionManager 导出函数 生成对象
obj = ext.NewPositionManager()
Log(obj.Account())
# 测试 OpenLong 、 OpenShort 、GetPosition
open_long = obj.OpenLong("MA405", 2)
open_short1 = obj.OpenShort("SR405", 3)
open_short2 = obj.OpenShort("jd2405", 4)
Log("open_long:", open_long)
Log("open_short1:", open_short1)
Log("open_short2:", open_short2)
Sleep(1000 * 60)
positions = obj.GetPosition("MA405", PD_SHORT)
Log("get MA405 PD_SHORT:", positions)
positions = obj.GetPosition("MA405", PD_LONG)
Log("get MA405 PD_LONG:", positions)
# 读取平仓前的持仓信息
positions = exchange.GetPosition()
Log("平仓前:", positions)
# 测试 CoverAll
obj.Cover("MA405")
# 测试 CoverAll
obj.CoverAll()
# 读取 Cover、CoverAll 后的 持仓信息
positions = exchange.GetPosition()
Log("平仓后:", positions)
Log("实时收益:", obj.Profit())
我们举例示范一下:首先,代码通过 ext.NewPositionManager()
创建了一个名为obj
的单品种控制对象对象。然后,代码使用 Log 函数输出了$.IsTrading()
的结果。$.IsTrading(symbol)
是交易类库中一个用于判断指定交易品种是否正在交易中的函数。IsTrading
支持判断各种期货品种的交易时间段,比如夜盘或者周末假期等,可以看到当设置时间为早上8点数未开盘时间,该函数返回结果False
。
接下来,代码调用 obj.OpenLong
方法开多仓,obj.OpenShort
方法开空仓。相对于我们前面讲过的Exchange.buy
或者Exchange.sell
函数,这里对交易的代码细节进行了一些优化。这里我们不需要填写任何的价格,只需要填写品种和数量就可以。在模版参数里也有滑价点数,大家也可以根据需要调整下。请注意,不同的品种的跳动点数是不同的,比如大多数品种是一个单位的跳动,而有个别品种,比如铁矿石,跳动单位是0.5。另外,目前交易类库里的交易函数是不支持限价单的,如果需要限价单策略,可以使Exchange.buy
或者Exchange.sell
等交易函数。
紧接着,代码使用了GetPosition()
方法 用来获取指定交易品种和持仓类型的仓位信息。其中,PD_SHORT
和 PD_LONG
是表示空头和多头仓位。因为MA405品种目前是多头的仓位,所以空头仓位信息返回值将会是null。最后,代码调用 obj.Cover
和 obj.CoverAll
方法进行平仓操作。随后使用obj.Profit
方法输出了仓位操作后的盈利情况。
点击开始回测,我们来看一下回测结果,符合我们的预设。这就是一个使用交易类库下单的简单例子。相对于前面我们讲过的交易函数,可以发现使用交易类库可以更加方便快捷的下单,省去了交易参数设置的烦恼。
第二种是针对多品种的操作。q = ext.NewTaskQueue()
,q为创建的多品种队列控制对象。这里的多品种并不是意味着只能操作多个品种,而是多种操作同时处理,有点类似于并联的概念。这里涉及到了异步处理的概念。异步处理是一种编程模式,用于处理可能需要耗时的操作,在程序化交易中,市场信号的判断是很迅速的,然而价格的快速波动造成下单成交需要耗费更多的时间。在异步处理中,程序可以继续执行其他任务而不必等待比较耗时操作的完成。
这里给大家稍微解释一下同步处理和异步处理的不同。传统的同步处理方式会导致阻塞(blocking):就是当一个任务执行时,程序会一直等待该任务完成后再执行下一个任务。这可能导致程序运行效率低下,特别是在需要等待I/O操作完成时。而异步处理采用了非阻塞(non-blocking)方式,使得在执行比较耗费时间的操作时,程序可以同时执行其他任务。异步操作通常是通过回调函数等机制来实现的。
在异步处理中,当一个耗时任务启动后,程序立即将控制权返还给调用方,让其继续执行其他任务。然后,当耗时任务完成时,会触发相应的回调函数,用来处理任务的执行结果。由于异步处理不会阻塞主要流程,可以提高程序的性能和响应能力。相对于单品种串联的操作,异步处理可以较好的实现同时下达任务,各个任务在满足各自条件的情况下执行,所以各任务之间不会阻塞。因此,对于多品种或者多操作的复杂交易的场景,使用任务队列NewTaskQueue
是非常适合的。我们来举例示范一下。
def main():
q = ext.NewTaskQueue()
q.pushTask(exchange, "MA888", "buy", 3, lambda task, ret: Log(task["desc"], ret, q.pushTask(exchange, "MA888", "closebuy", 1, lambda task, ret: Log(task["desc"], ret, "#FF0000")) if ret else "", "#FF0000"))
while True:
q.poll()
Sleep(1000)
我们来举例示范一下。这段代码是一个示例,展示了如何使用交易类库中的任务队列来处理多个非阻塞的交易任务。整体来说,这段代码中的异步处理体现在使用了任务队列ext.NewTaskQueue()
以及q.pushTask()
方法来执行非阻塞的交易任务。
首先调用ext.NewTaskQueue()
创建了一个任务队列q。然后使用q.pushTask()
方法将任务添加到队列中。其中,每个任务包含了交易相关信息和回调函数,用于处理任务完成后的返回结果。pushTask具体的参数是这样的:其中exchange是交易所,symbol是期货合约,action是对应的操作,amount是操作的手数,而onFinish是回调函数。
pushTask(exchange, symbol, action, amount, onFinish)
通过设置回调函数,如果当前任务成功执行,则继续调用q.pushTask()
添加下一个任务到队列中,并指定相应的回调函数。在任务队列设置完成以后,while循环检查队列中是否还有待执行的任务。如果队列不为空,调用q.poll()
从队列中提取并执行下一个任务。在执行任务期间,使用Sleep(1000)
进行延迟等待,以便给交易操作留出时间。
通过使用任务队列和回调函数,可以实现交易任务的非阻塞执行。这种方式允许在等待交易结果的同时进行其他操作,提高了交易过程的效率和灵活性。了解到代码的整体思路以后,我们来看下具体的交易是怎样实现的:
q = ext.NewTaskQueue()
:创建一个新的任务队列对象q,用于存储交易任务队列;
在 pushTask()
函数中,首先通过调用 q.pushTask()
方法将一个买入任务添加到任务队列中。这个买入任务包含了交易相关的信息,交易品种(“MA888”)、交易类型(例如 “buy”)、交易数量,以及一个回调函数。
当买入任务成功执行完成后,回调函数会被调用。在这个回调函数中,首先会记录买入交易的描述和执行结果。然后,如果买入交易成功(即 ret
为真值),则会再次调用 q.pushTask()
方法,将一个卖出任务添加到任务队列中。这个卖出任务也包含了交易相关的信息,以及一个回调函数。这样,在买入交易成功后,程序会立即添加一个卖出任务到任务队列中,以便在买入交易执行完成后立即执行卖出操作。
while True
:在任务队列定义完成以后,使用while循环,不断检查任务队列q是否还有未完成的任务。
q.poll()
使用poll函数从任务队列q中取出一个任务,并执行该任务。执行任务后,任务会被移除队列。
Sleep(1000)
暂停1秒,让程序等待一段时间再继续下一次循环。这样可以确保任务的逐步执行,而不是立即执行完所有任务。
通过使用任务队列,可以实现非阻塞的交易任务处理。当一个任务完成时,会触发回调函数,并可以在回调函数中继续推入下一个交易任务。同时,通过循环和暂停的方式,确保任务按序执行。我们来看下回测结果,可以看到,第一步收到任务对甲醇主力合约开多仓,数量为3,返回任务的描述task.desc
和任务结果ret,包括仓位的信息。第二步收到任务,平掉一手多仓。返回结果同样显示任务的描述和结果。
大家是不是有些疑问,我们这里使用了一个异步处理的方式实现了一个按顺序的操作,其实这个例子是让大家理解任务队列的交易处理和回调函数的底层逻辑,尝试实现异步的处理。请注意,这段代码只是为了教学示范作用,具体的使用方式可能需要根据具体的交易类库进行调整和修改。另外,Python语言还具有很多异步处理的设置,大家可以根据自己的经验进行更多异步尝试。
这段配置是针对交易优化模块的设定,其中包括了以下几项:
滑价:滑价是指在进行交易时,允许价格在一定范围内波动,以确保交易能够成功成交。在这里,滑价被设置为1,表示允许价格在当前市场价格上下波动一个单位。
轮询间隔:这是指程序在执行轮询或检查状态时的时间间隔。在这里,轮询间隔被设置为500毫秒,意味着程序每隔500毫秒就会执行一次轮询操作。
在状态栏显示持仓信息:这个设置确定是否在程序的状态栏中显示当前持仓信息。设置为true表示持仓信息会显示在状态栏中,这样用户可以方便地了解当前持仓情况。
账户与持仓同步周期:这是指账户信息与持仓信息之间同步的时间间隔。设置为5表示程序每隔5秒就会更新一次账户与持仓信息,以确保信息的及时性和准确性。
一个好的交易函数可以集成风险管理工具和技术指标,帮助我们有效控制风险。通过在交易函数中实现止损、止盈、资金管理等功能,我们可以最大限度地降低交易风险,并保护资金免受不利市场波动的影响。在优宽量化平台,我们也有一些优秀的交易类库,比如止损类库,大家都可以学习参考下。
第 5 章为大家介绍了优宽量化平台一系列实用功能,包括交易终端、数据探索模块、自定义数据源和本地回测引擎。我们将探讨如何利用这些功能提升交易效率,增强数据分析能力,以及获得更好的量化体验。
一个好的交易软件对于金融交易的重要性不言而喻。在期货市场中,交易软件是投资者进行交易的核心工具,其质量和性能对投资者的交易成果具有显著的影响。怎么样是一个好的交易软件呢?一个好的交易软件的界面设计应简单明了,操作流程简明易懂,以便投资者快速上手并提高交易效率。在同时,一个好的交易软件具备丰富的功能,包括实时报价、图表分析、交易下单、止损设置、风险管理等,以满足投资者的各种需求。在市面上,一个好用的软件通常需要额外的付费;而免费的软件提供的功能较少,并且没有教程也很难理解具体的使用方法。另外,有不少用户反应,在MAC的电脑端平台,没有好用的期货交易软件,需要安装Windows虚拟机才能进行期货交易。为解决这些痛点,优宽量化平台,作为一个开放的金融量化平台,经过研发工作,优宽量化新版的交易终端终于上线了,网页端和手机APP端都支持,功能更加丰富,使用更加方便。大家可以体验一下,欢迎各位小伙伴提供反馈意见,我们会不断根据大家的需求进行交易终端的持续优化。
首先,我们介绍一下交易终端这个模块,大家可能没有使用过。优宽量化的交易终端最初的时候只有一个简单的交易界面,只是为程序化交易者临时使用。但是除了全自动的量化交易,有不少朋友都是手动交易,或者半自动交易的爱好者。随着我们交易经验的增加,普通的交易功能已经不能满足我们的需求。例如,我们了解不同品种之间具有高度的相关性,在我们交易的时候,经常需要查看多个市场或者品种的信息和指标作为参考,如果手动的点击品种进行实时价格的查看确实比较麻烦,也无法处于同一个页面中进行操作。优宽量化平台利用框架灵活的优势,开发出了全新的增强版交易终端,方便大家进行不同类型的交易,比如查看多品种合约,实时筛选品种,高频套利等需求。今天,我们就来展示一下新版交易终端具体的使用方法。
进入优宽量化平台,点击交易终端,就可以进入新版界面。我们来介绍一下新版交易终端的各项功能,第一个功能是托管者-交易所-交易品种分组绑定。这个功能是交易终端的核心功能。分组绑定是将交易所,托管者和目标品种进行一起的绑定,然后在每个功能模块里就可以选择不同的分组,就对应到了不同交易所的不同品种,可以及时的进行相应的操作。点击每个模块右上角一个带颜色和数字的小方块,就可以进入不同分组的选择。数字代表了分组id,颜色便于直观确定属于那一分组。点击进入分组详情可以对该分组进行设置。
我们举例示范一下,首先我们进行分组绑定,点击这里的设置分组,首先设置第一组,然后点击这里选择托管者,开户公司,和不同交易所下的各类期货品种。如果哪些合约是我们的经常做的合约,可以点前面的星号进行收藏,在自选分组里可以看到,这样分组绑定就完成了。对于非主力合约,我们需要搜索合约的名称可以进行绑定。这样子绑定分组,各个分组对应的模块也是使用相同的交易所,托管者和交易品种,如果这里我们改为燃油,可以看到对应的图像模块和盘口数据模块对应的品种都进行了更换。这就是分组绑定的设置。
大家可以对常用交易所和交易品种提前设置好分组。分组完成后这些数据就会保存,下次进入还可以直接使用。
接下来我们可以添加其他分组,例如对于黑色系,第二组和第三组我们还可以加上铁矿石和热卷进行绑定。分组绑定是十分方便的,通过绑定不同交易所和不同品种,我们在各个模块里就可以改变这里的分组,实现多个交易所,多个分组价格信息的实时展示和交易。大家在这里这可能会有疑问,当需要进行分组切换的时候,还需要一个个点击,也挺麻烦的。当然我们也考虑到了这个问题,怎么进行多个品种图像的呈现和交易呢,这就涉及到了交易信息插件化自由布局。
这是交易终端的另一个核心功能,我们可以自定义交易信息插件化自由布局。
交易终端的布局并不是固定不变的,我们可以设置这里的模块选择,大小和位置。这里布局中的一个个模块其实是交易插件,交易终端是支持各种插件的,点击右上角的拼图图标,就可以进行设置和操作。在我们交易的时候,一般需要的信息,比如K线数据、订单簿、成交订单流、账户信息、持仓信息、订单等,交易终端把交易界面各种信息展示做成单独的模块插件,大家可以按需添加使用,和删除。并且每个插件可以拖动和调整大小。结合前面的分组绑定功能,灵活性达到最大,这就意味着我们可以根据自己的需要搭建出来私人订制的交易系统。
我们展示一下一个自定义布局的搭建过程。点击齿轮按钮,可以看到这里的布局选择,可以看到这里的系统的示范布局,我们也可以自定义布局。点击这里的加号就可以新建一个布局。点击这里的编辑铅笔按钮,就可以重新命名或者删除布局。这里我们将这个布局命名为黑色系多品种。需要注意的是,这里不同布局里绑定的品种是不一致的,所以我们新建一个布局后,需要设置我们需要绑定的品种。在这里设置好绑定分组,接下来我们就可以进行页面布局了。根据我们的需要,删除不需要的模块,直接点击右上角的叉号。一个模块是可以重复添加的,,模块的大小和位置我们也可以自主调整。当我们初步设置好布局以后,点击这里的分组选择进行各个模块品种的选择。这样一个可以实时查看多品种信息,并进行交易的界面布局就设置好了。另外,这里的颜色模式,红涨绿跌和绿涨红跌,可以根据我们的需要进行选择;布局呢,还具有导入和导出的功能,文件格式是json文件,这样呢,我们就可以实现布局的保存。
确实很方便,大家可以根据自己的交易习惯,设置不同的交易布局,对于短线高频选手,盘口数据是必须的;而对于趋势选手,长线的趋势展示可以安排上。所以想象一下,配合一个大屏显示器,同时盯着多品种的行情信息,开着多个子账号随时交易,不需要切换浏览器标签,也不需要切换账户,确实非常的方便和实用。
第三个特性核心功能是自定义功能模块,也就是交易插件的使用。刚才我们展示的可以实现各种需要的功能,这其实是通过交易插件来实现的。点击这里的拼图按钮,可以看到这里有系统插件和我们可以自定义的插件。这里的系统插件是优宽量化为我们装备的,这些插件对应了一个基本交易软件应该必备的模块,我们在原有的基础上进行了更具人性化的完善,图表模块实时观察k线的走势,我们可以选择不同的K线周期,还可以选择主图和副图呈现的指标进行实时趋势的判断;深度模块查看实时交易所返回的tick盘口数据;交易模块进行具体交易的操作,包括限价单和市价单下单操作,另外平仓这里还具有平今和平昨的选项;订单可以查看实时的挂单,账户的资产,和持有的仓位;逐笔交易查看实时的交易记录;另外还有系统插件里的工具,可以看到优宽量化官方准备的一些小程序插件。比如酷炫的订单流展示图,还有今日的期货交易结算单,各个品种的交易时间,网格交易,以及一键查询各个合约代码,委托查询和成交明细,都可以帮助我们进行期货的信息查询和交易操作的帮助,非常建议大家尝试使用下。另外这里我们新增了调试工具,我们可以JS语言进行一些实时信息的获取和交易逻辑的测试,例如这里我们查询一下主力螺纹钢合约的信息,这样呢可以进行目标品种的实时策略调试和运行。
除了使用官方的插件,大家也可以自己编写插件,定义自己想要的功能。插件的编写方法我们后续将为大家进行介绍。
对于交易终端的各个模块的细节,我们在结合用户需求的情况下,也进行了很多的完善。例如这里的对于行情信息,我们可以点击刷新按钮进行模块数据的刷新,点击这个按钮,模块里的信息可以设置是否自动刷新,以及刷新的周期。另外,在某些插件运行卡顿的时候,我们可以选择重启终端进程。
以上的讲解并不能涵盖所有的功能,大家如果感兴趣的话,可以来这里切身体验一下。如果大家体验有问题或者哪些功能需要加强,都可以提出来,我们的工程师会尽力的去完善,帮助大家获得更好的交易体验。
优宽量化身为量化交易平台,主要是为了服务程序化交易者。但也提供了简洁好用交易终端,通过不同板块和功能的组合,我们可以自定义属于自己交易界面,打造专属于自己的量化交易辅助系统。
我们经常看到类似文华财经,MT4等具有一键下单,多种功能的止盈止损功能等辅助交易模块,然而这种类似方便的功能需要我们额外的付费(年费通常在7000元左右)。优宽量化平台为了完善交易终端的体验,现在增加了插件功能。有时候,我们需要一个小功能来辅助交易,比如一键平仓、一键对冲、阶梯挂单、冰山委托等操作,这种类似的功能并不太需要经常查看执行日志,所以新建一个实盘有些繁琐,我们直接在终端点击一下插件,就能够立即实现相应的功能,这样可以大大方便手动交易。这些自定义的交易插件,我们自身可以编码实现。并且这个交易终端是定制化的,这就意味着我们可以根据我们的交易习惯,自定义交易功能辅助面板。
本节课,我们来学习交易插件的使用和编写。这个界面是为了快速的进行跨期对冲交易布置好的页面,原始的页面可以通过点击重置页面布局,进行恢复。这个就是初始的界面布局。如果我们想添加交易插件,通过右上角的拼图按钮,我们就可以点击交易插件进行使用。比如,我们点击近远月差价显示的插件,它就会展示在交易终端页面,输入目标合约,点击执行就会出现目标合约的跨期差价图像。需要注意的是,插件不会显示出日志,但是可以返回显示表格。交易终端插件运行时长最长为3分钟,超过3分钟自动停止运行,但是当我们需要进行一些时间较短的交易操作,或者当前的状态查看,3分钟还是足够的;并且也可以用来测试我们的实盘策略,新鲜的策略通过交易插件测试完成后,可以应用于实盘进行成熟的仿真或者实盘交易。
在插件里面是可以设置参数,没有参数的插件可以直接运行。插件的摆放位置,大小都是可以调整的,关闭插件点击右上角x号就可以,我们可以根据我们的交易习惯,进行不同功能模块的编写和摆放。
我们来稍微了解下插件的原理,插件其实相当于立即运行的实盘,功能和调试工具相同,所以插件运行直接对接真实市场的,在交易终端所选的托管者、交易对、K线周期就是默认的相应参数。交易插件会发送一段代码到交易终端页面的托管者进行执行,并且支持返回图表和表格,交易插件和调试工具都是免费使用的。
我们来看下插件是怎样编写的,在新建策略页面,设置策略类型为:交易插件。语言编写支持JavaScript、Python、C++、My语言。插件的main函数return的结果会在运行结束后,在终端弹出,支持字符串、画图和表格。因为插件执行看不到日志,可以将插件的执行结果return返回。插件的用途很广泛的,在很多时候手动交易需要很多重复执行的操作,其实这些操作都可以用插件实现。今天,我们讲解的插件使用,是辅助手动期货跨期对冲的插件套装。
期货跨期对冲是很常见的策略,由于频率不是很高,我们经常会手动操作,需要在分析差价走势的基础上,一个合约做多,一个合约做空。如果在期货软件上,我们可能需要复杂的分析和操作,而在交易终端使用插件,将大大节省我们的精力。当我们想进行手动的对冲交易的时候,我们可以调整下布局,将我们需要的插件摆放到合适的位置。
为方便进行跨期对冲,我们编写了三个插件,第一个是可以查看最新的跨期合约差价,这里我们填写目标合约,点击执行就会呈现最新以秒为单位的差价,并且这里还有有均线的显示,可以用来判断实时差价的偏离。当我们通过差价显示认为入场的时机到,我们就要迅速的进场进行交易,在没有辅助功能的期货软件中,我们需要手动的找到两个目标品种,然后填写价格进行相反方向的开仓,然而有时候,入场的最佳时间是很短暂的,当我们手忙脚乱开仓后,可能最佳的入场点已经过去;而使用我们的交易插件,当事先设置好交易品种,数量和方向(这里的reverse,代表是正套还是反套),一键点击执行就可以完成双向开仓的操作,这里点击一下仓位;可以显示目前的仓位状态;最后,当价差回归正常,我们就要进行双向的平仓,我们事先设置好滑价,点击就可以平仓。是不是很方便,今天呢,我们就要学习这些插件是如何编写出来的,它和平常的策略编写是有一些不同的,我们在讲解编码的过程中会为大家及时提醒。
首先介绍的是画跨期差价插件,这里我们首先设置好外部的参数,期货合约A和B。然后回到代码部分,这里使用原生的chart画图函数,设置图表对象chart,设置好title,x轴,y轴和数据列表,这里想呈现两根线,所以分别设置diff和meandiff。
回到主函数,首先分别获取两个目标合约的最新k线,这里的exchange.GetRecords
中填写参数为1,表示要获取的k线周期为1s。接下来,我们要利用K线数据进行差价的计算,两个k线是轮询获取的,因此数组的长度可能会有不一致,为了保存两个差值计算时间的一致对照性,所以我们取两者的最小值,定义为变量rlength;然后定义差价储存列表difflist。
使用for循环,根据获取的k线长度,按索引计算两个合约的diff值,然后向chart的第一个数据系列series[0]
添加数据,时间戳也是这样的设置;接下来计算diff的均值,使用difflist收集,使用TA.MA
进行计算,这里设置的周期为20,为了更及时的展现变化,最后向chart.series[1]
添加最新的diff均值。这样图表的设置就完成了,最后return一下chart结果就可
by2022 企业微信加不上啊啊啊啊啊啊
雨幕(youquant) 您好,企业微信满了,您加这个微信: https://www.youquant.com/upload/asset/1780ac4e8b9064c9d7d9a.png