function MainLoop(){ // 处理具体工作的函数
// deal Main task
}
function main() {
var status = null;
while(true){
status = exchange.IO("status"); // 调用API 确定连接状态
if(status === true){ // 判断状态
LogStatus("已连接!");
MainLoop(); // 连接上 交易所服务器后,执行主要工作函数。
}else{ // 如果没有连接上 即 exchange.IO("status") 函数返回 false
LogStatus("未连接状态!"); // 在状态栏显示 未连接状态。
}
Sleep(1000); // 需要有轮询间隔, 以免访问过于频繁。
}
}
接下来我们就按这样的架构来测试各个API
这里假设读者已经明白了CTP商品期货模拟盘账户的添加过程,并且已经添加好了 CTP商品期货模拟盘。 不清楚的可以温习 【章节 1.3.3 交易所】、【CTP商品期货 模拟盘 配置(教学贴)】
测试源码如下,使用的是CTP商品期货模拟盘。(模拟盘默认资金是100W , 这个之前测试亏了一点 ╮(╯_╰)╭)
var Account = null;
function MainLoop(){
Account = _C(exchange.GetAccount);
}
function main() {
var status = null;
while(true){
status = exchange.IO("status");
if(status === true){
LogStatus("已连接!", new Date(), '\n', "Account:", Account);
MainLoop();
}else{
LogStatus("未连接状态!", new Date());
}
Sleep(1000);
}
}
模拟盘运行显示:
有新用户可能会出现这样的错误, 编写一个CTP商品期货策略 学习的时候,上来直接调用API 获取K线、行情数据。会遇到报错信息:not ready 。 然后想不通是怎么回事,检查 exchange.IO("status"); 的返回值发现为true ,已连接。 这样的原因在于:没有订阅任何品种的信息,就调用获取K线、行情的API(托管者不知道要发送什么数据给你)。 所以来看看如何订阅合约信息,即设置当前操作的合约类型。 我们看下API文档描述:
SetContractType(ContractType) 设置合约类型
传统的CTP期货的ContractType就是指的合约ID, 如SetContractType("au1506") 返回合约的详细信息, 如最少一次买多少, 手续费, 交割时间等
股票合约格式为 股票代码.(SH/SZ), SH指上交所, SZ指深交所, 如000001.SZ就是指深交所的平安银行
商品期货与股票取消订阅合约, 在合约名前加上"-"前缀重新调用即可, 如SetContractType("-au1506"); 成功返回true
数字货币796支持: "week", "weekcny", 默认为子账户A, 要指定子账户是A还是B, 在合约后加"@A"或"@B", 如: "day@A" 为日合约A子账户
BitVC有week和quarter和next_week三个可选参数, OKCoin期货有this_week, next_week, quarter三个参数
exchange.SetContractType("week");
函数的参数 ContractType 就是合约代码,参数是字符串,所以不要忘记 双引号 “” ,先了解下这些合约:
举个例子, 甲醇MA,在2017年1月份交割的 合约,代码就是 MA701 。 下面我们就以MA701为例子,调用SetContractType 函数获取合约信息,并设置为当前操作的合约。
代码如下:
var Account = null;
var isFirstSetContractType = true; // 标记是否第一次设置 合约。
function MainLoop(){
Account = _C(exchange.GetAccount);
if(isFirstSetContractType === true){ // 是第一次设置合约 ,执行以下设置。
var ContractInfo = exchange.SetContractType("MA701"); // SetContractType 函数返回 设置的合约的详细信息。
for(var k in ContractInfo){ // 遍历这个信息结构。
Log(k, ContractInfo[k]); // 逐行打印。
}
isFirstSetContractType = false; // 设置过合约了。
}
}
function main() {
var status = null;
while(true){
status = exchange.IO("status");
if(status === true){
LogStatus("已连接!", new Date(), '\n', "Account:", Account);
MainLoop();
}else{
LogStatus("未连接状态!", new Date());
}
Sleep(1000);
}
}
可以看到打印出了MA701合约的详细信息。(信息比较多,分了2张显示)
简单的摘出几个属性看下: 合约:InstrumentName, 一手:VolumeMultiple 份, 最大下单量:MaxLimitOrderVolume,保证金率: LongMarginRatio(多仓), ShortMarginRatio(空仓), 交割日期:StartDelivDate 。
在使用中也许会有以下问题: 我想知道,都有哪些合约可以设置怎么办 ? 答: 可以用函数 exchange.IO("instruments"); 查询。 我想知道,当前程序都订阅了那些合约 ? 答: 可以用函数 exchange.IO("subscribed"); 查询。 试一试:
var Account = null;
var isFirstSetContractType = true; // 标记是否第一次设置 合约。
function MainLoop(){
Account = _C(exchange.GetAccount);
if(isFirstSetContractType === true){ // 是第一次设置合约 ,执行以下设置。
var ContractInfo = exchange.SetContractType("MA701"); // SetContractType 函数返回 设置的合约的详细信息。
for(var k in ContractInfo){ // 遍历这个信息结构。
Log(k, ContractInfo[k]); // 逐行打印。
}
isFirstSetContractType = false; // 设置过合约了。
var contracts = exchange.IO("instruments"); // 查询 可订阅的合约
var str = "";
for(var i in contracts){
str += (i + "--");
}
Log("已经订阅的合约:" ,exchange.IO("subscribed")); // 查询已经订阅的合约
Log("可订阅的合约:", str); // 显示可以订阅的合约信息
}
}
function main() {
var status = null;
while(true){
status = exchange.IO("status");
if(status === true){
LogStatus("已连接!", new Date(), '\n', "Account:", Account);
MainLoop();
}else{
LogStatus("未连接状态!", new Date());
}
Sleep(1000);
}
}
模拟盘测试结果:
用SetContractType 设置当前操作合约后,就可以获取该合约的K线和行情数据了。 要注意的是, 用SetContractType 函数设置为一个 合约,比如设置 SetContractType(“MA705”), 订阅(执行一次)并设置当前合约为 MA705 即 2017年5月交割的甲醇合约。 那么此刻调用 GetRecords 、GetTicker 、 GetDepth 等 API 函数 返回的均是 MA705 合约的 相关数据, 如果要获取别的合约必须重新调用 SetContractType 函数设置当前的合约类型,然后再调用 行情API 或者 交易 API。
var Account = null; // 全局变量 用来保存每次获取的账户信息
var ticker = null; // 用来保存每次获取的行情信息
var records = null; // 用来保存每次获取的K线数据
var isFirstSetContractType = true; // 标记是否第一次设置 合约。
function MainLoop(){
Account = _C(exchange.GetAccount);
if(isFirstSetContractType === true){ // 是第一次设置合约 ,执行以下设置。
var ContractInfo = exchange.SetContractType("MA701"); // SetContractType 函数返回 设置的合约的详细信息。
for(var k in ContractInfo){ // 遍历这个信息结构。
Log(k, ContractInfo[k]); // 逐行打印。
}
isFirstSetContractType = false; // 设置过合约了。
var contracts = exchange.IO("instruments"); // 查询 可订阅的合约
var str = "";
for(var i in contracts){
str += (i + "--");
}
}
ticker = exchange.GetTicker(); // 调用API GetTicker
records = exchange.GetRecords(); // 调用API GetRecords 默认周期
}
function main() {
var status = null;
while(true){
status = exchange.IO("status");
if(status === true){
LogStatus("已连接!", new Date(), '\n', "Account:", Account, '\n', "ticker:", ticker , '\n', "records:", records);
MainLoop();
}else{
LogStatus("未连接状态!", new Date());
}
Sleep(1000);
}
}
运行结果:
GetPosition 函数 API 文档描述:
GetPosition 获取当前持仓信息
返回一个Position数组, (BitVC和OKCoin)可以传入一个参数, 指定要获取的合约类型
Position 结构 期货交易中的持有仓位信息, 由GetPosition()函数返回此结构数组
{
MarginLevel :杆杠大小, 796期货有可能为5, 10, 20三个参数, OKCoin为10或者20,
BitVC期货和OK期货的全仓模式返回为固定的10, 因为原生API不支持。
Amount :持仓量, 796期货表示持币的数量, BitVC指持仓的总金额(100的倍数), OKCoin表示合约的份数(整数且大于1)
CanCover :可平量, 只有股票有此选项, 表示可以平仓的数量(股票为T+1)今日仓不能平
FrozenAmount :冻结量, 支持传统期货与股票, 数字货币只支持796交易所
Price :持仓均价
Profit :持仓浮动盈亏(数据货币单位:BTC/LTC, 传统期货单位:RMB, 股票不支持此字段,
注: OKCoin期货全仓情况下指实现盈余, 并非持仓盈亏, 逐仓下指持仓盈亏)
Type :PD_LONG为多头仓位(CTP中用closebuy_today平仓), PD_SHORT为空头仓位(CTP用closesell_today)平仓,
(CTP期货中)PD_LONG_YD为咋日多头仓位(用closebuy平), PD_SHORT_YD为咋日空头仓位(用closesell平)
ContractType :商品期货为合约代码, 股票为'交易所代码_股票代码', 具体参数SetContractType的传入类型
}
测试代码:
var Account = null; // 全局变量 用来保存每次获取的账户信息
var ticker = null; // 用来保存每次获取的行情信息
var records = null; // 用来保存每次获取的K线数据
var positions = null; // 用来获取 账户的持仓信息。
var isFirstSetContractType = true; // 标记是否第一次设置 合约。
function MainLoop(){
Account = _C(exchange.GetAccount);
if(isFirstSetContractType === true){ // 是第一次设置合约 ,执行以下设置。
var ContractInfo = exchange.SetContractType("MA701"); // SetContractType 函数返回 设置的合约的详细信息。
for(var k in ContractInfo){ // 遍历这个信息结构。
Log(k, ContractInfo[k]); // 逐行打印。
}
isFirstSetContractType = false; // 设置过合约了。
var contracts = exchange.IO("instruments"); // 查询 可订阅的合约
var str = "";
for(var i in contracts){
str += (i + "--");
}
exchange.SetDirection("buy"); // 设置 操作
exchange.Buy(_C(exchange.GetTicker).Sell + 2, 1); // 开多仓。
}
positions = exchange.GetPosition(); // 获取所有持仓信息
}
function main() {
var status = null;
while(true){
status = exchange.IO("status");
if(status === true){
LogStatus("已连接!", new Date(), '\n', "Account:", Account, '\n', "ticker:", ticker
, '\n', "records:", records, '\n', "positions:", positions);
MainLoop();
}else{
LogStatus("未连接状态!", new Date());
}
Sleep(1000);
}
}
运行结果:
可以看到我只开仓了一个品种,调用 GetPosition 函数 获取的就是只包含一个元素的数组, 如果持有多个品种仓位时,获取的是包含多个元素的数组。
在设置好合约类型后,开仓平仓操作前,必须设置操作方向(和现货不同),我们需要另外一个API函数: SetDirection
SetDirection(Direction) 设置Buy或者Sell下单类型
Direction可以取buy, closebuy, sell, closesell四个参数, 传统期货多出closebuy_today,与closesell_today, 指平今仓,
默认为closebuy/closesell为平昨仓
对于CTP传统期货, 可以设置第二个参数"1"或者"2"或者"3", 分别指"投机", "套利", "套保", 不设置默认为投机
股票只支持buy与closebuy, 因为股票只能买跟平仓
exchange.SetMarginLevel(5);
exchange.SetDirection("buy");
exchange.Buy(1000, 2);
exchange.SetMarginLevel(5);
exchange.SetDirection("closebuy");
exchange.Sell(1000, 2);
SetDirection 的参数分别解释:
传统期货多出了2个参数:
默认 2个参数意义:
可能有同学会问: 如何区分我的持仓是今日、昨日呢? 答: 交易所返回的数据会告诉我们答案, 在调用 GetPosition 获取持仓信息的数据中, 有一个 Type 属性,这个属性会告诉我们持仓是今仓 、 还是昨仓。
来动手试一试,开仓平仓吧!
function main() { // 这次为了方便重点看 开仓平仓操作,我们在回测系统中进行测试。
var initAccount = exchange.GetAccount(); // 获取初始 账户信息
var info = exchange.SetContractType("MA701"); // 设置我们要操作的合约 甲醇
var ticker = exchange.GetTicker(); // 先获取当前的行情 数据
Log("initAccount:", initAccount);
Log(info);
// 开仓买入做多
exchange.SetDirection("buy");
exchange.Buy(ticker.Sell + 1, 1); // 吃掉卖一价这个单子, 买入一手。
Sleep(1000);
// 获取一下持仓信息
var positions = exchange.GetPosition(); // 获取持仓信息
Log("当前所有持仓:", positions);
//平仓
var pos = null;
for(var i = 0 ; i < positions.length ; i++){
if(positions[i].ContractType == "MA701"){
pos = positions[i];
}
}
exchange.SetDirection("closebuy_today");
exchange.Sell(ticker.Buy - 1, pos.Amount);
positions = exchange.GetPosition();
Log("当前所有持仓:", positions);
}
回测系统中,手续费是自动扣除的,保证金也是自动返回到账户内。并且回测系统是不区分 今仓 、 昨仓 。 写策略时最好按照要求写,以免实盘的时候来回修改。
为了使用户更好的上手使用,平台已经封装了一个方便使用的工具– 《商品期货交易类库》模板。 源代码公开,有兴趣的同学可以看一下实现,可以学到不少知识、思想。 下面我们先领略一下模板带来的便捷。 1.先把模板复制过来
2.简述一下代码,本身模板代码 中有 main 函数 用来测试,可以直接运行模板测试。我们复制模板以后,在策略的模板栏就会出现已经有的模板,需要给策略添加哪一个就在它前边的方框中打钩。如图:
3.试着使用: 该模板有 单品种、 多任务 两种 工作模式,我们先认识初级的 单品种 使用方法。
function main() {
var p = $.NewPositionManager(); // $.NewPositionManager() 是 商品期货交易类库 模板的导出函数(接口)。
// 该函数的作用是返回一个对象,用该对象管理开仓、平仓等操作。
p.OpenShort("MA701", 1); // p对象 的方法 OpenShort() , 功能是开空仓, 参数传入 合约代码 ,数量
// 会根据当前行情的价格 开空仓。
p.OpenShort("MA701", 1); // 继续开空
Log(p.GetPosition("MA701", PD_SHORT)); // 调用对象 p的 方法 GetPosition() ,传入合约代码, 合约类型, 找出相应的持仓,打印出来。
Log(p.Account());
Sleep(60000 * 10); // 暂停一段时间
p.CoverAll(); // 调用 对象 p的方法 CoverAll() 把持仓全部平掉。
LogProfit(p.Profit()); // 调用 对象 p的方法 Profit() 并打印 盈亏信息。
}
在模板代码中 以 $. 字符串开头的函数即为模板导出函数,可以由其它策略调用(前提是已经添加到策略)。《商品期货交易类库》 这个模板还有很多强大的功能,如:判断该品种是不是在交易时间、多任务等。
主要支持 BitVC 、OKCoin 、796
SetMarginLevel(MarginLevel) 设置杆杠大小
设置Buy(多单)或者Sell(空单)的杆杠大小, MarginLevel有5, 10, 20 三个可选参数
796支持5,10,20,50三个选项, BitVC的LTC不支持20倍杠杆, OKCoin支持10倍和20倍
如: exchange.SetMarginLevel(5)
量化交易川 请问数字货币合约的教学部分,能否补充一下呢
小小梦 好的 新教程正在做。