聚币网/coinegg API使用教程 附demo代码

******* 2018.14 更新 ***********
现在聚币网已经被关闭了,但是所有的币都可以转移到CoinEgg网了,币种和以前一模一样,只是用户参与度减少了很多,市场不是一个有效的市场,但是这对于操盘手来说,更加是一个收益大的地方。
使用下面链接注册后,用户可以返30%的佣金。 其实也无所谓,佣金不会很多,一次也就几分钱到几毛钱,自己去官网注册也可以。看个人心情啦。
 
http://www.coinegg.com/user/register?inv=7d91a
 
 后续会就coinegg写一个自动交易的系统出来
 

******* 8.28 更新 ***********
不少人反应签名不通过,经过调试,发现是加密前的字符拼接的顺序问题,这个拼接顺序要和你post上去的顺序要一致,才能通过。如果出现104的返回代码,说明是你的顺序问题,说明你的签名没有成功。
 
贴代码说明下: 使用字典循环,就可以知道正确的拼接顺序。 下面的代码是获取成交订单的。
    def Trade_list(self, coin):
'''
Trade_list(挂单查询)
您指定时间后的挂单,可以根据类型查询,比如查看正在挂单和全部挂单
Path:/api/v1/trade_list/
Request类型:POST
参数
key - API key
signature - signature
nonce - nonce
since - unix timestamp(utc timezone) default == 0, i.e. 返回所有
coin - 币种简称,例如btc、ltc、xas
type - 挂单类型[open:正在挂单, all:所有挂单]

返回JSON dictionary
id - 挂单ID
datetime - date and time
type - "buy" or "sell"
price - price
amount_original - 下单时数量
amount_outstanding - 当前剩余数量
'''
url = self.host + '/api/v1/trade_list/'
time.sleep(random.random())
nonce = self.get_nonce_time()
types = 'all'
since = 0
parameters = {'key': self.public_key, 'nonce': str(nonce), 'type': types, 'coin': coin, 'signature': ''}
# print parameters
post_data = ''
for k, v in parameters.items():
if not isinstance(v, str):
#if type(v) is not types.StringType:
v = str(v)
post_data = post_data + k
post_data = post_data + '=' + v + '&'

#print 'post-data:\n',post_data
post_data = post_data[:-1]
post_data = post_data.replace('&signature=', '')
#print post_data

signature = hmac.new(self.md5, post_data, digestmod=hashlib.sha256).digest()
sig = self.toHex(signature)
parameters['signature'] = sig
#print parameters
r = requests.post(url=url, data=parameters)
s = r.json()
#print s
return s

 
如果还是没有解决的话就网站内私信我看看问题所在。

******************************************* 原文内容 ***************************************************
 

 官方有API的文档,可是这个文档就像一个草稿一样,两个基本例子都没有。 所以自己摸索一下,自己写一个现成的例子给大家,可以有个参考。 下面的例子亲测成功。 
 
首先看一下官方的API文档:


一、API使用说明

1、请求过程说明

1.1 构造请求数据,用户数据按照Jubi提供的接口规则,通过程序生成签名和要传输给Jubi的数据集合;

1.2 发送请求数据,把构造完成的数据集合通过POST/GET提交的方式传递给Jubi;

1.3 Jubi对请求数据进行处理,服务器在接收到请求后,会首先进行安全校验,验证通过后便会处理该次发送过来的请求;

1.4 返回响应结果数据,Jubi把响应结果以JSON的格式反馈给用户,具体的响应格式,错误代码参见接口部分;

1.5 对获取的返回结果数据进行处理;

2、安全认证

所有的private API都需要经过认证

Api的申请可以到财务中心 -> API,申请得到私钥和公钥,私钥Jubi将不做储存,一旦丢失将无法找回

注意:请勿向任何人泄露这两个参数,这像您的密码一样重要

2.签名机制

每次请求private api 都需要验证签名,发送的参数示例:

