commit
1c49d1e1b7
@ -558,7 +558,7 @@ class DataApi(object):
|
||||
self.taskThread = Thread(target=self.run) # 处理任务的线程
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def init(self, interval, debug=True):
|
||||
def init(self, interval):
|
||||
"""初始化"""
|
||||
self.taskInterval = interval
|
||||
self.DEBUG = debug
|
||||
@ -567,8 +567,8 @@ class DataApi(object):
|
||||
self.taskThread.start()
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def stop(self):
|
||||
"""停止"""
|
||||
def exit(self):
|
||||
"""退出"""
|
||||
self.active = False
|
||||
|
||||
if self.taskThread.isAlive():
|
||||
|
@ -1,7 +1,13 @@
|
||||
[
|
||||
{
|
||||
"name": "double ema",
|
||||
"className": "DoubleEmaDemo",
|
||||
"vtSymbol": "IF1602"
|
||||
"className": "EmaDemoStrategy",
|
||||
"vtSymbol": "IF1702"
|
||||
},
|
||||
|
||||
{
|
||||
"name": "atr rsi",
|
||||
"className": "AtrRsiStrategy",
|
||||
"vtSymbol": "IC1702"
|
||||
}
|
||||
]
|
@ -13,7 +13,7 @@ import multiprocessing
|
||||
import pymongo
|
||||
|
||||
from ctaBase import *
|
||||
from ctaSetting import *
|
||||
from strategy import *
|
||||
|
||||
from vtConstant import *
|
||||
from vtGateway import VtOrderData, VtTradeData
|
||||
@ -881,6 +881,7 @@ def optimize(strategyClass, setting, targetName,
|
||||
engine = BacktestingEngine()
|
||||
engine.setBacktestingMode(mode)
|
||||
engine.setStartDate(startDate, initDays)
|
||||
engine.setEndDate(endDate)
|
||||
engine.setSlippage(slippage)
|
||||
engine.setRate(rate)
|
||||
engine.setSize(size)
|
||||
|
@ -23,7 +23,7 @@ from collections import OrderedDict
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
from ctaBase import *
|
||||
from ctaSetting import STRATEGY_CLASS
|
||||
from strategy import STRATEGY_CLASS
|
||||
from eventEngine import *
|
||||
from vtConstant import *
|
||||
from vtGateway import VtSubscribeReq, VtOrderReq, VtCancelOrderReq, VtLogData
|
||||
|
@ -314,6 +314,55 @@ class HistoryDataEngine(object):
|
||||
|
||||
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def downloadEquityDailyBarts(self, symbol):
|
||||
"""
|
||||
下载股票的日行情,symbol是股票代码
|
||||
"""
|
||||
print u'开始下载%s日行情' %symbol
|
||||
|
||||
# 查询数据库中已有数据的最后日期
|
||||
cl = self.dbClient[DAILY_DB_NAME][symbol]
|
||||
cx = cl.find(sort=[('datetime', pymongo.DESCENDING)])
|
||||
if cx.count():
|
||||
last = cx[0]
|
||||
else:
|
||||
last = ''
|
||||
# 开始下载数据
|
||||
import tushare as ts
|
||||
|
||||
if last:
|
||||
start = last['date'][:4]+'-'+last['date'][4:6]+'-'+last['date'][6:]
|
||||
|
||||
data = ts.get_k_data(symbol,start)
|
||||
|
||||
if not data.empty:
|
||||
# 创建datetime索引
|
||||
self.dbClient[DAILY_DB_NAME][symbol].ensure_index([('datetime', pymongo.ASCENDING)],
|
||||
unique=True)
|
||||
|
||||
for index, d in data.iterrows():
|
||||
bar = CtaBarData()
|
||||
bar.vtSymbol = symbol
|
||||
bar.symbol = symbol
|
||||
try:
|
||||
bar.open = d.get('open')
|
||||
bar.high = d.get('high')
|
||||
bar.low = d.get('low')
|
||||
bar.close = d.get('close')
|
||||
bar.date = d.get('date').replace('-', '')
|
||||
bar.time = ''
|
||||
bar.datetime = datetime.strptime(bar.date, '%Y%m%d')
|
||||
bar.volume = d.get('volume')
|
||||
except KeyError:
|
||||
print d
|
||||
|
||||
flt = {'datetime': bar.datetime}
|
||||
self.dbClient[DAILY_DB_NAME][symbol].update_one(flt, {'$set':bar.__dict__}, upsert=True)
|
||||
|
||||
print u'%s下载完成' %symbol
|
||||
else:
|
||||
print u'找不到合约%s' %symbol
|
||||
#----------------------------------------------------------------------
|
||||
def loadMcCsv(fileName, dbName, symbol):
|
||||
"""将Multicharts导出的csv格式的历史数据插入到Mongo数据库中"""
|
||||
@ -393,6 +442,7 @@ if __name__ == '__main__':
|
||||
#e = HistoryDataEngine()
|
||||
#sleep(1)
|
||||
#e.downloadEquityDailyBar('000001')
|
||||
#e.downloadEquityDailyBarts('000001')
|
||||
|
||||
# 这里将项目中包含的股指日内分钟线csv导入MongoDB,作者电脑耗时大约3分钟
|
||||
loadMcCsv('IF0000_1min.csv', MINUTE_DB_NAME, 'IF0000')
|
||||
|
@ -1,14 +0,0 @@
|
||||
# encoding: UTF-8
|
||||
|
||||
'''
|
||||
在本文件中引入所有希望在系统中使用的策略类
|
||||
|
||||
这个字典中保存了需要运行的策略的名称和策略类的映射关系,
|
||||
用户的策略类写好后,先在该文件中引入,并设置好名称,然后
|
||||
在CTA_setting.json中写入具体每个策略对象的类和合约设置。
|
||||
'''
|
||||
|
||||
from ctaDemo import DoubleEmaDemo
|
||||
|
||||
STRATEGY_CLASS = {}
|
||||
STRATEGY_CLASS['DoubleEmaDemo'] = DoubleEmaDemo
|
31
vn.trader/ctaAlgo/strategy/__init__.py
Normal file
31
vn.trader/ctaAlgo/strategy/__init__.py
Normal file
@ -0,0 +1,31 @@
|
||||
# encoding: UTF-8
|
||||
|
||||
'''
|
||||
动态载入所有的策略类
|
||||
'''
|
||||
|
||||
import os
|
||||
import importlib
|
||||
|
||||
# 用来保存策略类的字典
|
||||
STRATEGY_CLASS = {}
|
||||
|
||||
# 获取目录路径
|
||||
path = os.path.abspath(os.path.dirname(__file__))
|
||||
|
||||
# 遍历strategy目录下的文件
|
||||
for root, subdirs, files in os.walk(path):
|
||||
for name in files:
|
||||
# 只有文件名中包含strategy且非.pyc的文件,才是策略文件
|
||||
if 'strategy' in name and '.pyc' not in name:
|
||||
# 模块名称需要上前缀
|
||||
moduleName = 'ctaAlgo.strategy.' + name.replace('.py', '')
|
||||
|
||||
# 使用importlib动态载入模块
|
||||
module = importlib.import_module(moduleName)
|
||||
|
||||
# 遍历模块下的对象,只有名称中包含'Strategy'的才是策略类
|
||||
for k in dir(module):
|
||||
if 'Strategy' in k:
|
||||
v = module.__getattribute__(k)
|
||||
STRATEGY_CLASS[k] = v
|
@ -17,9 +17,9 @@ from ctaTemplate import CtaTemplate
|
||||
|
||||
|
||||
########################################################################
|
||||
class DoubleEmaDemo(CtaTemplate):
|
||||
class EmaDemoStrategy(CtaTemplate):
|
||||
"""双指数均线策略Demo"""
|
||||
className = 'DoubleEmaDemo'
|
||||
className = 'EmaDemoStrategy'
|
||||
author = u'用Python的交易员'
|
||||
|
||||
# 策略参数
|
||||
@ -59,7 +59,7 @@ class DoubleEmaDemo(CtaTemplate):
|
||||
#----------------------------------------------------------------------
|
||||
def __init__(self, ctaEngine, setting):
|
||||
"""Constructor"""
|
||||
super(DoubleEmaDemo, self).__init__(ctaEngine, setting)
|
||||
super(EmaDemoStrategy, self).__init__(ctaEngine, setting)
|
||||
|
||||
# 注意策略类中的可变对象属性(通常是list和dict等),在策略初始化时需要重新创建,
|
||||
# 否则会出现多个策略实例之间数据共享的情况,有可能导致潜在的策略逻辑错误风险,
|
||||
@ -188,10 +188,10 @@ class DoubleEmaDemo(CtaTemplate):
|
||||
|
||||
|
||||
########################################################################################
|
||||
class OrderManagementDemo(CtaTemplate):
|
||||
class OrderManagementDemoStrategy(CtaTemplate):
|
||||
"""基于tick级别细粒度撤单追单测试demo"""
|
||||
|
||||
className = 'OrderManagementDemo'
|
||||
className = 'OrderManagementDemoStrategy'
|
||||
author = u'用Python的交易员'
|
||||
|
||||
# 策略参数
|
||||
@ -216,7 +216,7 @@ class OrderManagementDemo(CtaTemplate):
|
||||
#----------------------------------------------------------------------
|
||||
def __init__(self, ctaEngine, setting):
|
||||
"""Constructor"""
|
||||
super(OrderManagementDemo, self).__init__(ctaEngine, setting)
|
||||
super(OrderManagementDemoStrategy, self).__init__(ctaEngine, setting)
|
||||
|
||||
self.lastOrder = None
|
||||
self.orderType = ''
|
6
vn.trader/huobiGateway/HUOBI_connect.json
Normal file
6
vn.trader/huobiGateway/HUOBI_connect.json
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
"accessKey": "3f669293-60e6dd7f-8e39c295-5aae5",
|
||||
"secretKey": "7050aec8-43fc680d-06471837-57e38",
|
||||
"interval": 0.5,
|
||||
"market": "cny"
|
||||
}
|
0
vn.trader/huobiGateway/__init__.py
Normal file
0
vn.trader/huobiGateway/__init__.py
Normal file
347
vn.trader/huobiGateway/huobiGateway.py
Normal file
347
vn.trader/huobiGateway/huobiGateway.py
Normal file
@ -0,0 +1,347 @@
|
||||
# encoding: UTF-8
|
||||
|
||||
'''
|
||||
vn.huobi的gateway接入
|
||||
'''
|
||||
|
||||
|
||||
import os
|
||||
import json
|
||||
from datetime import datetime
|
||||
from copy import copy
|
||||
from threading import Condition
|
||||
from Queue import Queue
|
||||
from threading import Thread
|
||||
|
||||
import vnhuobi
|
||||
from vtGateway import *
|
||||
|
||||
|
||||
########################################################################
|
||||
class HuobiGateway(VtGateway):
|
||||
"""火币接口"""
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def __init__(self, eventEngine, gatewayName='HUOBI'):
|
||||
"""Constructor"""
|
||||
super(HuobiGateway, self).__init__(eventEngine, gatewayName)
|
||||
|
||||
self.market = 'cny'
|
||||
|
||||
self.tradeApi = HuobiTradeApi(self)
|
||||
self.dataApi = HuobiDataApi(self)
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def connect(self):
|
||||
"""连接"""
|
||||
# 载入json文件
|
||||
fileName = self.gatewayName + '_connect.json'
|
||||
path = os.path.abspath(os.path.dirname(__file__))
|
||||
fileName = os.path.join(path, fileName)
|
||||
|
||||
try:
|
||||
f = file(fileName)
|
||||
except IOError:
|
||||
log = VtLogData()
|
||||
log.gatewayName = self.gatewayName
|
||||
log.logContent = u'读取连接配置出错,请检查'
|
||||
self.onLog(log)
|
||||
return
|
||||
|
||||
# 解析json文件
|
||||
setting = json.load(f)
|
||||
try:
|
||||
accessKey = str(setting['accessKey'])
|
||||
secretKey = str(setting['secretKey'])
|
||||
interval = setting['interval']
|
||||
market = setting['market']
|
||||
except KeyError:
|
||||
log = VtLogData()
|
||||
log.gatewayName = self.gatewayName
|
||||
log.logContent = u'连接配置缺少字段,请检查'
|
||||
self.onLog(log)
|
||||
return
|
||||
|
||||
# 初始化接口
|
||||
self.tradeApi.connect(accessKey, secretKey)
|
||||
self.writeLog(u'交易接口初始化成功')
|
||||
|
||||
self.dataApi.connect(interval)
|
||||
self.writeLog(u'行情接口初始化成功')
|
||||
|
||||
# 启动查询
|
||||
#self.initQuery()
|
||||
#self.startQuery()
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def writeLog(self, content):
|
||||
"""发出日志"""
|
||||
log = VtLogData()
|
||||
log.gatewayName = self.gatewayName
|
||||
log.logContent = content
|
||||
self.onLog(log)
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def subscribe(self, subscribeReq):
|
||||
"""订阅行情,自动订阅全部行情,无需实现"""
|
||||
pass
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def sendOrder(self, orderReq):
|
||||
"""发单"""
|
||||
pass
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def cancelOrder(self, cancelOrderReq):
|
||||
"""撤单"""
|
||||
pass
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def qryAccount(self):
|
||||
"""查询账户资金"""
|
||||
pass
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def qryPosition(self):
|
||||
"""查询持仓"""
|
||||
pass
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def close(self):
|
||||
"""关闭"""
|
||||
self.tradeApi.exit()
|
||||
self.dataApi.exit()
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def initQuery(self):
|
||||
"""初始化连续查询"""
|
||||
if self.qryEnabled:
|
||||
# 需要循环的查询函数列表
|
||||
self.qryFunctionList = [self.qryAccount]
|
||||
|
||||
self.qryCount = 0 # 查询触发倒计时
|
||||
self.qryTrigger = 2 # 查询触发点
|
||||
self.qryNextFunction = 0 # 上次运行的查询函数索引
|
||||
|
||||
self.startQuery()
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def query(self, event):
|
||||
"""注册到事件处理引擎上的查询函数"""
|
||||
self.qryCount += 1
|
||||
|
||||
if self.qryCount > self.qryTrigger:
|
||||
# 清空倒计时
|
||||
self.qryCount = 0
|
||||
|
||||
# 执行查询函数
|
||||
function = self.qryFunctionList[self.qryNextFunction]
|
||||
function()
|
||||
|
||||
# 计算下次查询函数的索引,如果超过了列表长度,则重新设为0
|
||||
self.qryNextFunction += 1
|
||||
if self.qryNextFunction == len(self.qryFunctionList):
|
||||
self.qryNextFunction = 0
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def startQuery(self):
|
||||
"""启动连续查询"""
|
||||
self.eventEngine.register(EVENT_TIMER, self.query)
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def setQryEnabled(self, qryEnabled):
|
||||
"""设置是否要启动循环查询"""
|
||||
self.qryEnabled = qryEnabled
|
||||
|
||||
|
||||
########################################################################
|
||||
class HuobiTradeApi(vnhuobi.TradeApi):
|
||||
"""交易接口"""
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def __init__(self, gateway):
|
||||
"""Constructor"""
|
||||
super(HuobiTradeApi, self).__init__()
|
||||
|
||||
self.gateway = gateway
|
||||
self.gatewayName = gateway.gatewayName
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def onError(self, error, reqID):
|
||||
"""错误推送"""
|
||||
err = VtErrorData()
|
||||
err.gatewayName = self.gatewayName
|
||||
err.errorMsg = str(error)
|
||||
err.errorTime = datetime.now().strftime('%H:%M:%S')
|
||||
self.gateway.onError(err)
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def onGetAccountInfo(self, data, reqID):
|
||||
"""查询账户回调"""
|
||||
# 推送账户数据
|
||||
account = VtAccountData()
|
||||
account.gatewayName = self.gatewayName
|
||||
account.balance = data['net_asset']
|
||||
self.gateway.onAccount(account)
|
||||
|
||||
# 推送持仓数据
|
||||
if self.market == 'cny':
|
||||
posCny = VtPositionData()
|
||||
posCny.gatewayName = self.gatewayName
|
||||
posCny.position = data['available_cny_display']
|
||||
posCny.frozen = data['frozen_cny_display']
|
||||
self.gateway.onPosition(posCny)
|
||||
|
||||
posLtc = VtPositionData()
|
||||
posLtc.gatewayName = self.gatewayName
|
||||
posLtc.position = data['available_ltc_display']
|
||||
posLtc.frozen = data['frozen_ltc_display']
|
||||
self.gateway.onPosition(posLtc)
|
||||
else:
|
||||
posUsd = VtPositionData()
|
||||
posUsd.gatewayName = self.gatewayName
|
||||
posUsd.position = data['available_usd_display']
|
||||
posUsd.frozen = data['frozen_usd_display']
|
||||
self.gateway.onPosition(posUsd)
|
||||
|
||||
posBtc = VtPositionData()
|
||||
posBtc.gatewayName = self.gatewayName
|
||||
posBtc.position = data['available_btc_display']
|
||||
posBtc.frozen = data['frozen_btc_display']
|
||||
self.gateway.onPosition(posBtc)
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def onGetOrders(self, data, reqID):
|
||||
"""查询委托回调"""
|
||||
for d in data:
|
||||
order = VtOrderData()
|
||||
order.gatewayName = self.gatewayName
|
||||
|
||||
order
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def onOrderInfo(self, data, reqID):
|
||||
"""委托详情回调"""
|
||||
print data
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def onBuy(self, data, reqID):
|
||||
"""买入回调"""
|
||||
print data
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def onSell(self, data, reqID):
|
||||
"""卖出回调"""
|
||||
print data
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def onBuyMarket(self, data, reqID):
|
||||
"""市价买入回调"""
|
||||
print data
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def onSellMarket(self, data, reqID):
|
||||
"""市价卖出回调"""
|
||||
print data
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def onCancelOrder(self, data, reqID):
|
||||
"""撤单回调"""
|
||||
print data
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def onGetNewDealOrders(self, data, reqID):
|
||||
"""查询最新成交回调"""
|
||||
print data
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def onGetOrderIdByTradeId(self, data, reqID):
|
||||
"""通过成交编号查询委托编号回调"""
|
||||
print data
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def onWithdrawCoin(self, data, reqID):
|
||||
"""提币回调"""
|
||||
print data
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def onCancelWithdrawCoin(self, data, reqID):
|
||||
"""取消提币回调"""
|
||||
print data
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def onGetWithdrawCoinResult(self, data, reqID):
|
||||
"""查询提币结果回调"""
|
||||
print data
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def onTransfer(self, data, reqID):
|
||||
"""转账回调"""
|
||||
print data
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def onLoan(self, data, reqID):
|
||||
"""申请杠杆回调"""
|
||||
print data
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def onRepayment(self, data, reqID):
|
||||
"""归还杠杆回调"""
|
||||
print data
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def onLoanAvailable(self, data, reqID):
|
||||
"""查询杠杆额度回调"""
|
||||
print data
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def onGetLoans(self, data, reqID):
|
||||
"""查询杠杆列表"""
|
||||
print data
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def connect(self, accessKey, secretKey, market):
|
||||
"""连接服务器"""
|
||||
self.market = market
|
||||
|
||||
self.init(accessKey, secretKey)
|
||||
|
||||
|
||||
########################################################################
|
||||
class HuobiDataApi(vnhuobi.DataApi):
|
||||
"""行情接口"""
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def __init__(self, gateway):
|
||||
"""Constructor"""
|
||||
super(HuobiDataApi, self).__init__()
|
||||
|
||||
self.gateway = gateway
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def onTick(self, data):
|
||||
"""实时成交推送"""
|
||||
print data
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def onQuote(self, data):
|
||||
"""实时报价推送"""
|
||||
print data
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def onDepth(self, data):
|
||||
"""实时深度推送"""
|
||||
print data
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def connect(self, interval):
|
||||
"""连接服务器"""
|
||||
self.init(interval)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
650
vn.trader/huobiGateway/vnhuobi.py
Normal file
650
vn.trader/huobiGateway/vnhuobi.py
Normal file
@ -0,0 +1,650 @@
|
||||
# encoding: utf-8
|
||||
|
||||
import urllib
|
||||
import hashlib
|
||||
|
||||
import json
|
||||
import requests
|
||||
from time import time, sleep
|
||||
from Queue import Queue, Empty
|
||||
from threading import Thread
|
||||
|
||||
|
||||
# 常量定义
|
||||
COINTYPE_BTC = 1
|
||||
COINTYPE_LTC = 2
|
||||
|
||||
ACCOUNTTYPE_CNY = 1
|
||||
ACCOUNTTYPE_USD = 2
|
||||
|
||||
LOANTYPE_CNY = 1
|
||||
LOANTYPE_BTC = 2
|
||||
LOANTYPE_LTC = 3
|
||||
LOANTYPE_USD = 4
|
||||
|
||||
MARKETTYPE_CNY = 'cny'
|
||||
MARKETTYPE_USD = 'usd'
|
||||
|
||||
SYMBOL_BTCCNY = 'BTC_CNY'
|
||||
SYMBOL_LTCCNY = 'LTC_CNY'
|
||||
SYMBOL_BTCUSD = 'BTC_USD'
|
||||
|
||||
PERIOD_1MIN = '001'
|
||||
PERIOD_5MIN = '005'
|
||||
PERIOD_15MIN = '015'
|
||||
PERIOD_30MIN = '030'
|
||||
PERIOD_60MIN = '060'
|
||||
PERIOD_DAILY = '100'
|
||||
PERIOD_WEEKLY = '200'
|
||||
PERIOD_MONTHLY = '300'
|
||||
PERIOD_ANNUALLY = '400'
|
||||
|
||||
# API相关定义
|
||||
HUOBI_TRADE_API = 'https://api.huobi.com/apiv3'
|
||||
|
||||
# 功能代码
|
||||
FUNCTIONCODE_GETACCOUNTINFO = 'get_account_info'
|
||||
FUNCTIONCODE_GETORDERS = 'get_orders'
|
||||
FUNCTIONCODE_ORDERINFO = 'order_info'
|
||||
FUNCTIONCODE_BUY = 'buy'
|
||||
FUNCTIONCODE_SELL = 'sell'
|
||||
FUNCTIONCODE_BUYMARKET = 'buy_market'
|
||||
FUNCTIONCODE_SELLMARKET = 'sell_market'
|
||||
FUNCTIONCODE_CANCELORDER = 'cancel_order'
|
||||
FUNCTIONCODE_GETNEWDEALORDERS = 'get_new_deal_orders'
|
||||
FUNCTIONCODE_GETORDERIDBYTRADEID = 'get_order_id_by_trade_id'
|
||||
FUNCTIONCODE_WITHDRAWCOIN = 'withdraw_coin'
|
||||
FUNCTIONCODE_CANCELWITHDRAWCOIN = 'cancel_withdraw_coin'
|
||||
FUNCTIONCODE_GETWITHDRAWCOINRESULT = 'get_withdraw_coin_result'
|
||||
FUNCTIONCODE_TRANSFER = 'transfer'
|
||||
FUNCTIONCODE_LOAN = 'loan'
|
||||
FUNCTIONCODE_REPAYMENT = 'repayment'
|
||||
FUNCTIONCODE_GETLOANAVAILABLE = 'get_loan_available'
|
||||
FUNCTIONCODE_GETLOANS = 'get_loans'
|
||||
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def signature(params):
|
||||
"""生成签名"""
|
||||
params = sorted(params.iteritems(), key=lambda d:d[0], reverse=False)
|
||||
message = urllib.urlencode(params)
|
||||
|
||||
m = hashlib.md5()
|
||||
m.update(message)
|
||||
m.digest()
|
||||
|
||||
sig=m.hexdigest()
|
||||
return sig
|
||||
|
||||
|
||||
########################################################################
|
||||
class TradeApi(object):
|
||||
"""交易接口"""
|
||||
DEBUG = True
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def __init__(self):
|
||||
"""Constructor"""
|
||||
self.accessKey = ''
|
||||
self.secretKey = ''
|
||||
|
||||
self.active = False # API工作状态
|
||||
self.reqID = 0 # 请求编号
|
||||
self.reqQueue = Queue() # 请求队列
|
||||
self.reqThread = Thread(target=self.processQueue) # 请求处理线程
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def processRequest(self, req):
|
||||
"""处理请求"""
|
||||
# 读取方法和参数
|
||||
method = req['method']
|
||||
params = req['params']
|
||||
optional = req['optional']
|
||||
|
||||
# 在参数中增加必须的字段
|
||||
params['created'] = long(time())
|
||||
params['access_key'] = self.accessKey
|
||||
params['secret_key'] = self.secretKey
|
||||
params['method'] = method
|
||||
|
||||
# 添加签名
|
||||
sign = signature(params)
|
||||
params['sign'] = sign
|
||||
del params['secret_key']
|
||||
|
||||
# 添加选填参数
|
||||
if optional:
|
||||
params.update(optional)
|
||||
|
||||
# 发送请求
|
||||
payload = urllib.urlencode(params)
|
||||
|
||||
r = requests.post(HUOBI_TRADE_API_API, params=payload)
|
||||
if r.status_code == 200:
|
||||
data = r.json()
|
||||
return data
|
||||
else:
|
||||
return None
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def processQueue(self):
|
||||
"""处理请求队列中的请求"""
|
||||
while self.active:
|
||||
try:
|
||||
req = self.reqQueue.get(block=True, timeout=1) # 获取请求的阻塞为一秒
|
||||
callback = req['callback']
|
||||
reqID = req['reqID']
|
||||
|
||||
data = self.processRequest(req)
|
||||
|
||||
# 请求失败
|
||||
if 'code' in data and 'message' in data:
|
||||
error = u'错误信息:%s' %data['message']
|
||||
self.onError(error, reqID)
|
||||
# 请求成功
|
||||
else:
|
||||
if self.DEBUG:
|
||||
print callback.__name__
|
||||
callback(data, reqID)
|
||||
|
||||
except Empty:
|
||||
pass
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def sendRequest(self, method, params, callback, optional=None):
|
||||
"""发送请求"""
|
||||
# 请求编号加1
|
||||
self.reqID += 1
|
||||
|
||||
# 生成请求字典并放入队列中
|
||||
req = {}
|
||||
req['method'] = method
|
||||
req['params'] = params
|
||||
req['callback'] = callback
|
||||
req['optional'] = optional
|
||||
req['reqID'] = self.reqID
|
||||
self.reqQueue.put(req)
|
||||
|
||||
# 返回请求编号
|
||||
return self.reqID
|
||||
|
||||
####################################################
|
||||
## 主动函数
|
||||
####################################################
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def init(self, accessKey, secretKey):
|
||||
"""初始化"""
|
||||
self.accessKey = accessKey
|
||||
self.secretKey = secretKey
|
||||
|
||||
self.active = True
|
||||
self.reqThread.start()
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def exit(self):
|
||||
"""退出"""
|
||||
self.active = False
|
||||
self.reqThread.join()
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def getAccountInfo(self, market='cny'):
|
||||
"""查询账户"""
|
||||
method = FUNCTIONCODE_GETACCOUNTINFO
|
||||
params = {}
|
||||
callback = self.onGetAccountInfo
|
||||
optional = {'market': market}
|
||||
return self.sendRequest(method, params, callback, optional)
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def getOrders(self, coinType=COINTYPE_BTC, market='cny'):
|
||||
"""查询委托"""
|
||||
method = FUNCTIONCODE_GETORDERS
|
||||
params = {'coin_type': coinType}
|
||||
callback = self.onGetOrders
|
||||
optional = {'market': market}
|
||||
return self.sendRequest(method, params, callback, optional)
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def orderInfo(self, id_, coinType=COINTYPE_BTC, market='cny'):
|
||||
"""获取委托详情"""
|
||||
method = FUNCTIONCODE_ORDERINFO
|
||||
params = {
|
||||
'coin_type': coinType,
|
||||
'id': id_
|
||||
}
|
||||
callback = self.onOrderInfo
|
||||
optional = {'market': market}
|
||||
return self.sendRequest(method, params, callback, optional)
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def buy(self, price, amount, coinType=COINTYPE_BTC,
|
||||
tradePassword='', tradeId = '', market='cny'):
|
||||
"""委托买入"""
|
||||
method = FUNCTIONCODE_BUY
|
||||
params = {
|
||||
'coin_type': coinType,
|
||||
'price': price,
|
||||
'amount': amount
|
||||
}
|
||||
callback = self.onBuy
|
||||
optional = {
|
||||
'trade_password': tradePassword,
|
||||
'trade_id': tradeId,
|
||||
'market': market
|
||||
}
|
||||
return self.sendRequest(method, params, callback, optional)
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def sell(self, price, amount, coinType=COINTYPE_BTC,
|
||||
tradePassword='', tradeId = '', market='cny'):
|
||||
"""委托卖出"""
|
||||
method = FUNCTIONCODE_SELL
|
||||
params = {
|
||||
'coin_type': coinType,
|
||||
'price': price,
|
||||
'amount': amount
|
||||
}
|
||||
callback = self.onSell
|
||||
optional = {
|
||||
'trade_password': tradePassword,
|
||||
'trade_id': tradeId,
|
||||
'market': market
|
||||
}
|
||||
return self.sendRequest(method, params, callback, optional)
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def buyMarket(self, amount, coinType=COINTYPE_BTC,
|
||||
tradePassword='', tradeId = '', market='cny'):
|
||||
"""市价买入"""
|
||||
method = FUNCTIONCODE_BUYMARKET
|
||||
params = {
|
||||
'coin_type': coinType,
|
||||
'amount': amount
|
||||
}
|
||||
callback = self.onBuyMarket
|
||||
optional = {
|
||||
'trade_password': tradePassword,
|
||||
'trade_id': tradeId,
|
||||
'market': market
|
||||
}
|
||||
return self.sendRequest(method, params, callback, optional)
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def sellMarket(self, amount, coinType=COINTYPE_BTC,
|
||||
tradePassword='', tradeId = '', market='cny'):
|
||||
"""市价卖出"""
|
||||
method = FUNCTIONCODE_SELLMARKET
|
||||
params = {
|
||||
'coin_type': coinType,
|
||||
'amount': amount
|
||||
}
|
||||
callback = self.onSellMarket
|
||||
optional = {
|
||||
'trade_password': tradePassword,
|
||||
'trade_id': tradeId,
|
||||
'market': market
|
||||
}
|
||||
return self.sendRequest(method, params, callback, optional)
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def cancelOrder(self, id_, coinType=COINTYPE_BTC, market='cny'):
|
||||
"""撤销委托"""
|
||||
method = FUNCTIONCODE_CANCELORDER
|
||||
params = {
|
||||
'coin_type': coinType,
|
||||
'id': id_
|
||||
}
|
||||
callback = self.onCancelOrder
|
||||
optional = {'market': market}
|
||||
return self.sendRequest(method, params, callback, optional)
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def getNewDealOrders(self, market='cny'):
|
||||
"""查询最新10条成交"""
|
||||
method = FUNCTIONCODE_GETNEWDEALORDERS
|
||||
params = {}
|
||||
callback = self.onGetNewDealOrders
|
||||
optional = {'market': market}
|
||||
return self.sendRequest(method, params, callback, optional)
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def getOrderIdByTradeId(self, tradeId, coinType=COINTYPE_BTC,
|
||||
market='cny'):
|
||||
"""通过成交编号查询委托编号"""
|
||||
method = FUNCTIONCODE_GETORDERIDBYTRADEID
|
||||
params = {
|
||||
'coin_type': coinType,
|
||||
'trade_id': tradeId
|
||||
}
|
||||
callback = self.onGetOrderIdByTradeId
|
||||
optional = {'market': market}
|
||||
return self.sendRequest(method, params, callback, optional)
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def withdrawCoin(self, withdrawAddress, withdrawAmount,
|
||||
coinType=COINTYPE_BTC, tradePassword='',
|
||||
market='cny', withdrawFee=0.0001):
|
||||
"""提币"""
|
||||
method = FUNCTIONCODE_WITHDRAWCOIN
|
||||
params = {
|
||||
'coin_type': coinType,
|
||||
'withdraw_address': withdrawAddress,
|
||||
'withdraw_amount': withdrawAmount
|
||||
}
|
||||
callback = self.onWithdrawCoin
|
||||
optional = {
|
||||
'market': market,
|
||||
'withdraw_fee': withdrawFee
|
||||
}
|
||||
return self.sendRequest(method, params, callback, optional)
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def cancelWithdrawCoin(self, id_, market='cny'):
|
||||
"""取消提币"""
|
||||
method = FUNCTIONCODE_CANCELWITHDRAWCOIN
|
||||
params = {'withdraw_coin_id': id_}
|
||||
callback = self.onCancelWithdrawCoin
|
||||
optional = {'market': market}
|
||||
return self.sendRequest(method, params, callback, optional)
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def onGetWithdrawCoinResult(self, id_, market='cny'):
|
||||
"""查询提币结果"""
|
||||
method = FUNCTIONCODE_GETWITHDRAWCOINRESULT
|
||||
params = {'withdraw_coin_id': id_}
|
||||
callback = self.onGetWithdrawCoinResult
|
||||
optional = {'market': market}
|
||||
return self.sendRequest(method, params, callback, optional)
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def transfer(self, amountFrom, amountTo, amount,
|
||||
coinType=COINTYPE_BTC ):
|
||||
"""账户内转账"""
|
||||
method = FUNCTIONCODE_TRANSFER
|
||||
params = {
|
||||
'amount_from': amountFrom,
|
||||
'amount_to': amountTo,
|
||||
'amount': amount,
|
||||
'coin_type': coinType
|
||||
}
|
||||
callback = self.onTransfer
|
||||
optional = {}
|
||||
return self.sendRequest(method, params, callback, optional)
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def loan(self, amount, loan_type=LOANTYPE_CNY,
|
||||
market=MARKETTYPE_CNY):
|
||||
"""申请杠杆"""
|
||||
method = FUNCTIONCODE_LOAN
|
||||
params = {
|
||||
'amount': amount,
|
||||
'loan_type': loan_type
|
||||
}
|
||||
callback = self.onLoan
|
||||
optional = {'market': market}
|
||||
return self.sendRequest(method, params, callback, optional)
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def repayment(self, id_, amount, repayAll=0,
|
||||
market=MARKETTYPE_CNY):
|
||||
"""归还杠杆"""
|
||||
method = FUNCTIONCODE_REPAYMENT
|
||||
params = {
|
||||
'loan_id': id_,
|
||||
'amount': amount
|
||||
}
|
||||
callback = self.onRepayment
|
||||
optional = {
|
||||
'repay_all': repayAll,
|
||||
'market': market
|
||||
}
|
||||
return self.sendRequest(method, params, callback, optional)
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def getLoanAvailable(self, market='cny'):
|
||||
"""查询杠杆额度"""
|
||||
method = FUNCTIONCODE_GETLOANAVAILABLE
|
||||
params = {}
|
||||
callback = self.onLoanAvailable
|
||||
optional = {'market': market}
|
||||
return self.sendRequest(method, params, callback, optional)
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def getLoans(self, market='cny'):
|
||||
"""查询杠杆列表"""
|
||||
method = FUNCTIONCODE_GETLOANS
|
||||
params = {}
|
||||
callback = self.onGetLoans
|
||||
optional = {'market': market}
|
||||
return self.sendRequest(method, params, callback, optional)
|
||||
|
||||
####################################################
|
||||
## 回调函数
|
||||
####################################################
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def onError(self, error, reqID):
|
||||
"""错误推送"""
|
||||
print error, reqID
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def onGetAccountInfo(self, data, reqID):
|
||||
"""查询账户回调"""
|
||||
print data
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def onGetOrders(self, data, reqID):
|
||||
"""查询委托回调"""
|
||||
print data
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def onOrderInfo(self, data, reqID):
|
||||
"""委托详情回调"""
|
||||
print data
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def onBuy(self, data, reqID):
|
||||
"""买入回调"""
|
||||
print data
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def onSell(self, data, reqID):
|
||||
"""卖出回调"""
|
||||
print data
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def onBuyMarket(self, data, reqID):
|
||||
"""市价买入回调"""
|
||||
print data
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def onSellMarket(self, data, reqID):
|
||||
"""市价卖出回调"""
|
||||
print data
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def onCancelOrder(self, data, reqID):
|
||||
"""撤单回调"""
|
||||
print data
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def onGetNewDealOrders(self, data, reqID):
|
||||
"""查询最新成交回调"""
|
||||
print data
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def onGetOrderIdByTradeId(self, data, reqID):
|
||||
"""通过成交编号查询委托编号回调"""
|
||||
print data
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def onWithdrawCoin(self, data, reqID):
|
||||
"""提币回调"""
|
||||
print data
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def onCancelWithdrawCoin(self, data, reqID):
|
||||
"""取消提币回调"""
|
||||
print data
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def onGetWithdrawCoinResult(self, data, reqID):
|
||||
"""查询提币结果回调"""
|
||||
print data
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def onTransfer(self, data, reqID):
|
||||
"""转账回调"""
|
||||
print data
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def onLoan(self, data, reqID):
|
||||
"""申请杠杆回调"""
|
||||
print data
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def onRepayment(self, data, reqID):
|
||||
"""归还杠杆回调"""
|
||||
print data
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def onLoanAvailable(self, data, reqID):
|
||||
"""查询杠杆额度回调"""
|
||||
print data
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def onGetLoans(self, data, reqID):
|
||||
"""查询杠杆列表"""
|
||||
print data
|
||||
|
||||
|
||||
########################################################################
|
||||
class DataApi(object):
|
||||
"""行情接口"""
|
||||
TICK_SYMBOL_URL = {
|
||||
SYMBOL_BTCCNY: 'http://api.huobi.com/staticmarket/detail_btc_json.js',
|
||||
SYMBOL_LTCCNY: 'http://api.huobi.com/staticmarket/detail_ltc_json.js',
|
||||
SYMBOL_BTCUSD: 'http://api.huobi.com/usdmarket/detail_btc_json.js'
|
||||
}
|
||||
|
||||
QUOTE_SYMBOL_URL = {
|
||||
SYMBOL_BTCCNY: 'http://api.huobi.com/staticmarket/ticker_btc_json.js',
|
||||
SYMBOL_LTCCNY: 'http://api.huobi.com/staticmarket/ticker_ltc_json.js',
|
||||
SYMBOL_BTCUSD: 'http://api.huobi.com/usdmarket/ticker_btc_json.js'
|
||||
}
|
||||
|
||||
DEPTH_SYMBOL_URL = {
|
||||
SYMBOL_BTCCNY: 'http://api.huobi.com/staticmarket/depth_btc_json.js',
|
||||
SYMBOL_LTCCNY: 'http://api.huobi.com/staticmarket/depth_ltc_json.js',
|
||||
SYMBOL_BTCUSD: 'http://api.huobi.com/usdmarket/depth_btc_json.js'
|
||||
}
|
||||
|
||||
KLINE_SYMBOL_URL = {
|
||||
SYMBOL_BTCCNY: 'http://api.huobi.com/staticmarket/btc_kline_[period]_json.js',
|
||||
SYMBOL_LTCCNY: 'http://api.huobi.com/staticmarket/btc_kline_[period]_json.js',
|
||||
SYMBOL_BTCUSD: 'http://api.huobi.com/usdmarket/btc_kline_[period]_json.js'
|
||||
}
|
||||
|
||||
DEBUG = True
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def __init__(self):
|
||||
"""Constructor"""
|
||||
self.active = False
|
||||
|
||||
self.taskInterval = 0 # 每轮请求延时
|
||||
self.taskList = [] # 订阅的任务列表
|
||||
self.taskThread = Thread(target=self.run) # 处理任务的线程
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def init(self, interval):
|
||||
"""初始化"""
|
||||
self.taskInterval = interval
|
||||
self.DEBUG = debug
|
||||
|
||||
self.active = True
|
||||
self.taskThread.start()
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def exit(self):
|
||||
"""退出"""
|
||||
self.active = False
|
||||
|
||||
if self.taskThread.isAlive():
|
||||
self.taskThread.join()
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def run(self):
|
||||
"""连续运行"""
|
||||
while self.active:
|
||||
for url, callback in self.taskList:
|
||||
try:
|
||||
r = requests.get(url)
|
||||
if r.status_code == 200:
|
||||
data = r.json()
|
||||
if self.DEBUG:
|
||||
print callback.__name__
|
||||
callback(data)
|
||||
except Exception, e:
|
||||
print e
|
||||
|
||||
sleep(self.taskInterval)
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def subscribeTick(self, symbol):
|
||||
"""订阅实时成交数据"""
|
||||
url = self.TICK_SYMBOL_URL[symbol]
|
||||
task = (url, self.onTick)
|
||||
self.taskList.append(task)
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def subscribeQuote(self, symbol):
|
||||
"""订阅实时报价数据"""
|
||||
url = self.QUOTE_SYMBOL_URL[symbol]
|
||||
task = (url, self.onQuote)
|
||||
self.taskList.append(task)
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def subscribeDepth(self, symbol, level=0):
|
||||
"""订阅深度数据"""
|
||||
url = self.DEPTH_SYMBOL_URL[symbol]
|
||||
|
||||
if level:
|
||||
url = url.replace('json', str(level))
|
||||
|
||||
task = (url, self.onDepth)
|
||||
self.taskList.append(task)
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def onTick(self, data):
|
||||
"""实时成交推送"""
|
||||
print data
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def onQuote(self, data):
|
||||
"""实时报价推送"""
|
||||
print data
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def onDepth(self, data):
|
||||
"""实时深度推送"""
|
||||
print data
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def getKline(self, symbol, period, length=0):
|
||||
"""查询K线数据"""
|
||||
url = self.KLINE_SYMBOL_URL[symbol]
|
||||
url = url.replace('[period]', period)
|
||||
|
||||
if length:
|
||||
url = url + '?length=' + str(length)
|
||||
|
||||
try:
|
||||
r = requests.get(url)
|
||||
if r.status_code == 200:
|
||||
data = r.json()
|
||||
return data
|
||||
except Exception, e:
|
||||
print e
|
||||
return None
|
@ -4,8 +4,7 @@
|
||||
vn.okcoin的gateway接入
|
||||
|
||||
注意:
|
||||
1. 该接口尚处于测试阶段,用于实盘请谨慎
|
||||
2. 目前仅支持USD和CNY的现货交易,USD的期货合约交易暂不支持
|
||||
1. 前仅支持USD和CNY的现货交易,USD的期货合约交易暂不支持
|
||||
'''
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user