$param = array(

amount => 1,

price => 10000,

type => 'buy',

nonce => 141377098123

key => 5zi7w-4mnes-swmc4-egg9b-f2iqw-396z4-g541b

signature => 459c69d25c496765191582d9611028b9974830e9dfafd762854669809290ed82

);

nonce 可以理解为一个递增的整数:http://zh.wikipedia.org/wiki/Nonce

key 是申请到的公钥

signature是签名,是将amount price type nonce key等参数通过'&'字符连接起来通过md5(私钥)为key进行sha256算法加密得到的值.

 


 
 
  
首先聚币的行情是使用网络爬虫获取的,而说明中给出了一系列的参数,你需要做的就是把这些参数填充上去。
 
如果你只是想要获取行情,那么事情容易很多。
    def real_time_ticker(coin):
url = 'https://www.jubi.com/api/v1/ticker/'
try:
data = requests.post(url, data={'coin': coin}).json()

except Exception ,e:
print e
return data

上面代码展示的时候获取实时的行情。委一和买一的价格,数量,和当前成交的数量,价格。
 按照上面的格式,把参数coin填上去,比如要获取泽塔币, real_time_ticker('zet') 就会返回获取的数据。
{u'sell': u'0.179000', u'volume': 21828245.102822, u'buy': u'0.175010', u'last': u'0.179000', u'vol': 108290769.9171, u'high': u'0.289000', u'low': u'0.119141'}

 
 
所有的private API都需要经过认证, 就是说如果你要进行交易,委托,下单,你就需要使用私钥和公钥,并进行一系列的加密。


每次请求private api 都需要验证签名,发送的参数示例:

$param = array(

amount => 1,

price => 10000,

type => 'buy',

nonce => 141377098123

key => 5zi7w-4mnes-swmc4-egg9b-f2iqw-396z4-g541b

signature => 459c69d25c496765191582d9611028b9974830e9dfafd762854669809290ed82

);

nonce 可以理解为一个递增的整数:http://zh.wikipedia.org/wiki/Nonce

key 是申请到的公钥

signature是签名,是将amount price type nonce key等参数通过'&'字符连接起来通过md5(私钥)为key进行sha256算法加密得到的值.


 
 
比如下单:


Trade_add(下单)
Path:/api/v1/trade_add/
Request类型:POST
 
参数
key - API key
signature - signature
nonce - nonce
amount - 购买数量
price - 购买价格
type - 买单或者卖单
coin - 币种简称,例如btc、ltc、xas
id - 挂单ID
result - true(成功), false(失败)
{"result":true, "id":"11"}
 
返回JSON dictionary
id - 挂单ID
result - true(成功), false(失败)
 
返回结果示例:
{"result":true, "id":"11"}
 



首先解决nonce。
 
在维基百科中
在安全工程中,Nonce是一个在加密通信只能使用一次的数字。在认证协议中,它往往是一个随机或伪随机数,以避免重放攻击。Nonce也用于流密码以确保安全。如果需要使用相同的密钥加密一个以上的消息,就需要Nonce来确保不同的消息与该密钥加密的密钥流不同。
 
结合stackoverflow, nonce只是一个12位的随机数。
可以用以下方法获得这个随机数
    def get_nonce(self):
lens=12
return ''.join([str(random.randint(0, 9)) for i in range(lens)])

 聚币中的nonce的位数是12位,所以lens定义为12
 
或者可以直接用时间函数生成:
    def get_nonce_time(self):
lens = 12
curr_stamp = time.time()*100
nonece=int(curr_stamp)
return nonece

 
然后是signature。
signature是签名,是将amount price type nonce key等参数通过'&'字符连接起来通过md5(私钥)为key进行sha256算法加密得到的值.

先把私钥进行md5处理
    def getHash(self,s):
m=hashlib.md5()
m.update(s)
return m.hexdigest()

只要把私钥传入函数getHash就可以得到一个md5处理过的字符串。
 
私钥是聚币网给每个用户分配的字符串,是唯一的,这里假设为private_key=123456789吧,具体是多少,在你的聚币网设置里面可以找到。
sha_256key=self.getHash(private_key)
 
按照要求吧 你要post的数据字符串连起来
nonce=self.get_nonce_time
type='buy'
amount='10000'
key='xxxxxxxxxxx‘ #这个是聚币网给你的公钥,同样在设置里头可以找到
price='10' #你要设置的价格为10
coin='zet'
message = "amount=“+amount+”&nonce="+str(nonce)+"&type="+type+"&key="+key+'&price="+price+"&coin"+coin

signature = hmac.new(sha_256key, message, digestmod=hashlib.sha256).digest()

这样获得signature之后,就可以通过签名来进行post操作。

data_wrap={'nonce':nonce,'key':key_value,'signature':signature}

js=requests.post(url,data=data_wrap).json()

 
如果直接按照上面的代码去获取账户相关信息或者去挂单的话,会返回104的签名错误。 经过不断的排查,发现是signature的字符格式的问题。
 
构造一个str转换格式的函数:
    def toHex(self,str):
lst =
for ch in str:
hv = hex(ord(ch)).replace('0x', '')
if len(hv) == 1:
hv = '0' + hv
lst.append(hv)
return reduce(lambda x, y: x + y, lst)
这个函数的作用就是把原来十六进制格式的字符完全转化成十六进制,把前面的0x去掉,不足2位的补全为2位。
把经过处理的signature进行格式转换后,几次提交,终于发现可以获取到用户的账户信息,进行下单,撤单,等操作。
 
 
 
下面是一个获取账户信息的代码段:
    def getAccount(self):
url='https://www.jubi.com/api/v1/balance/'

nonce_value=self.get_nonce_time()
print nonce_value
key_value=self.public_key
private_key=self.private_key

s='nonce='+str(nonce_value)+'&'+'key='+key_value

print s

#signature是签名,是将amount price type nonce key等参数通过'&'字符连接起来通过md5(私钥)为key进行sha256算法加密得到的值.
md5=self.getHash(private_key)
print md5
print type(md5)

msg=bytes(s).encode('utf-8')
key=bytes(md5).encode('utf-8')
signature =hmac.new(key,msg,digestmod=hashlib.sha256).digest()
print signature
print type(signature)
sig=self.toHex(signature)

print sig
data_wrap={'nonce':nonce_value,'key':key_value,'signature':sig}

print data_wrap

data_en=urllib.urlencode(data_wrap)
req=urllib2.Request(url,data=data_en)
resp=urllib2.urlopen(req).read()
print resp


def toHex(self,str):
lst =
for ch in str:
hv = hex(ord(ch)).replace('0x', '')
if len(hv) == 1:
hv = '0' + hv
lst.append(hv)
return reduce(lambda x, y: x + y, lst)

 
以上的代码运行后返回一下账户信息:
{"uid":123456,"nameauth":1,"moflag":1,"asset":,"btc_balance":0,"btc_lock":0,"drk_balance":0,"drk_lock":0,"blk_balance":0,"blk_lock":0,"vrc_balance":0,"vrc_lock":0,"tfc_balance":0,"tfc_lock":0,"jbc_balance":0,"jbc_lock":0,"ltc_balance":0,"ltc_lock":0,"doge_balance":0,"doge_lock":0,"xpm_balance":0,"xpm_lock":0,"ppc_balance":0,"ppc_lock":0,"wdc_balance":0,"wdc_lock":0,"vtc_balance":0,"vtc_lock":0,"max_balance":0,"max_lock":0,"ifc_balance":0,"ifc_lock":0,"zcc_balance":0,"zcc_lock":0,"zet_balance":0,"zet_lock":0,"eac_balance":0,"eac_lock":0,"fz_balance":0,"fz_lock":0,"skt_balance":0,"skt_lock":0,"plc_balance":0,"plc_lock":0,"mtc_balance":0,"mtc_lock":0,"qec_balance":0,"qec_lock":0,"lkc_balance":10,"lkc_lock":0,"met_balance":0,"met_lock":0,"ytc_balance":0,"ytc_lock":0,"hlb_balance":0,"hlb_lock":0,"game_balance":0,"game_lock":0,"rss_balance":0,"rss_lock":0,"rio_balance":0,"rio_lock":0,"ktc_balance":0,"ktc_lock":0,"pgc_balance":0,"pgc_lock":0,"mryc_balance":0,"mryc_lock":0,"eth_balance":0,"eth_lock":0,"etc_balance":0,"etc_lock":0,"dnc_balance":0,"dnc_lock":0,"gooc_balance":0,"gooc_lock":0,"xrp_balance":0,"xrp_lock":0,"nxt_balance":0,"nxt_lock":0,"lsk_balance":0,"lsk_lock":0,"xas_balance":0,"xas_lock":0,"peb_balance":0,"peb_lock":0,"nhgh_balance":0,"nhgh_lock":0,"xsgs_balance":0,"xsgs_lock":0,"ans_balance":0,"ans_lock":0,"bts_balance":0,"bts_lock":0,"cny_balance":0,"cny_lock":0}











 
聚币网个人邀请码:
514330
 
还没注册可以拿去用,对于我而言可以拿到你们交易费用的50%,不过一般交易费除非是超级大户,一般散户都很少。千分之一的交易手续费。
 
欢迎一起讨论:
Email:weigesysu@qq.com

 原创内容,转载请注明出处
http://30daydo.com/article/181 
 

56 个评论

签名不匹配啊??是将amount price type nonce key等参数通过'&'字符连接起来通过md5(私钥)为key进行sha256算法加密得到的值。这句话的逻辑没看懂啊。请教请教一下,谢谢
我也在研究,可能格式不对。 兄弟可以一起研究下吗
我也是搞这个搞了两三天了,一直都是104错误,签名不正确。真不知道该怎么搞的,连balance都通不过。求共享Demo!!!
“将amount price type nonce key等参数通过'&'字符连接起来通过md5(私钥)为key进行sha256算法加密得到的值.”一直没搞懂这句话
目前还在研究
官方的api文档写的很烂。
将私钥用MD5加密后再用hmac_sha256加密
hmac_sha256(拼接的字符,私钥MD5)
请问这个函数出自哪里? 我谷歌了下,没有这个函数
python我不清楚,我说的是JS的,但是两者是相通的。(SHA-256-HMAC加密算法)
还有一个要注意的是,私钥的MD5用小写
偶尔能连通balance,大都返回{"result":false,"code":"106"},这怎么用啊?
106 请求过期(nonce错误)
试试用时间戳做nonce
用时间戳做nonce,依然是{"result":false,"code":"106"},郁闷~~~
谢谢!几经周折,终于搞定:)
请教下, 为什么 balance可以成功(偶尔104错误), 但trade_list\trade_add大部分时间都会报104错误?
是message参数需要按特定顺序排列还是什么问题? 谢谢!
好的。 请问最终是什么原因呢?
下单一直是104错误,签名不正确。
我nonce改成时间戳,重新申请了API,nonce不能用随机数
请教一下,trade_list\trade_add什么情况下调试成功过,我一直是104,一次也没成功过
有一次离开电脑一段时间, 回来一试trade_list就通了, 但后续又一直失败, 前后没有改动代码, 不明白是怎么的
真神奇。。。。。。
太神奇了,这种好事,我一次也没有遇到过:(
嗯, 神奇得有点抓狂, 那次获取了list, 还根据获取到的id调用trade_cancel成功, 但也就那一次
想来 balance也用了签名, 都没问题, 怎么trade_list的签名就有问题, 两个签名不是就只有用&拼message的时候有点差别? 不解...
@李魔佛 @fenge21 ,谢谢二位!
有人用C# 写的吗?交流一下QQ 114725909~~
你可以把你的想法写出来,发表个文章,这样更多人能够看到你的信息,能更好的交流。纯属建议哈
那个获取签名的方法用hexdigest就可以,不需要调用toHex的方法
signature = hmac.new(key, msg, digestmod=hashlib.sha256).hexdigest()
对,这个我也试过。 编码问题,两种方法都可以。
windows下可以成功,但linux下只有trade_cancel通过,其余都会报104错误,好奇怪~~~
签名已调通,谢谢李魔佛博主。
我就是C#写的
bool CBalance::Update()
{
CString _strResult;
try
{
_AutoClear _autoClear(this);
ASSERT(m_pSession);
ASSERT(m_pConnection == NULL);
m_pConnection = m_pSession->GetHttpConnection(_T("www.jubi.com"));
if (!m_pConnection)
return false;

ASSERT(m_pFile == NULL);
CString _strObjectName = _T("/api/v1/balance/");
m_pFile = m_pConnection->OpenRequest(CHttpConnection::HTTP_VERB_POST, _strObjectName);
if (!m_pFile)
return false;

CString _strHeaders = _T("Content-Type:application/x-www-form-urlencoded");
CString _strOptional;
_strOptional.Format(_T("key=%s&nonce=%s"), GetPublicKey(), GetNonce());
_strOptional.AppendFormat(_T("&signature=%s"), GetSignature(_strOptional));
m_pFile->SendRequest(_strHeaders, (LPVOID)(LPCTSTR)_strOptional, _strOptional.GetLength());
if (!m_pFile->ReadString(_strResult))
return false;
}
catch (CInternetException* e)
{
DWORD _dwError = e->m_dwError;
return false;
}
......
签名部分是这样:
CString CApi_V1::GetSignature(const CString& strText_)
{
String^ _strSKeyMd5 = gcnew String(GetSecretKeyMd5());

UTF8Encoding^ _encoding = gcnew UTF8Encoding();
array<unsigned char>^ _bytesSKeyMd5 = _encoding->GetBytes(_strSKeyMd5);
array<unsigned char>^ _bytesText = _encoding->GetBytes(gcnew String(strText_));
HMACSHA256^ _hmacsha256 = gcnew HMACSHA256(_bytesSKeyMd5);
array<unsigned char>^ _bytesSign = _hmacsha256->ComputeHash(_bytesText);

String^ _strSign = BitConverter::ToString(_bytesSign)->Replace("-", "")->ToLower();
return (CString)_strSign;
}
不好意思比较懒,签名调通了一直没上来答谢博主。
习惯了没问题就过有问题才找解决 ^.^
很无耻地说,今天还是带着问题上来的。。。
现在人民币交易的调通了,普银交易区的不知道怎么访问,看帮助里没说针对普银交易区的API,但也没说API不支持普银交易区。请问有没有猜成功的。
普银区的我没有试过,不过我觉得原理应该是一样的。 签名目前大部分人都只是能够获取balance,对于交易还是出现各种错误。
看了这文章和文章里面评论的所有注意事项,还是104,最后绝望之际把签名串里面的参数顺序换了下,nonce在前,key在后,通过了。。。 有顺序的,还不是字母顺序。。。
还真是。。。。我把获取账号的那部分的nonce和key交换了下,本来成功的,就变成104
请问tradelist的签名串参数顺序是怎样的。。。。。试得我要疯掉了。。
刚学没一个星期的python,如果是低级错误,请告知,谢谢。signature =hmac.new(key,msg,digestmod=hashlib.sha256).digest()计算出来的格式以‘\x20’表示,执行hex(ord(ch))这条语句时会出错。哪位大佬能把成功运行后的signature的格式贴出来,谢谢啦
在历史数据存储、选币策略方面,大家有什么好的思路?
存储用mysql或者csv,选币只能靠平时的经验。
如果要达到数据快速清洗、存储、实时决策交易的要求,还有好多坑啊
请问一下,我用python3.54
按楼主的demo代码写,出现两处错误
第一
key_value='Y***K-d***/-O***3-N***M-X***e-{***}-j***e'
def getHash(s):
m=hashlib.md5()
m.update(s)
return m.hexdigest()

md5=getHash(key_value)
print(md5)
#TypeError: Unicode-objects must be encoded before hashing
这个要是什么问题,
查了百度说要改成这样m.update(s.encode('utf8'))运行,这样改MD5会不会变?要怎么改才正确?
第二
key_value='Y***K-d***/-O***3-N***M-X***e-{***}-j***e'
def getHash(s):
m=hashlib.md5()
m.update(s.encode('utf8'))
return m.hexdigest()

def toHex(str):
lst = ""
for ch in str:
hv = hex(ord(ch)).replace('0x', '')
if len(hv) == 1:
hv = '0' + hv
lst.append(hv)
return reduce(lambda x, y: x + y, lst)

def get_nonce_time():
lens = 12
curr_stamp = time.time() * 100
nonece = int(curr_stamp)
return nonece

md5=getHash(key_value)
print(md5)

#TypeError: Unicode-objects must be encoded before hashing

nonce = get_nonce_time()
public_key = 'n***8-u***j-w***h-v***m-3***e-r***z-q***7'
post_data='key='+public_key+'&'+'nonce='+str(nonce)
print(post_data)
key=bytes((md5).encode('utf-8'))
msg=bytes((post_data).encode('utf-8'))
signature =hmac.new(key,msg,digestmod=hashlib.sha256).digest()
print(signature)
sig=toHex(signature))
#Traceback (most recent call last):
# File "C:/Users/Administrator/Desktop/juiapi.py", line 45, in <module>
# sig=toHex(signature)
# File "C:/Users/Administrator/Desktop/juiapi.py", line 21, in toHex
# hv = hex(ord(ch)).replace('0x', '')
#TypeError: ord() expected string of length 1, but int found
请问一下楼主要的Python是那个版本。我出现这问题在Python3.54要怎么写才能通过?
我的是2.7, 编码会比较坑。要专门处理一些编码问题, 3.5的会好一些的。
问题解决签名通过,来谢谢群主,顺便问下,聚币没提供历史数据,这个怎么解决,按理说,浏览器有历史数据,就应该有方法下载下来才对啊
历史数据只能通过api 自己保存到本地
感谢楼主大大先行的填坑~用python3实现了一下。
值得注意的是最终POST请求时,必须注意参数的排序。

只有以下两种排序是正确的,其余的都返回104错误:
signature,nonce,key
nonce,singature,key
总结:nonce参数一定要在key前头

https://github.com/se4/jubi-tiny-api
你只需要提交的时候按照字典默认顺序就可以了。具体顺序你循坏一下你的字典就可以
请问楼主,我调用trade_add为什么一直报错<Response [200]>,我参数的顺序是signaturn,nonce, key, amount , price, type, coin.可是一直报错,,,,
贴上返回的json格式,无论顺序对错都是返回respoonse200的。
解决了!谢谢。可是我调用trade_add时候按照signaturn,nonce, key, amount , price, type, coin.的顺序还是104,为什么呢?
104怎么破,nonce在前面key在后面也一样,怎么换都不对,求解
我把代码贴上来了,你们参考下。
我把代码贴上来了,你们参考下。
signaturn拼错了,你这个会一直报100吧
您好,我也是用C#写的,一直没调通需要签名的接口,自己感觉是nonce参数不对,可以把你的GetNonce函数代码贴上来给我参考一下吗?

要回复文章请先登录注册