You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1408 lines
59 KiB
1408 lines
59 KiB
9 years ago
|
/******************************************************************************
|
||
|
* Copyright © 2014-2016 The SuperNET Developers. *
|
||
|
* *
|
||
|
* See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at *
|
||
|
* the top-level directory of this distribution for the individual copyright *
|
||
|
* holder information and the developer policies on copyright and licensing. *
|
||
|
* *
|
||
|
* Unless otherwise agreed in a custom licensing agreement, no part of the *
|
||
|
* SuperNET software, including this file may be copied, modified, propagated *
|
||
|
* or distributed except according to the terms contained in the LICENSE file *
|
||
|
* *
|
||
|
* Removal or modification of this copyright notice is prohibited. *
|
||
|
* *
|
||
|
******************************************************************************/
|
||
|
|
||
|
|
||
|
#ifndef xcode_exchanges_h
|
||
|
#define xcode_exchanges_h
|
||
|
|
||
|
#define SHA512_DIGEST_SIZE (512 / 8)
|
||
|
void *curl_post(void **cHandlep,char *url,char *userpass,char *postfields,char *hdr0,char *hdr1,char *hdr2,char *hdr3);
|
||
|
|
||
|
char *exchange_would_submit(char *postreq,char *hdr1,char *hdr2,char *hdr3, char *hdr4)
|
||
|
{
|
||
|
char *data; cJSON *json;
|
||
|
json = cJSON_CreateObject();
|
||
|
jaddstr(json,"post",postreq);
|
||
|
if ( hdr1[0] != 0 )
|
||
|
jaddstr(json,"hdr1",hdr1);
|
||
|
if ( hdr2[0] != 0 )
|
||
|
jaddstr(json,"hdr2",hdr2);
|
||
|
if ( hdr3[0] != 0 )
|
||
|
jaddstr(json,"hdr3",hdr3);
|
||
|
if ( hdr4[0] != 0 )
|
||
|
jaddstr(json,"hdr4",hdr4);
|
||
|
data = jprint(json,1);
|
||
|
json = 0;
|
||
|
return(data);
|
||
|
}
|
||
|
|
||
|
uint64_t exchange_nonce(struct exchange_info *exchange)
|
||
|
{
|
||
|
uint64_t nonce;
|
||
|
nonce = time(NULL);
|
||
|
if ( nonce < exchange->lastnonce )
|
||
|
nonce = exchange->lastnonce + 1;
|
||
|
exchange->lastnonce = nonce;
|
||
|
return(nonce);
|
||
|
}
|
||
|
|
||
|
int32_t flip_for_exchange(char *pairstr,char *fmt,char *refstr,int32_t dir,double *pricep,double *volumep,char *base,char *rel)
|
||
|
{
|
||
|
if ( strcmp(rel,refstr) == 0 )
|
||
|
sprintf(pairstr,fmt,rel,base);
|
||
|
else
|
||
|
{
|
||
|
if ( strcmp(base,refstr) == 0 )
|
||
|
{
|
||
|
sprintf(pairstr,fmt,base,rel);
|
||
|
dir = -dir;
|
||
|
*volumep *= *pricep;
|
||
|
*pricep = (1. / *pricep);
|
||
|
}
|
||
|
else sprintf(pairstr,fmt,rel,base);
|
||
|
}
|
||
|
return(dir);
|
||
|
}
|
||
|
|
||
|
int32_t flipstr_for_exchange(struct exchange_info *exchange,char *pairstr,char *fmt,int32_t dir,double *pricep,double *volumep,char *_base,char *_rel)
|
||
|
{
|
||
|
int32_t polarity; char base[64],rel[64];
|
||
|
strcpy(base,_base), strcpy(rel,_rel);
|
||
|
tolowercase(base), tolowercase(rel);
|
||
|
polarity = (*exchange->issue.supports)(base,rel);
|
||
|
if ( dir > 0 )
|
||
|
sprintf(pairstr,fmt,base,rel);
|
||
|
else if ( dir < 0 )
|
||
|
{
|
||
|
*volumep *= *pricep;
|
||
|
*pricep = (1. / *pricep);
|
||
|
sprintf(pairstr,fmt,rel,base);
|
||
|
}
|
||
|
return(dir);
|
||
|
}
|
||
|
|
||
|
int32_t cny_flip(char *market,char *coinname,char *base,char *rel,int32_t dir,double *pricep,double *volumep)
|
||
|
{
|
||
|
char pairstr[512],lbase[16],lrel[16],*refstr=0;
|
||
|
strcpy(lbase,base), tolowercase(lbase), strcpy(lrel,rel), tolowercase(lrel);
|
||
|
if ( strcmp(lbase,"cny") == 0 || strcmp(lrel,"cny") == 0 )
|
||
|
{
|
||
|
dir = flip_for_exchange(pairstr,"%s_%s","cny",dir,pricep,volumep,lbase,lrel);
|
||
|
refstr = "cny";
|
||
|
}
|
||
|
else if ( strcmp(lbase,"btc") == 0 || strcmp(lrel,"btc") == 0 )
|
||
|
{
|
||
|
dir = flip_for_exchange(pairstr,"%s_%s","btc",dir,pricep,volumep,lbase,lrel);
|
||
|
refstr = "btc";
|
||
|
}
|
||
|
if ( market != 0 && coinname != 0 && refstr != 0 )
|
||
|
{
|
||
|
strcpy(market,refstr);
|
||
|
if ( strcmp(lbase,"refstr") != 0 )
|
||
|
strcpy(coinname,lbase);
|
||
|
else strcpy(coinname,lrel);
|
||
|
touppercase(coinname);
|
||
|
}
|
||
|
return(dir);
|
||
|
}
|
||
|
|
||
|
char *exchange_extractorderid(int32_t historyflag,char *status,uint64_t quoteid,char *quoteid_field)
|
||
|
{
|
||
|
cJSON *array,*item,*json; int32_t i,n; uint64_t txid;
|
||
|
if ( status != 0 )
|
||
|
{
|
||
|
if ( (array= cJSON_Parse(status)) != 0 && is_cJSON_Array(array) != 0 && (n= cJSON_GetArraySize(array)) > 0 )
|
||
|
{
|
||
|
for (i=0; i<n; i++)
|
||
|
{
|
||
|
item = jitem(array,i);
|
||
|
if ( (txid= juint(item,quoteid_field)) == quoteid )
|
||
|
{
|
||
|
json = cJSON_CreateObject();
|
||
|
jaddstr(json,"result",historyflag == 0 ? "order still pending" : "order completed");
|
||
|
jadd(json,"order",cJSON_Duplicate(item,1));
|
||
|
free_json(array);
|
||
|
return(jprint(json,1));
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if ( array != 0 )
|
||
|
free_json(array);
|
||
|
}
|
||
|
return(0);
|
||
|
}
|
||
|
|
||
|
#ifdef notnow
|
||
|
uint64_t bittrex_trade(char **retstrp,struct exchange_info *exchange,char *base,char *rel,int32_t dir,double price,double volume)
|
||
|
{
|
||
|
static CURL *cHandle;
|
||
|
char *sig,*data,urlbuf[2048],hdr[1024],pairstr[512],dest[SHA512_DIGEST_SIZE*2 + 1]; struct destbuf uuidstr;
|
||
|
uint8_t databuf[512];
|
||
|
uint64_t nonce,txid = 0;
|
||
|
cJSON *json,*resultobj;
|
||
|
int32_t i,j,n;
|
||
|
nonce = exchange_nonce(exchange);
|
||
|
|
||
|
// https://bittrex.com/api/v1.1/market/selllimit?apikey=API_KEY&market=BTC-LTC&quantity=1.2&rate=1.3
|
||
|
if ( dir == 0 )
|
||
|
sprintf(urlbuf,"https://bittrex.com/api/v1.1/account/getbalances?apikey=%s&nonce=%llu",exchange->apikey,(long long)nonce);
|
||
|
else
|
||
|
{
|
||
|
dir = flip_for_exchange(pairstr,"%s-%s","BTC",dir,&price,&volume,base,rel);
|
||
|
sprintf(urlbuf,"https://bittrex.com/api/v1.1/market/%slimit?apikey=%s&nonce=%llu&market=%s&rate=%.8f&quantity=%.8f",dir>0?"buy":"sell",exchange->apikey,(long long)nonce,pairstr,price,volume);
|
||
|
}
|
||
|
if ( (sig = hmac_sha512_str(dest,exchange->apisecret,(int32_t)strlen(exchange->apisecret),urlbuf)) != 0 )
|
||
|
sprintf(hdr,"apisign:%s",sig);
|
||
|
else hdr[0] = 0;
|
||
|
//printf("cmdbuf.(%s) h1.(%s)\n",urlbuf,hdr);
|
||
|
if ( (data= curl_post(&cHandle,urlbuf,0,0,hdr,0,0,0)) != 0 )
|
||
|
{
|
||
|
//printf("cmd.(%s) [%s]\n",urlbuf,data);
|
||
|
if ( (json= cJSON_Parse(data)) != 0 )
|
||
|
{
|
||
|
// { "success" : true, "message" : "", "result" : { "uuid" : "e606d53c-8d70-11e3-94b5-425861b86ab6" } }
|
||
|
if ( dir == 0 )
|
||
|
{
|
||
|
//printf("got balances.(%s)\n",data);
|
||
|
}
|
||
|
else if ( is_cJSON_True(cJSON_GetObjectItem(json,"success")) != 0 && (resultobj= cJSON_GetObjectItem(json,"result")) != 0 )
|
||
|
{
|
||
|
copy_cJSON(&uuidstr,cJSON_GetObjectItem(resultobj,"uuid"));
|
||
|
for (i=j=0; uuidstr.buf[i]!=0; i++)
|
||
|
if ( uuidstr.buf[i] != '-' )
|
||
|
uuidstr.buf[j++] = uuidstr.buf[i];
|
||
|
uuidstr.buf[j] = 0;
|
||
|
n = (int32_t)strlen(uuidstr.buf);
|
||
|
printf("-> uuidstr.(%s).%d\n",uuidstr.buf,n);
|
||
|
decode_hex(databuf,n/2,uuidstr.buf);
|
||
|
if ( n >= 16 )
|
||
|
for (i=0; i<8; i++)
|
||
|
databuf[i] ^= databuf[8 + i];
|
||
|
memcpy(&txid,databuf,8);
|
||
|
printf("-> %llx\n",(long long)txid);
|
||
|
}
|
||
|
free_json(json);
|
||
|
}
|
||
|
}
|
||
|
if ( retstrp != 0 )
|
||
|
*retstrp = data;
|
||
|
else if ( data != 0 )
|
||
|
free(data);
|
||
|
return(txid);
|
||
|
}
|
||
|
|
||
|
uint64_t poloniex_trade(char **retstrp,struct exchange_info *exchange,char *base,char *rel,int32_t dir,double price,double volume)
|
||
|
{
|
||
|
static CURL *cHandle;
|
||
|
char *sig,*data,*extra,*typestr,cmdbuf[8192],hdr1[4096],hdr2[4096],pairstr[512],dest[SHA512_DIGEST_SIZE*2 + 1]; cJSON *json; uint64_t nonce,txid = 0;
|
||
|
nonce = exchange_nonce(exchange);
|
||
|
if ( (extra= *retstrp) != 0 )
|
||
|
*retstrp = 0;
|
||
|
if ( dir == 0 )
|
||
|
sprintf(cmdbuf,"command=returnCompleteBalances&nonce=%llu",(long long)nonce);
|
||
|
else
|
||
|
{
|
||
|
dir = flip_for_exchange(pairstr,"%s_%s","BTC",dir,&price,&volume,base,rel);
|
||
|
if ( extra != 0 && strcmp(extra,"margin") == 0 )
|
||
|
typestr = (dir > 0) ? "marginBuy":"marginSell";
|
||
|
else typestr = (dir > 0) ? "buy":"sell";
|
||
|
sprintf(cmdbuf,"command=%s&nonce=%ld¤cyPair=%s&rate=%.8f&amount=%.8f",typestr,(long)time(NULL),pairstr,price,volume);
|
||
|
}
|
||
|
if ( (sig= hmac_sha512_str(dest,exchange->apisecret,(int32_t)strlen(exchange->apisecret),cmdbuf)) != 0 )
|
||
|
sprintf(hdr2,"Sign:%s",sig);
|
||
|
else hdr2[0] = 0;
|
||
|
sprintf(hdr1,"Key:%s",exchange->apikey);
|
||
|
//printf("cmdbuf.(%s) h1.(%s) h2.(%s)\n",cmdbuf,hdr2,hdr1);
|
||
|
if ( (data= curl_post(&cHandle,"https://poloniex.com/tradingApi",0,cmdbuf,hdr2,hdr1,0,0)) != 0 )
|
||
|
{
|
||
|
//printf("cmd.(%s) [%s]\n",cmdbuf,data);
|
||
|
if ( (json= cJSON_Parse(data)) != 0 )
|
||
|
{
|
||
|
txid = (get_API_nxt64bits(cJSON_GetObjectItem(json,"orderNumber")) << 32) | get_API_nxt64bits(cJSON_GetObjectItem(json,"tradeID"));
|
||
|
free_json(json);
|
||
|
}
|
||
|
}
|
||
|
if ( retstrp != 0 )
|
||
|
*retstrp = data;
|
||
|
else if ( data != 0 )
|
||
|
free(data);
|
||
|
return(txid);
|
||
|
}
|
||
|
|
||
|
/*uint64_t bter_trade(char **retstrp,struct exchange_info *exchange,char *base,char *rel,int32_t dir,double price,double volume)
|
||
|
{
|
||
|
static CURL *cHandle;
|
||
|
char *sig,*data,buf[512],cmdbuf[8192],hdr1[1024],hdr2[1024],pairstr[512],dest[SHA512_DIGEST_SIZE*2 + 1];
|
||
|
cJSON *json; uint64_t txid = 0;
|
||
|
dir = cny_flip(0,0,base,rel,dir,&price,&volume);
|
||
|
sprintf(cmdbuf,"type=%s&nonce=%ld&pair=%s&rate=%.8f&amount=%.8f",dir>0?"BUY":"SELL",(long)time(NULL),pairstr,price,volume);
|
||
|
if ( (sig = hmac_sha512_str(dest,exchange->apisecret,(int32_t)strlen(exchange->apisecret),cmdbuf)) != 0 )
|
||
|
sprintf(hdr2,"SIGN:%s",sig);
|
||
|
else hdr2[0] = 0;
|
||
|
sprintf(hdr1,"KEY:%s",exchange->apikey);
|
||
|
printf("cmdbuf.(%s) h1.(%s) h2.(%s)\n",cmdbuf,hdr2,hdr1);
|
||
|
if ( (data= curl_post(&cHandle,"https://bter.com/api/1/private/placeorder",0,cmdbuf,hdr2,hdr1,0)) != 0 )
|
||
|
{
|
||
|
printf("cmd.(%s) [%s]\n",cmdbuf,data);
|
||
|
//{ "result":"true", "order_id":"123456", "msg":"Success" }
|
||
|
if ( (json= cJSON_Parse(data)) != 0 )
|
||
|
{
|
||
|
copy_cJSON(buf,cJSON_GetObjectItem(json,"result"));
|
||
|
if ( strcmp(buf,"true") != 0 )
|
||
|
{
|
||
|
copy_cJSON(buf,cJSON_GetObjectItem(json,"msg"));
|
||
|
if ( strcmp(buf,"Success") != 0 )
|
||
|
txid = get_API_nxt64bits(cJSON_GetObjectItem(json,"order_id"));
|
||
|
}
|
||
|
free_json(json);
|
||
|
}
|
||
|
}
|
||
|
if ( retstrp != 0 )
|
||
|
*retstrp = data;
|
||
|
else if ( data != 0 )
|
||
|
free(data);
|
||
|
return(txid);
|
||
|
}*/
|
||
|
|
||
|
uint64_t btce_trade(char **retstrp,struct exchange_info *exchange,char *_base,char *_rel,int32_t dir,double price,double volume)
|
||
|
{
|
||
|
/*Authentication is made by sending the following HTTP headers:
|
||
|
Key — API key. API key examples: 46G9R9D6-WJ77XOIP-XH9HH5VQ-A3XN3YOZ-8T1R8I8T
|
||
|
API keys are created in the Profile in the API keys section.
|
||
|
Sign — Signature. POST-parameters (?nonce=1¶m0=val0), signed with a Secret key using HMAC-SHA512*/
|
||
|
static CURL *cHandle;
|
||
|
|
||
|
char *sig,*data,base[64],rel[64],payload[8192],hdr1[4096],hdr2[4096],pairstr[512],dest[SHA512_DIGEST_SIZE*2 + 1]; cJSON *json,*resultobj; uint64_t nonce,txid = 0;
|
||
|
sprintf(hdr1,"Key:%s",exchange->apikey);
|
||
|
nonce = exchange_nonce(exchange);
|
||
|
if ( dir == 0 )
|
||
|
sprintf(payload,"method=getInfo&nonce=%llu",(long long)nonce);
|
||
|
else
|
||
|
{
|
||
|
if ( (dir= flipstr_for_exchange(exchange,pairstr,"%s_%s",dir,&price,&volume,base,rel)) == 0 )
|
||
|
{
|
||
|
printf("cant find baserel (%s/%s)\n",base,rel);
|
||
|
return(0);
|
||
|
}
|
||
|
sprintf(payload,"method=Trade&nonce=%ld&pair=%s&type=%s&rate=%.3f&amount=%.6f",(long)time(NULL),pairstr,dir>0?"buy":"sell",price,volume);
|
||
|
}
|
||
|
if ( (sig= hmac_sha512_str(dest,exchange->apisecret,(int32_t)strlen(exchange->apisecret),payload)) != 0 )
|
||
|
sprintf(hdr2,"Sign:%s",sig);
|
||
|
else hdr2[0] = 0;
|
||
|
//printf("cmdbuf.(%s) h1.(%s) h2.(%s)\n",payload,hdr2,hdr1);
|
||
|
if ( (data= curl_post(&cHandle,"https://btc-e.com/tapi",0,payload,hdr2,hdr1,0,0)) != 0 )
|
||
|
{
|
||
|
//printf("cmd.(%s) [%s]\n",payload,data);
|
||
|
//{ "success":1, "return":{ "received":0.1, "remains":0, "order_id":0, "funds":{ "usd":325, "btc":2.498, } } }
|
||
|
if ( (json= cJSON_Parse(data)) != 0 )
|
||
|
{
|
||
|
if ( juint(json,"success") > 0 && (resultobj= cJSON_GetObjectItem(json,"return")) != 0 )
|
||
|
{
|
||
|
if ( (txid= get_API_nxt64bits(cJSON_GetObjectItem(resultobj,"order_id"))) == 0 )
|
||
|
{
|
||
|
if ( get_API_nxt64bits(cJSON_GetObjectItem(resultobj,"remains")) == 0 )
|
||
|
txid = _crc32(0,payload,strlen(payload));
|
||
|
}
|
||
|
}
|
||
|
free_json(json);
|
||
|
}
|
||
|
}
|
||
|
if ( retstrp != 0 )
|
||
|
*retstrp = data;
|
||
|
else if ( data != 0 )
|
||
|
free(data);
|
||
|
return(txid);
|
||
|
}
|
||
|
|
||
|
uint64_t kraken_trade(char **retstrp,struct exchange_info *exchange,char *_base,char *_rel,int32_t dir,double price,double volume)
|
||
|
{
|
||
|
//API-Key = API key
|
||
|
//API-Sign = Message signature using HMAC-SHA512 of (URI path + SHA256(nonce + POST data)) and base64 decoded secret API key
|
||
|
|
||
|
static CURL *cHandle;
|
||
|
char *sig,*data,url[512],base[64],rel[64],buf[8192],postbuf[1024],payload[8192],sha256[65],hdr1[4096],hdr2[4096],encode64[4096],decode64[4096],dest[SHA512_DIGEST_SIZE*2 + 1];
|
||
|
cJSON *json,*resultobj; uint8_t hash[32]; uint64_t nonce,txid = 0; int32_t n;
|
||
|
if ( _base != 0 && _rel != 0 )
|
||
|
{
|
||
|
strcpy(base,_base), strcpy(rel,_rel);
|
||
|
touppercase(base), touppercase(rel);
|
||
|
if ( strcmp(base,"BTC") == 0 )
|
||
|
strcpy(base,"XBT");
|
||
|
if ( strcmp(rel,"BTC") == 0 )
|
||
|
strcpy(rel,"XBT");
|
||
|
if ( strcmp(base,"DOGE") == 0 )
|
||
|
strcpy(base,"XDG");
|
||
|
if ( strcmp(rel,"DOGE") == 0 )
|
||
|
strcpy(rel,"XDG");
|
||
|
}
|
||
|
sprintf(hdr1,"API-Key:%s",exchange->apikey);
|
||
|
n = nn_base64_decode((void *)exchange->apisecret,strlen(exchange->apisecret),(void *)decode64,sizeof(decode64));
|
||
|
nonce = exchange_nonce(exchange);
|
||
|
if ( dir == 0 )
|
||
|
{
|
||
|
sprintf(postbuf,"nonce=%llu",(long long)nonce);
|
||
|
sprintf(url,"https://api.kraken.com/0/private/Balance");
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
/*
|
||
|
if ( (dir= flipstr_for_exchange(exchange,pairstr,"%s_%s",dir,&price,&volume,base,rel) == 0 )
|
||
|
{
|
||
|
printf("cant find baserel (%s/%s)\n",base,rel);
|
||
|
return(0);
|
||
|
}
|
||
|
//dir = flip_for_exchange(pairstr,"%s_%s","BTC",dir,&price,&volume,base,rel);
|
||
|
sprintf(payload,"method=Trade&nonce=%ld&pair=%s&type=%s&rate=%.6f&amount=%.6f",(long)time(NULL),pairstr,dir>0?"buy":"sell",price,volume);*/
|
||
|
}
|
||
|
sprintf(buf,"%s",postbuf);
|
||
|
calc_sha256(sha256,hash,(uint8_t *)buf,(int32_t)strlen(buf));
|
||
|
sprintf(payload,"%s%s",url,sha256);
|
||
|
//memset(payload,0,sizeof(payload));
|
||
|
//sprintf(payload,"%s",url);
|
||
|
//memcpy(payload+strlen(payload),hash,sizeof(hash));
|
||
|
if ( (sig= hmac_sha512_str(dest,decode64,n,payload)) != 0 )
|
||
|
{
|
||
|
n = nn_base64_encode((void *)sig,n,(void *)encode64,sizeof(encode64));
|
||
|
sprintf(hdr2,"API-Sign:%s",encode64);
|
||
|
}
|
||
|
else hdr2[0] = 0;
|
||
|
//printf("cmdbuf.(%s) h1.(%s) h2.(%s)\n",postbuf,hdr2,hdr1);
|
||
|
if ( (data= curl_post(&cHandle,url,0,postbuf,hdr1,hdr2,0,0)) != 0 )
|
||
|
{
|
||
|
//printf("cmd.(%s) [%s]\n",payload,data);
|
||
|
//{ "success":1, "return":{ "received":0.1, "remains":0, "order_id":0, "funds":{ "usd":325, "btc":2.498, } } }
|
||
|
if ( (json= cJSON_Parse(data)) != 0 )
|
||
|
{
|
||
|
if ( juint(json,"success") > 0 && (resultobj= cJSON_GetObjectItem(json,"return")) != 0 )
|
||
|
{
|
||
|
if ( (txid= get_API_nxt64bits(cJSON_GetObjectItem(resultobj,"order_id"))) == 0 )
|
||
|
{
|
||
|
if ( get_API_nxt64bits(cJSON_GetObjectItem(resultobj,"remains")) == 0 )
|
||
|
txid = _crc32(0,payload,strlen(payload));
|
||
|
}
|
||
|
}
|
||
|
free_json(json);
|
||
|
}
|
||
|
}
|
||
|
if ( retstrp != 0 )
|
||
|
*retstrp = data;
|
||
|
else if ( data != 0 )
|
||
|
free(data);
|
||
|
return(txid);
|
||
|
}
|
||
|
|
||
|
uint64_t bitfinex_trade(char **retstrp,struct exchange_info *exchange,char *_base,char *_rel,int32_t dir,double price,double volume)
|
||
|
{
|
||
|
/* POST https://api.bitfinex.com/v1/order/new
|
||
|
void *curl_post(CURL **cHandlep,char *url,char *userpass,char *postfields,char *hdr0,char *hdr1,char *hdr2)
|
||
|
With a payload of
|
||
|
|
||
|
{
|
||
|
"request": "/v1/order/new",
|
||
|
"nonce": "1234",
|
||
|
"option1": ...
|
||
|
}
|
||
|
The nonce provided must be strictly increasing.
|
||
|
|
||
|
To authenticate a request, use the following:
|
||
|
|
||
|
payload = parameters-dictionary -> JSON encode -> base64
|
||
|
signature = HMAC-SHA384(payload, api-secret) as hexadecimal
|
||
|
send (api-key, payload, signature)
|
||
|
These are encoded as HTTP headers named:
|
||
|
|
||
|
X-BFX-APIKEY
|
||
|
X-BFX-PAYLOAD
|
||
|
X-BFX-SIGNATURE
|
||
|
*/
|
||
|
/* POST /order/new
|
||
|
Request
|
||
|
Key Type Description
|
||
|
symbol [string] The name of the symbol (see `/symbols`).
|
||
|
amount [decimal] Order size: how much to buy or sell.
|
||
|
price [price] Price to buy or sell at. Must be positive. Use random number for market orders.
|
||
|
exchange [string] "bitfinex"
|
||
|
side [string] Either "buy" or "sell".
|
||
|
type [string] Either "market" / "limit" / "stop" / "trailing-stop" / "fill-or-kill" / "exchange market" / "exchange limit" / "exchange stop" / "exchange trailing-stop" / "exchange fill-or-kill". (type starting by "exchange " are exchange orders, others are margin trading orders)
|
||
|
is_hidden [bool] true if the order should be hidden. Default is false.*/
|
||
|
|
||
|
static CURL *cHandle;
|
||
|
char *sig,*data,hdr3[4096],url[512],*extra,*typestr,*method,req[4096],base[16],rel[16],payload[4096],hdr1[4096],hdr2[4096],pairstr[512],dest[1024 + 1];
|
||
|
cJSON *json; uint64_t nonce,txid = 0;
|
||
|
if ( (extra= *retstrp) != 0 )
|
||
|
*retstrp = 0;
|
||
|
memset(req,0,sizeof(req));
|
||
|
nonce = exchange_nonce(exchange);
|
||
|
if ( dir == 0 )
|
||
|
{
|
||
|
method = "balances";
|
||
|
sprintf(req,"{\"request\":\"/v1/%s\",\"nonce\":\"%llu\"}",method,(long long)nonce);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if ( (dir= flipstr_for_exchange(exchange,pairstr,"%s%s",dir,&price,&volume,base,rel)) == 0 )
|
||
|
{
|
||
|
printf("cant find baserel (%s/%s)\n",base,rel);
|
||
|
return(0);
|
||
|
}
|
||
|
method = "order/new";
|
||
|
//Either "market" / "limit" / "stop" / "trailing-stop" / "fill-or-kill" / "exchange market" / "exchange limit" / "exchange stop" / "exchange trailing-stop" / "exchange fill-or-kill". (type starting by "exchange " are exchange orders, others are margin trading orders)
|
||
|
if ( (typestr= extra) == 0 )
|
||
|
typestr = "exchange limit";
|
||
|
sprintf(req,"{\"request\":\"/v1/%s\",\"nonce\":\"%llu\",\"exchange\":\"bitfinex\",\"side\":\"%s\",\"type\":\"%s\",\"price\":\"%.8f\",\"amount\":\"%.8f\",\"symbol\":\"%s\"}",method,(long long)nonce,dir>0?"buy":"sell",typestr,price,volume,pairstr);
|
||
|
}
|
||
|
nn_base64_encode((void *)req,strlen(req),payload,sizeof(payload));
|
||
|
if ( (sig= hmac_sha384_str(dest,exchange->apisecret,(int32_t)strlen(exchange->apisecret),payload)) != 0 )
|
||
|
{
|
||
|
sprintf(hdr1,"X-BFX-APIKEY:%s",exchange->apikey);
|
||
|
sprintf(hdr2,"X-BFX-PAYLOAD:%s",payload);
|
||
|
sprintf(hdr3,"X-BFX-SIGNATURE:%s",sig);
|
||
|
sprintf(url,"https://api.bitfinex.com/v1/%s",method);
|
||
|
//printf("bitfinex req.(%s) -> (%s) [%s %s %s]\n",req,payload,hdr1,hdr2,hdr3);
|
||
|
if ( (data= curl_post(&cHandle,url,0,req,hdr1,hdr2,hdr3,0)) != 0 )
|
||
|
{
|
||
|
//printf("[%s]\n",data);
|
||
|
if ( (json= cJSON_Parse(data)) != 0 )
|
||
|
{
|
||
|
if ( (txid= j64bits(json,"order_id")) == 0 )
|
||
|
{
|
||
|
if ( dir != 0 )
|
||
|
printf("bitfinex: no txid error\n");
|
||
|
}
|
||
|
free_json(json);
|
||
|
}
|
||
|
}
|
||
|
if ( retstrp != 0 )
|
||
|
*retstrp = data;
|
||
|
else if ( data != 0 )
|
||
|
free(data);
|
||
|
}
|
||
|
return(txid);
|
||
|
}
|
||
|
|
||
|
uint64_t btc38_trade(char **retstrp,struct exchange_info *exchange,char *_base,char *_rel,int32_t dir,double price,double volume)
|
||
|
{
|
||
|
/* $ Stamp = $ date-> getTimestamp ();
|
||
|
type, 1 for the purchase of Entry, 2 entry order to sell, can not be empty / the type of the order
|
||
|
|
||
|
$ Mdt = "_ public here to write here write here to write user ID_ private _" $ stamp.;
|
||
|
$ Mdt = md5 ($ mdt);
|
||
|
|
||
|
$ Data = array ("key" => "here to write public", "time" => $ stamp, "md5" => $ mdt, "type" => 1, "mk_type" => "cny",
|
||
|
"Price" => "0.0001", "amount" => "100", "coinname" => "XRP");
|
||
|
// $ Data_string = json_encode ($ data);
|
||
|
$ Ch = curl_init ();
|
||
|
curl_setopt ($ ch, CURLOPT_URL, 'http://www.btc38.com/trade/t_api/submitOrder.php');
|
||
|
curl_setopt ($ ch, CURLOPT_POST, 1);
|
||
|
curl_setopt ($ ch, CURLOPT_POSTFIELDS, $ data);
|
||
|
curl_setopt ($ ch, CURLOPT_RETURNTRANSFER, 1);
|
||
|
curl_setopt ($ ch, CURLOPT_HEADER, 0); */
|
||
|
|
||
|
static CURL *cHandle;
|
||
|
char *data,*path,url[1024],cmdbuf[8192],buf[512],digest[33],market[16],base[64],rel[64],coinname[16],fmtstr[512],*pricefmt,*volfmt = "%.3f";
|
||
|
cJSON *json,*resultobj; uint64_t nonce,txid = 0;
|
||
|
if ( _base != 0 && _rel != 0 )
|
||
|
{
|
||
|
strcpy(base,_base), strcpy(rel,_rel);
|
||
|
touppercase(base), touppercase(rel);
|
||
|
if ( btc38_supports(base,rel) == 0 )
|
||
|
{
|
||
|
*retstrp = clonestr("{\"error\":\"invalid contract pair\"}");
|
||
|
return(0);
|
||
|
}
|
||
|
}
|
||
|
nonce = exchange_nonce(exchange);
|
||
|
sprintf(buf,"%s_%s_%s_%llu",exchange->apikey,exchange->userid,exchange->apisecret,(long long)nonce);
|
||
|
//printf("MD5.(%s)\n",buf);
|
||
|
calc_md5(digest,buf,(int32_t)strlen(buf));
|
||
|
*retstrp = 0;
|
||
|
if ( dir == 0 )
|
||
|
{
|
||
|
path = "getMyBalance.php";
|
||
|
sprintf(cmdbuf,"key=%s&time=%llu&md5=%s",exchange->apikey,(long long)nonce,digest);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if ( (dir= cny_flip(market,coinname,base,rel,dir,&price,&volume)) == 0 )
|
||
|
{
|
||
|
fprintf(stderr,"btc38_trade illegal base.(%s) or rel.(%s)\n",base,rel);
|
||
|
return(0);
|
||
|
}
|
||
|
if ( strcmp(market,"cny") == 0 )
|
||
|
pricefmt = "%.5f";
|
||
|
else pricefmt = "%.6f";
|
||
|
sprintf(fmtstr,"key=%%s&time=%%llu&md5=%%s&type=%%s&mk_type=%%s&coinname=%%s&price=%s&amount=%s",pricefmt,volfmt);
|
||
|
sprintf(cmdbuf,fmtstr,exchange->apikey,(long long)nonce,digest,dir>0?"1":"2",market,coinname,price,volume);
|
||
|
path = "submitOrder.php";
|
||
|
}
|
||
|
sprintf(url,"http://www.btc38.com/trade/t_api/%s",path);
|
||
|
if ( (data= curl_post(&cHandle,url,0,cmdbuf,0,0,0,0)) != 0 )
|
||
|
{
|
||
|
//printf("submit cmd.(%s) [%s]\n",cmdbuf,data);
|
||
|
if ( (json= cJSON_Parse(data)) != 0 )
|
||
|
{
|
||
|
if ( juint(json,"success") > 0 && (resultobj= cJSON_GetObjectItem(json,"return")) != 0 )
|
||
|
{
|
||
|
if ( (txid= get_API_nxt64bits(cJSON_GetObjectItem(resultobj,"order_id"))) == 0 )
|
||
|
{
|
||
|
if ( get_API_nxt64bits(cJSON_GetObjectItem(resultobj,"remains")) == 0 )
|
||
|
txid = _crc32(0,cmdbuf,strlen(cmdbuf));
|
||
|
}
|
||
|
}
|
||
|
free_json(json);
|
||
|
}
|
||
|
} else fprintf(stderr,"submit err cmd.(%s)\n",cmdbuf);
|
||
|
if ( retstrp != 0 && data != 0 )
|
||
|
{
|
||
|
if ( (json= cJSON_Parse(data)) == 0 )
|
||
|
{
|
||
|
json = cJSON_CreateObject();
|
||
|
jaddstr(json,"result",data);
|
||
|
data = jprint(json,1);
|
||
|
} else free_json(json);
|
||
|
//printf("btc38 returning.(%s) in %p\n",data,data);
|
||
|
*retstrp = data;
|
||
|
}
|
||
|
else if ( data != 0 )
|
||
|
free(data);
|
||
|
return(txid);
|
||
|
}
|
||
|
|
||
|
uint64_t huobi_trade(char **retstrp,struct exchange_info *exchange,char *_base,char *_rel,int32_t dir,double price,double volume)
|
||
|
{
|
||
|
static CURL *cHandle;
|
||
|
char *data,*extra,*method,pricestr[64],pairstr[64],base[64],rel[64],url[1024],cmdbuf[8192],buf[512],digest[33]; cJSON *json; uint64_t nonce,txid = 0; int32_t type;
|
||
|
nonce = exchange_nonce(exchange);
|
||
|
pricestr[0] = 0;
|
||
|
if ( (extra= *retstrp) != 0 )
|
||
|
*retstrp = 0;
|
||
|
if ( dir == 0 )
|
||
|
{
|
||
|
method = "get_account_info";
|
||
|
sprintf(buf,"access_key=%s&created=%llu&method=%s&secret_key=%s",exchange->apikey,(long long)nonce,method,exchange->apisecret);
|
||
|
calc_md5(digest,buf,(int32_t)strlen(buf));
|
||
|
sprintf(cmdbuf,"access_key=%s&created=%llu&method=%s&sign=%s",exchange->apikey,(long long)nonce,method,digest);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if ( (dir= flipstr_for_exchange(exchange,pairstr,"%s%s",dir,&price,&volume,base,rel)) == 0 )
|
||
|
{
|
||
|
printf("cant find baserel (%s/%s)\n",base,rel);
|
||
|
return(0);
|
||
|
}
|
||
|
if ( extra != 0 && strcmp(extra,"market") == 0 )
|
||
|
method = (dir > 0) ? "buy_market" : "sell_market";
|
||
|
else method = (dir > 0) ? "buy" : "sell", sprintf(pricestr,"&price=%.2f",price);
|
||
|
if ( strcmp(pairstr,"btccny") == 0 )
|
||
|
type = 1;
|
||
|
else if ( strcmp(pairstr,"ltccny") == 0 )
|
||
|
type = 2;
|
||
|
else
|
||
|
{
|
||
|
printf("cant find baserel (%s/%s)\n",base,rel);
|
||
|
return(0);
|
||
|
}
|
||
|
sprintf(buf,"access_key=%s&amount=%.4f&coin_type=%d&created=%llu&method=%s%s&secret_key=%s",exchange->apikey,volume,type,(long long)nonce,method,pricestr,exchange->apisecret);
|
||
|
calc_md5(digest,buf,(int32_t)strlen(buf));
|
||
|
sprintf(cmdbuf,"access_key=%s&amount=%.4f&coin_type=%d&created=%llu&method=%s%s&sign=%s",exchange->apikey,volume,type,(long long)nonce,method,pricestr,digest);
|
||
|
}
|
||
|
sprintf(url,"https://api.huobi.com/apiv3");
|
||
|
if ( (data= curl_post(&cHandle,url,0,cmdbuf,"Content-Type:application/x-www-form-urlencoded",0,0,0)) != 0 )
|
||
|
{
|
||
|
//printf("submit cmd.(%s) [%s]\n",cmdbuf,data);
|
||
|
if ( (json= cJSON_Parse(data)) != 0 )
|
||
|
{
|
||
|
txid = j64bits(json,"order_id");
|
||
|
free_json(json);
|
||
|
}
|
||
|
} else fprintf(stderr,"submit err cmd.(%s)\n",cmdbuf);
|
||
|
if ( retstrp != 0 )
|
||
|
*retstrp = data;
|
||
|
else if ( data != 0 )
|
||
|
free(data);
|
||
|
return(txid);
|
||
|
}
|
||
|
|
||
|
uint64_t bityes_trade(char **retstrp,struct exchange_info *exchange,char *_base,char *_rel,int32_t dir,double price,double volume)
|
||
|
{
|
||
|
static CURL *cHandle;
|
||
|
char *data,*extra,*method,pricestr[64],pairstr[64],base[64],rel[64],url[1024],cmdbuf[8192],buf[512],digest[33]; cJSON *json; uint64_t nonce,txid = 0; int32_t type;
|
||
|
nonce = exchange_nonce(exchange);
|
||
|
pricestr[0] = 0;
|
||
|
if ( (extra= *retstrp) != 0 )
|
||
|
*retstrp = 0;
|
||
|
if ( dir == 0 )
|
||
|
{
|
||
|
method = "get_account_info";
|
||
|
sprintf(buf,"access_key=%s&created=%llu&method=%s&secret_key=%s",exchange->apikey,(long long)nonce,method,exchange->apisecret);
|
||
|
calc_md5(digest,buf,(int32_t)strlen(buf));
|
||
|
sprintf(cmdbuf,"access_key=%s&created=%llu&method=%s&sign=%s",exchange->apikey,(long long)nonce,method,digest);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if ( (dir= flipstr_for_exchange(exchange,pairstr,"%s%s",dir,&price,&volume,base,rel)) == 0 )
|
||
|
{
|
||
|
printf("cant find baserel (%s/%s)\n",base,rel);
|
||
|
return(0);
|
||
|
}
|
||
|
if ( extra != 0 && strcmp(extra,"market") == 0 )
|
||
|
method = (dir > 0) ? "buy_market" : "sell_market";
|
||
|
else method = (dir > 0) ? "buy" : "sell", sprintf(pricestr,"&price=%.2f",price);
|
||
|
if ( strcmp(pairstr,"btcusd") == 0 )
|
||
|
type = 1;
|
||
|
else if ( strcmp(pairstr,"ltcusd") == 0 )
|
||
|
type = 2;
|
||
|
else
|
||
|
{
|
||
|
printf("cant find baserel (%s/%s)\n",base,rel);
|
||
|
return(0);
|
||
|
}
|
||
|
/* access_key Required Access Key
|
||
|
amount Required Order Amount
|
||
|
coin_type Required Type 1 -BTC 2 -LTC
|
||
|
created Required Submit 10 digits timestamp
|
||
|
method Required Request method: buy_market
|
||
|
sign Required MD5 Signature
|
||
|
Encryption Instance sign=md5(access_key=xxxxxxxx-xxxxxxxx-xxxxxxxx-xxxxxxx&amount=10&coin_type=1&created=1386844119&method=buy_market&secret_key=xxxxxxxx-xxxxxxxx-xxxxxxxx-xxxxxxxx)
|
||
|
trade_password Optional No sign signature, payment password is required.
|
||
|
*/
|
||
|
sprintf(buf,"access_key=%s&amount=%.4f&coin_type=%d&created=%llu&method=%s%s&secret_key=%s",exchange->apikey,volume,type,(long long)nonce,method,pricestr,exchange->apisecret);
|
||
|
calc_md5(digest,buf,(int32_t)strlen(buf));
|
||
|
sprintf(cmdbuf,"access_key=%s&amount=%.4f&coin_type=%d&created=%llu&method=%s%s&sign=%s",exchange->apikey,volume,type,(long long)nonce,method,pricestr,digest);
|
||
|
}
|
||
|
sprintf(url,"https://api.bityes.com/apiv2");
|
||
|
if ( (data= curl_post(&cHandle,url,0,cmdbuf,"Content-Type:application/x-www-form-urlencoded",0,0,0)) != 0 )
|
||
|
{
|
||
|
//printf("submit cmd.(%s) [%s]\n",cmdbuf,data);
|
||
|
if ( (json= cJSON_Parse(data)) != 0 )
|
||
|
{
|
||
|
txid = j64bits(json,"order_id");
|
||
|
free_json(json);
|
||
|
}
|
||
|
} else fprintf(stderr,"submit err cmd.(%s)\n",cmdbuf);
|
||
|
if ( retstrp != 0 )
|
||
|
*retstrp = data;
|
||
|
else if ( data != 0 )
|
||
|
free(data);
|
||
|
return(txid);
|
||
|
}
|
||
|
|
||
|
uint64_t okcoin_trade(char **retstrp,struct exchange_info *exchange,char *_base,char *_rel,int32_t dir,double price,double volume)
|
||
|
{
|
||
|
static CURL *cHandle;
|
||
|
char *data,*path,*typestr,*extra,pricestr[64],base[64],rel[64],pairstr[64],url[1024],cmdbuf[8192],buf[512],digest[33]; cJSON *json; uint64_t nonce,txid = 0;
|
||
|
nonce = exchange_nonce(exchange);
|
||
|
if ( (extra= *retstrp) != 0 )
|
||
|
*retstrp = 0;
|
||
|
if ( dir == 0 )
|
||
|
{
|
||
|
path = "userinfo.do";
|
||
|
sprintf(buf,"api_key=%s&secret_key=%s",exchange->apikey,exchange->apisecret);
|
||
|
calc_md5(digest,buf,(int32_t)strlen(buf));
|
||
|
touppercase(digest);
|
||
|
sprintf(cmdbuf,"api_key=%s&sign=%s",exchange->apikey,digest);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
path = "trade.do";
|
||
|
if ( (dir= flipstr_for_exchange(exchange,pairstr,"%s_%s",dir,&price,&volume,base,rel)) == 0 )
|
||
|
{
|
||
|
printf("cant find baserel (%s/%s)\n",base,rel);
|
||
|
return(0);
|
||
|
}
|
||
|
if ( extra != 0 && strcmp(extra,"market") == 0 )
|
||
|
typestr = (dir > 0) ? "buy_market" : "sell_market", sprintf(pricestr,"&price=%.2f",price); // docs say market orders put volume in price
|
||
|
else typestr = (dir > 0) ? "buy" : "sell", sprintf(pricestr,"&price=%.2f",price);
|
||
|
sprintf(buf,"amount=%.4f&api_key=%s%ssymbol=%s&type=%s&secret_key=%s",volume,exchange->apikey,pricestr,pairstr,typestr,exchange->apisecret);
|
||
|
calc_md5(digest,buf,(int32_t)strlen(buf));
|
||
|
touppercase(digest);
|
||
|
sprintf(cmdbuf,"amount=%.4f&api_key=%s%s&symbol=%s&type=%s&sign=%s",volume,exchange->apikey,pricestr,pairstr,typestr,digest);
|
||
|
}
|
||
|
//printf("MD5.(%s)\n",buf);
|
||
|
sprintf(url,"https://www.okcoin.com/api/v1/%s",path);
|
||
|
if ( (data= curl_post(&cHandle,url,0,cmdbuf,0,0,0,0)) != 0 ) // "{\"Content-type\":\"application/x-www-form-urlencoded\"}","{\"User-Agent\":\"OKCoin Javascript API Client\"}"
|
||
|
{
|
||
|
//printf("submit cmd.(%s) [%s]\n",cmdbuf,data);
|
||
|
if ( (json= cJSON_Parse(data)) != 0 )
|
||
|
{
|
||
|
txid = j64bits(json,"order_id");
|
||
|
free_json(json);
|
||
|
}
|
||
|
} else fprintf(stderr,"submit err cmd.(%s)\n",cmdbuf);
|
||
|
if ( retstrp != 0 )
|
||
|
*retstrp = data;
|
||
|
else if ( data != 0 )
|
||
|
free(data);
|
||
|
return(txid);
|
||
|
}
|
||
|
|
||
|
uint64_t lakebtc_trade(char **retstrp,struct exchange_info *exchange,char *_base,char *_rel,int32_t dir,double price,double volume)
|
||
|
{
|
||
|
/* LakeBTC provides trading JSON-RPC API interface. HMAC (Hash-based Message Authentication Code) is employed as our authentication mechanisms. You need at 0.1 BTC in your account to retrieve your private key.
|
||
|
|
||
|
Besides your private key, the client needs to prepare the following attributes
|
||
|
tonce (timestamp in microseconds, i.e., unixtime × 1000000, make sure your clock is correctly adjusted)
|
||
|
accesskey (your registered email address at LakeBTC)
|
||
|
requestmethod (post)
|
||
|
id (JSON-RPC request id, an integer)
|
||
|
method (JSON-RPC method)
|
||
|
params (JSON-RPC parameters)
|
||
|
Concatenate the above parameters with &, in that order. Parameters can be blank. For example, $signature =
|
||
|
tonce=1389067414466757&accesskey=foo@bar.com&requestmethod=post&id=123&method=ticker¶ms=
|
||
|
Create HMAC signature with your private key by using SHA1. $hash =
|
||
|
hash_hmac('sha1', $signature, $privatetkey) #php
|
||
|
Join your email and the hash signature with colon (:), and sign with Base64. $b64 =
|
||
|
base64_encode("foo@bar.com:<hash>") #php YXRjQHF3amlhbi5jb206ZmEzM2UzYzg5MDZjg5MzdiYzFiYw==
|
||
|
Set HTTP Header. Note tonce is the same as that in Step 2.
|
||
|
Json-Rpc-Tonce: 1389067414466757 #HTTP HEADER
|
||
|
Authorization: Basic YXRjQHF3amlhbi5jb206ZmEzM2UzYzg5MDZjg5MzdiYzFiYw== #HTTP HEADER
|
||
|
POST params data in JSON format to this url:
|
||
|
https://www.LakeBTC.com/api_v1
|
||
|
API Methods
|
||
|
getAccountInfo
|
||
|
method=getAccountInfo
|
||
|
params= (i.e., blank)*/
|
||
|
|
||
|
static CURL *cHandle;
|
||
|
char *data,*method,buf64[4096],paramstr[128],jsonbuf[1024],base[64],rel[64],pairstr[64],params[1024],dest[512],url[1024],cmdbuf[8192],*sig,hdr1[4096],hdr2[4096],buf[4096]; cJSON *json; uint64_t tonce,nonce,txid = 0;
|
||
|
*retstrp = 0;
|
||
|
params[0] = 0;
|
||
|
nonce = exchange_nonce(exchange);
|
||
|
tonce = (nonce * 1000000 + ((uint64_t)milliseconds() % 1000) * 1000);
|
||
|
if ( dir == 0 )
|
||
|
{
|
||
|
method = "getAccountInfo";
|
||
|
sprintf(buf,"tonce=%llu&accesskey=%s&requestmethod=post&id=1&method=%s¶ms=",(long long)tonce,exchange->userid,method);
|
||
|
sprintf(jsonbuf,"{\"method\":\"%s\",\"params\":[\"%s\"],\"id\":1}",method,params);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if ( (dir= flipstr_for_exchange(exchange,pairstr,"%s_%s",dir,&price,&volume,base,rel)) == 0 )
|
||
|
{
|
||
|
printf("cant find baserel (%s/%s)\n",base,rel);
|
||
|
return(0);
|
||
|
}
|
||
|
method = (dir > 0) ? "buyOrder" : "sellOrder";
|
||
|
touppercase(rel);
|
||
|
sprintf(paramstr,"%.2f,%.4f,%s",price,volume,rel);
|
||
|
sprintf(buf,"tonce=%llu&accesskey=%s&requestmethod=post&id=1&method=%s¶ms=%s",(long long)tonce,exchange->userid,method,paramstr);
|
||
|
sprintf(jsonbuf,"{\"method\":\"%s\",\"params\":[\"%s\"],\"id\":1}",method,paramstr);
|
||
|
}
|
||
|
if ( (sig= hmac_sha1_str(dest,exchange->apisecret,(int32_t)strlen(exchange->apisecret),buf)) != 0 )
|
||
|
{
|
||
|
sprintf(cmdbuf,"%s:%s",exchange->userid,sig);
|
||
|
nn_base64_encode((void *)cmdbuf,strlen(cmdbuf),buf64,sizeof(buf64));
|
||
|
sprintf(url,"https://www.lakebtc.com/api_v1");
|
||
|
sprintf(hdr1,"Authorization:Basic %s",buf64);
|
||
|
sprintf(hdr2,"Json-Rpc-Tonce: %llu",(long long)tonce);
|
||
|
if ( (data= curl_post(&cHandle,url,0,jsonbuf,hdr1,hdr2,0,0)) != 0 )
|
||
|
{
|
||
|
//printf("submit cmd.(%s) [%s]\n",jsonbuf,data);
|
||
|
if ( (json= cJSON_Parse(data)) != 0 )
|
||
|
{
|
||
|
txid = j64bits(json,"order_id");
|
||
|
free_json(json);
|
||
|
}
|
||
|
} else fprintf(stderr,"submit err cmd.(%s)\n",cmdbuf);
|
||
|
if ( retstrp != 0 )
|
||
|
*retstrp = data;
|
||
|
else if ( data != 0 )
|
||
|
free(data);
|
||
|
}
|
||
|
return(txid);
|
||
|
}
|
||
|
|
||
|
uint64_t quadriga_trade(char **retstrp,struct exchange_info *exchange,char *_base,char *_rel,int32_t dir,double price,double volume)
|
||
|
{
|
||
|
/* You need to POST 3 fields as a JSON payload to the API in order to perform authentication.
|
||
|
|
||
|
key – The API Key as shown above
|
||
|
nonce – an integer that must be unique for each API call (we recommend using a UNIX timestamp)
|
||
|
signature – HMAC_SHA256 encrypted string
|
||
|
Signature
|
||
|
|
||
|
The signature has to be created using a concatenation of the nonce, your client id, the API key and using the MD5 hash of the API Secret as key. The pseudo-algorithm is shown below and you will find code examples in the Appendix.
|
||
|
|
||
|
HMAC_SHA256 ( nonce + client + key, MD5 ( secret ) )
|
||
|
Please note the HMAC_SHA256 and MD5 strings are both lower case.
|
||
|
|
||
|
Using the API shown in Figure 2, the JSON payload will be:
|
||
|
|
||
|
{
|
||
|
key: "JJHlXeDcFM",
|
||
|
nonce: 1391683499,
|
||
|
signature: "cdbf5cc64c70e1485fcf976cdf367960c2b28cfc28080973ce677cebb6db9681"
|
||
|
}
|
||
|
The signature being calculated using:
|
||
|
|
||
|
HMAC_SHA256 ( 1391683499 + 3 + JJHlXeDcFM , MD5 ( *9q(;5]necq[otcCTfBeiI_Ug;ErCt]Ywjgg^G;t ) )
|
||
|
HMAC_SHA256 ( 13916834993JJHlXeDcFM , 230664ae53cbe5a07c6c389910540729 )
|
||
|
= cdbf5cc64c70e1485fcf976cdf367960c2b28cfc28080973ce677cebb6db9681
|
||
|
|
||
|
curl_setopt($ch, CURLOPT_POSTFIELDS, $data_string);
|
||
|
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||
|
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
|
||
|
'Content-Type: application/json; charset=utf-8',
|
||
|
'Content-Length: ' . strlen($data_string))
|
||
|
);
|
||
|
|
||
|
*/
|
||
|
static CURL *cHandle;
|
||
|
char *extra,*sig,*data,*path,pairstr[64],base[64],rel[64],hdr3[4096],url[512],md5secret[128],req[4096],payload[4096],hdr1[4096],hdr2[4096],dest[1024 + 1];
|
||
|
cJSON *json; uint64_t nonce,txid = 0;
|
||
|
memset(payload,0,sizeof(payload));
|
||
|
if ( (extra= *retstrp) != 0 )
|
||
|
*retstrp = 0;
|
||
|
nonce = exchange_nonce(exchange);
|
||
|
sprintf(payload,"%llu%s%s",(long long)nonce,exchange->userid,exchange->apikey);
|
||
|
calc_md5(md5secret,exchange->apisecret,(int32_t)strlen(exchange->apisecret));
|
||
|
if ( (sig= hmac_sha256_str(dest,md5secret,(int32_t)strlen(md5secret),payload)) != 0 )
|
||
|
{
|
||
|
if ( dir == 0 )
|
||
|
{
|
||
|
path = "balance";
|
||
|
sprintf(req,"{\"key\":\"%s\",\"nonce\":%llu,\"signature\":\"%s\"}",exchange->apikey,(long long)nonce,sig);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if ( (dir= flipstr_for_exchange(exchange,pairstr,"%s_%s",dir,&price,&volume,base,rel)) == 0 )
|
||
|
{
|
||
|
printf("cant find baserel (%s/%s)\n",base,rel);
|
||
|
return(0);
|
||
|
}
|
||
|
path = (dir > 0) ? "buy" : "sell";
|
||
|
/*key - API key
|
||
|
signature - signature
|
||
|
nonce - nonce
|
||
|
amount - amount of major currency
|
||
|
price - price to buy at
|
||
|
book - optional, if not specified, will default to btc_cad*/
|
||
|
sprintf(req,"{\"key\":\"%s\",\"amount\":%.6f,\"price\":%.3f,\"book\":\"%s_%s\",\"nonce\":%llu,\"signature\":\"%s\"}",exchange->apikey,volume,price,base,rel,(long long)nonce,sig);
|
||
|
|
||
|
//dir = flip_for_exchange(pairstr,"%s_%s","BTC",dir,&price,&volume,base,rel);
|
||
|
}
|
||
|
sprintf(hdr1,"Content-Type:application/json"), sprintf(hdr2,"charset=utf-8"), sprintf(hdr3,"Content-Length:%ld",(long)strlen(req));
|
||
|
printf("quadriga req.(%s) -> (%s) [%s %s sig.%s]\n",req,payload,md5secret,payload,sig);
|
||
|
sprintf(url,"https://api.quadrigacx.com/v2/%s",path);
|
||
|
if ( (data= curl_post(&cHandle,url,0,req,hdr1,hdr2,hdr3,0)) != 0 )
|
||
|
{
|
||
|
printf("[%s]\n",data);
|
||
|
if ( (json= cJSON_Parse(data)) != 0 )
|
||
|
{
|
||
|
free_json(json);
|
||
|
}
|
||
|
}
|
||
|
if ( retstrp != 0 )
|
||
|
*retstrp = data;
|
||
|
else if ( data != 0 )
|
||
|
free(data);
|
||
|
}
|
||
|
return(txid);
|
||
|
}
|
||
|
|
||
|
uint64_t bitstamp_trade(char **retstrp,struct exchange_info *exchange,char *base,char *rel,int32_t dir,double price,double volume)
|
||
|
{
|
||
|
/*signature is a HMAC-SHA256 encoded message containing: nonce, customer ID (can be found here) and API key. The HMAC-SHA256 code must be generated using a secret key that was generated with your API key. This code must be converted to it's hexadecimal representation (64 uppercase characters).Example (Python):
|
||
|
message = nonce + customer_id + api_key
|
||
|
signature = hmac.new(API_SECRET, msg=message, digestmod=hashlib.sha256).hexdigest().upper()
|
||
|
|
||
|
key - API key
|
||
|
signature - signature
|
||
|
nonce - nonce
|
||
|
*/
|
||
|
|
||
|
static CURL *cHandle;
|
||
|
char *sig,*data,*path,url[512],req[4096],payload[2048],dest[1024 + 1]; cJSON *json; uint64_t nonce,txid = 0;
|
||
|
memset(payload,0,sizeof(payload));
|
||
|
nonce = exchange_nonce(exchange);
|
||
|
sprintf(payload,"%llu%s%s",(long long)nonce,exchange->userid,exchange->apikey);
|
||
|
if ( dir == 0 )
|
||
|
path = "balance";
|
||
|
else
|
||
|
{
|
||
|
//dir = flip_for_exchange(pairstr,"%s_%s","BTC",dir,&price,&volume,base,rel);
|
||
|
}
|
||
|
if ( (sig= hmac_sha256_str(dest,exchange->apisecret,(int32_t)strlen(exchange->apisecret),payload)) != 0 )
|
||
|
{
|
||
|
touppercase(sig);
|
||
|
sprintf(req,"{\"key\":\"%s\",\"signature\":\"%s\",\"nonce\":%llu}",exchange->apikey,sig,(long long)nonce);
|
||
|
sprintf(url,"https://www.bitstamp.net/api/%s/",path);
|
||
|
printf("bitstamp.(%s) ->\n",req);
|
||
|
if ( (data= curl_post(&cHandle,url,0,req,0,0,0,0)) != 0 )
|
||
|
{
|
||
|
printf("[%s]\n",data);
|
||
|
if ( (json= cJSON_Parse(data)) != 0 )
|
||
|
{
|
||
|
free_json(json);
|
||
|
}
|
||
|
}
|
||
|
if ( retstrp != 0 )
|
||
|
*retstrp = data;
|
||
|
else if ( data != 0 )
|
||
|
free(data);
|
||
|
}
|
||
|
return(txid);
|
||
|
}
|
||
|
|
||
|
uint64_t coinbase_trade(char **retstrp,struct exchange_info *exchange,char *base,char *rel,int32_t dir,double price,double volume)
|
||
|
{
|
||
|
/*All REST requests must contain the following headers:
|
||
|
|
||
|
CB-ACCESS-KEY The api key as a string.
|
||
|
CB-ACCESS-SIGN The base64-encoded signature (see Signing a Message).
|
||
|
CB-ACCESS-TIMESTAMP A timestamp for your request.
|
||
|
CB-ACCESS-PASSPHRASE The passphrase you specified when creating the API key.
|
||
|
All request bodies should have content type application/json and be valid JSON.
|
||
|
|
||
|
Signing a Message
|
||
|
The CB-ACCESS-SIGN header is generated by creating a sha256 HMAC using the base64-decoded
|
||
|
secret key on the prehash string timestamp + method + requestPath + body (where + represents string concatenation)
|
||
|
and base64-encode the output. The timestamp value is the same as the CB-ACCESS-TIMESTAMP header.
|
||
|
|
||
|
The body is the request body string or omitted if there is no request body (typically for GET requests).
|
||
|
|
||
|
The method should be UPPER CASE
|
||
|
Remember to first base64-decode the alphanumeric secret string (resulting in 64 bytes) before using it as the key for HMAC. Also, base64-encode the digest output before sending in the header.
|
||
|
*/
|
||
|
static CURL *cHandle;
|
||
|
char *sig,*data,*path,sig64[1024],body[4096],method[64],prehash64[512],prehash[512],cmdbuf[8192],url[1024],decodedsecret[128],hdr1[4096],hdr2[4096],hdr3[4096],hdr4[4096],pairstr[512],dest[SHA512_DIGEST_SIZE*2 + 1]; cJSON *json; int32_t n; uint64_t nonce,txid = 0;
|
||
|
nonce = exchange_nonce(exchange);
|
||
|
cmdbuf[0] = 0;
|
||
|
body[0] = 0;
|
||
|
n = nn_base64_decode((void *)exchange->apisecret,strlen(exchange->apisecret),(void *)decodedsecret,sizeof(decodedsecret));
|
||
|
if ( dir == 0 )
|
||
|
path = "accounts", strcpy(method,"GET");
|
||
|
else
|
||
|
{
|
||
|
path = "trade", strcpy(method,"POST");
|
||
|
dir = flip_for_exchange(pairstr,"%s_%s","BTC",dir,&price,&volume,base,rel);
|
||
|
sprintf(cmdbuf,"method=Trade&nonce=%ld&pair=%s&type=%s&rate=%.6f&amount=%.6f",(long)time(NULL),pairstr,dir>0?"buy":"sell",price,volume);
|
||
|
}
|
||
|
touppercase(method);
|
||
|
sprintf(prehash,"%llu%s/%s%s",(long long)nonce,method,path,body);
|
||
|
nn_base64_encode((void *)prehash,strlen(prehash),prehash64,sizeof(prehash64));
|
||
|
if ( (sig= hmac_sha256_str(dest,decodedsecret,n,prehash64)) != 0 )
|
||
|
{
|
||
|
nn_base64_encode((void *)sig,strlen(sig),sig64,sizeof(sig64));
|
||
|
}
|
||
|
//CB-ACCESS-KEY The api key as a string.
|
||
|
//CB-ACCESS-SIGN The base64-encoded signature (see Signing a Message).
|
||
|
//CB-ACCESS-TIMESTAMP A timestamp for your request.
|
||
|
//CB-ACCESS-PASSPHRASE The passphrase you specified when creating the API key.
|
||
|
sprintf(hdr1,"CB-ACCESS-KEY:%s",exchange->apikey);
|
||
|
sprintf(hdr2,"CB-ACCESS-SIGN:%s",sig64);
|
||
|
sprintf(hdr3,"CB-ACCESS-TIMESTAMP:%llu",(long long)nonce);
|
||
|
//sprintf(hdr4,"CB-ACCESS-PASSPHRASE:%s; content-type:application/json; charset=utf-8",exchange->userid);
|
||
|
sprintf(hdr4,"CB-ACCESS-PASSPHRASE:%s",exchange->userid);
|
||
|
sprintf(url,"https://api.exchange.coinbase.com/%s",path);
|
||
|
if ( (data= curl_post(&cHandle,url,0,cmdbuf,hdr1,hdr2,hdr3,hdr4)) != 0 )
|
||
|
{
|
||
|
printf("cmd.(%s) prehash.(%s) n.%d [%s]\n",cmdbuf,prehash,n,data);
|
||
|
//{ "success":1, "return":{ "received":0.1, "remains":0, "order_id":0, "funds":{ "usd":325, "btc":2.498, } } }
|
||
|
if ( (json= cJSON_Parse(data)) != 0 )
|
||
|
{
|
||
|
free_json(json);
|
||
|
}
|
||
|
}
|
||
|
if ( retstrp != 0 )
|
||
|
*retstrp = data;
|
||
|
else if ( data != 0 )
|
||
|
free(data);
|
||
|
return(txid);
|
||
|
}
|
||
|
|
||
|
#ifdef enable_exmo
|
||
|
uint64_t exmo_trade(char **retstrp,struct exchange_info *exchange,char *base,char *rel,int32_t dir,double price,double volume)
|
||
|
{
|
||
|
/* $req['nonce'] = $NONCE;
|
||
|
|
||
|
// generate the POST data string
|
||
|
$post_data = http_build_query($req, '', '&');
|
||
|
|
||
|
$sign = hash_hmac('sha512', $post_data, $secret);
|
||
|
|
||
|
// generate the extra headers
|
||
|
$headers = array(
|
||
|
'Sign: ' . $sign,
|
||
|
'Key: ' . $key,
|
||
|
);
|
||
|
*/
|
||
|
static CURL *cHandle;
|
||
|
char *sig,*method,*data,url[512],cmdbuf[8192],hdr1[4096],hdr2[4096],pairstr[512],dest[SHA512_DIGEST_SIZE*2 + 1]; cJSON *json; uint64_t nonce,txid = 0;
|
||
|
nonce = exchange_nonce(exchange);
|
||
|
if ( dir == 0 )
|
||
|
{
|
||
|
sprintf(cmdbuf,"nonce=%llu?method=get_info",(long long)nonce);
|
||
|
method = "get_info";
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
method = "notyet";
|
||
|
dir = flip_for_exchange(pairstr,"%s_%s","BTC",dir,&price,&volume,base,rel);
|
||
|
sprintf(cmdbuf,"method=Trade&nonce=%ld&pair=%s&type=%s&rate=%.6f&amount=%.6f",(long)time(NULL),pairstr,dir>0?"buy":"sell",price,volume);
|
||
|
//printf("cmdbuf.(%s) h1.(%s) h2.(%s)\n",cmdbuf,hdr2,hdr1);
|
||
|
}
|
||
|
if ( (sig= hmac_sha512_str(dest,exchange->apisecret,(int32_t)strlen(exchange->apisecret),cmdbuf)) != 0 )
|
||
|
sprintf(hdr2,"Sign:%s",sig);
|
||
|
else hdr2[0] = 0;
|
||
|
sprintf(hdr1,"Key:%s",exchange->apikey);
|
||
|
sprintf(url,"https://api.exmo.com/api_v2/%s",method);
|
||
|
sprintf(cmdbuf,"{\"method\":\"get_info\"}");
|
||
|
if ( (data= curl_post(&cHandle,url,0,cmdbuf,hdr1,hdr2,0,0)) != 0 )
|
||
|
{
|
||
|
printf("cmd.(%s) [%s]\n",cmdbuf,data);
|
||
|
if ( (json= cJSON_Parse(data)) != 0 )
|
||
|
{
|
||
|
free_json(json);
|
||
|
}
|
||
|
}
|
||
|
if ( retstrp != 0 )
|
||
|
*retstrp = data;
|
||
|
else if ( data != 0 )
|
||
|
free(data);
|
||
|
return(txid);
|
||
|
}
|
||
|
#endif
|
||
|
#endif
|
||
|
|
||
|
uint64_t submit_triggered_nxtae(int32_t dotrade,char **retjsonstrp,int32_t is_MS,char *bidask,uint64_t nxt64bits,char *NXTACCTSECRET,uint64_t assetid,uint64_t qty,uint64_t NXTprice,char *triggerhash,char *comment,uint64_t otherNXT,uint32_t triggerheight)
|
||
|
{
|
||
|
int32_t deadline = 1 + 20; uint64_t txid = 0; struct destbuf errstr; char cmd[4096],secret[8192],*jsonstr; cJSON *json;
|
||
|
if ( retjsonstrp != 0 )
|
||
|
*retjsonstrp = 0;
|
||
|
if ( triggerheight != 0 )
|
||
|
deadline = DEFAULT_NXT_DEADLINE;
|
||
|
escape_code(secret,NXTACCTSECRET);
|
||
|
if ( dotrade == 0 )
|
||
|
strcpy(secret,"<secret>");
|
||
|
sprintf(cmd,"requestType=%s&secretPhrase=%s&feeNQT=%llu&deadline=%d",bidask,secret,(long long)MIN_NQTFEE,deadline);
|
||
|
sprintf(cmd+strlen(cmd),"&%s=%llu&%s=%llu",is_MS!=0?"units":"quantityQNT",(long long)qty,is_MS!=0?"currency":"asset",(long long)assetid);
|
||
|
if ( NXTprice != 0 )
|
||
|
{
|
||
|
if ( is_MS != 0 )
|
||
|
sprintf(cmd+strlen(cmd),"&rateNQT=%llu",(long long)NXTprice);
|
||
|
else sprintf(cmd+strlen(cmd),"&priceNQT=%llu",(long long)NXTprice);
|
||
|
}
|
||
|
if ( otherNXT != 0 )
|
||
|
sprintf(cmd+strlen(cmd),"&recipient=%llu",(long long)otherNXT);
|
||
|
if ( triggerhash != 0 && triggerhash[0] != 0 )
|
||
|
{
|
||
|
if ( triggerheight == 0 )
|
||
|
sprintf(cmd+strlen(cmd),"&referencedTransactionFullHash=%s",triggerhash);
|
||
|
else sprintf(cmd+strlen(cmd),"&referencedTransactionFullHash=%s&phased=true&phasingFinishHeight=%u&phasingVotingModel=4&phasingQuorum=1&phasingLinkedFullHash=%s",triggerhash,triggerheight,triggerhash);
|
||
|
}
|
||
|
if ( comment != 0 && comment[0] != 0 )
|
||
|
sprintf(cmd+strlen(cmd),"&message=%s",comment);
|
||
|
if ( dotrade == 0 )
|
||
|
{
|
||
|
if ( retjsonstrp != 0 )
|
||
|
{
|
||
|
json = cJSON_CreateObject();
|
||
|
jaddstr(json,"submit",cmd);
|
||
|
*retjsonstrp = jprint(json,1);
|
||
|
}
|
||
|
return(0);
|
||
|
}
|
||
|
if ( (jsonstr= issue_NXTPOST(cmd)) != 0 )
|
||
|
{
|
||
|
_stripwhite(jsonstr,' ');
|
||
|
if ( (json= cJSON_Parse(jsonstr)) != 0 )
|
||
|
{
|
||
|
copy_cJSON(&errstr,cJSON_GetObjectItem(json,"error"));
|
||
|
if ( errstr.buf[0] == 0 )
|
||
|
copy_cJSON(&errstr,cJSON_GetObjectItem(json,"errorDescription"));
|
||
|
if ( errstr.buf[0] != 0 )
|
||
|
{
|
||
|
printf("submit_triggered_bidask.(%s) -> (%s)\n",cmd,jsonstr);
|
||
|
if ( retjsonstrp != 0 )
|
||
|
*retjsonstrp = clonestr(errstr.buf);
|
||
|
}
|
||
|
else txid = get_API_nxt64bits(cJSON_GetObjectItem(json,"transaction"));
|
||
|
}
|
||
|
free(jsonstr);
|
||
|
}
|
||
|
return(txid);
|
||
|
}
|
||
|
|
||
|
int32_t get_assettype(int32_t *numdecimalsp,char *assetidstr)
|
||
|
{
|
||
|
cJSON *json; char name[64],*jsonstr; uint64_t assetid; int32_t ap_type = -1; //struct assethash *ap,A;
|
||
|
*numdecimalsp = -1;
|
||
|
name[0] = 0;
|
||
|
if ( is_native_crypto(name,calc_nxt64bits(assetidstr)) > 0 )
|
||
|
{
|
||
|
//printf("found native crypto.(%s) name.(%s)\n",assetidstr,name);
|
||
|
ap_type = 0;
|
||
|
*numdecimalsp = 8;
|
||
|
return(0);
|
||
|
}
|
||
|
if ( (assetid= calc_nxt64bits(assetidstr)) == NXT_ASSETID )
|
||
|
{
|
||
|
//printf("found NXT_ASSETID.(%s)\n",assetidstr);
|
||
|
ap_type = 0;
|
||
|
*numdecimalsp = 8;
|
||
|
return(0);
|
||
|
}
|
||
|
/*if ( (ap= find_asset(assetid)) != 0 )
|
||
|
{
|
||
|
*numdecimalsp = ap->decimals;
|
||
|
return(ap->type);
|
||
|
}*/
|
||
|
memset(name,0,sizeof(name));
|
||
|
if ( (jsonstr= _issue_getAsset(assetidstr)) != 0 )
|
||
|
{
|
||
|
if ( (json= cJSON_Parse(jsonstr)) != 0 )
|
||
|
{
|
||
|
if ( get_cJSON_int(json,"errorCode") == 0 )
|
||
|
{
|
||
|
//printf("assetstr.(%s)\n",jsonstr);
|
||
|
if ( extract_cJSON_str(name,16,json,"name") <= 0 )
|
||
|
*numdecimalsp = -1;
|
||
|
else *numdecimalsp = (int32_t)get_cJSON_int(json,"decimals");
|
||
|
ap_type = 2;
|
||
|
} //else printf("errorcode.%lld (%s)\n",(long long)get_cJSON_int(json,"errorCode"),jsonstr);
|
||
|
free_json(json);
|
||
|
} else printf("cant parse.(%s)\n",jsonstr);
|
||
|
free(jsonstr);
|
||
|
} else printf("couldnt getAsset.(%s)\n",assetidstr);
|
||
|
if ( ap_type < 0 )
|
||
|
{
|
||
|
if ( (jsonstr= _issue_getCurrency(assetidstr)) != 0 )
|
||
|
{
|
||
|
if ( (json= cJSON_Parse(jsonstr)) != 0 )
|
||
|
{
|
||
|
if ( get_cJSON_int(json,"errorCode") == 0 )
|
||
|
{
|
||
|
if ( extract_cJSON_str(name,16,json,"name") <= 0 )
|
||
|
*numdecimalsp = -1;
|
||
|
else *numdecimalsp = (int32_t)get_cJSON_int(json,"decimals");
|
||
|
ap_type = 5;
|
||
|
}
|
||
|
free_json(json);
|
||
|
}
|
||
|
free(jsonstr);
|
||
|
}
|
||
|
}
|
||
|
/*memset(&A,0,sizeof(A));
|
||
|
A.assetid = assetid;
|
||
|
A.minvol = A.mult = calc_decimals_mult(*numdecimalsp);
|
||
|
A.decimals = *numdecimalsp;
|
||
|
A.type = ap_type;
|
||
|
strcpy(A.name,name);
|
||
|
create_asset(assetid,&A);*/
|
||
|
return(ap_type);
|
||
|
}
|
||
|
|
||
|
uint64_t assetmult(char *assetidstr)
|
||
|
{
|
||
|
int32_t ap_type,decimals; uint64_t mult = 0;
|
||
|
ap_type = get_assettype(&decimals,assetidstr);
|
||
|
if ( decimals >= 0 && decimals <= 8 )
|
||
|
mult = calc_decimals_mult(decimals);
|
||
|
return(mult);
|
||
|
}
|
||
|
|
||
|
int32_t assetdecimals(char *assetidstr)
|
||
|
{
|
||
|
int32_t ap_type,decimals = 0;
|
||
|
ap_type = get_assettype(&decimals,assetidstr);
|
||
|
if ( ap_type == 0 )
|
||
|
return(8);
|
||
|
return(decimals);
|
||
|
}
|
||
|
|
||
|
uint64_t min_asset_amount(uint64_t assetid)
|
||
|
{
|
||
|
char assetidstr[64];
|
||
|
if ( assetid == NXT_ASSETID )
|
||
|
return(1);
|
||
|
expand_nxt64bits(assetidstr,assetid);
|
||
|
return(assetmult(assetidstr));
|
||
|
}
|
||
|
|
||
|
int32_t get_assetdecimals(uint64_t assetid)
|
||
|
{
|
||
|
char assetidstr[64];
|
||
|
if ( assetid == NXT_ASSETID )
|
||
|
return(8);
|
||
|
expand_nxt64bits(assetidstr,assetid);
|
||
|
return(assetdecimals(assetidstr));
|
||
|
}
|
||
|
|
||
|
uint64_t get_assetmult(uint64_t assetid)
|
||
|
{
|
||
|
char assetidstr[64];
|
||
|
expand_nxt64bits(assetidstr,assetid);
|
||
|
return(assetmult(assetidstr));
|
||
|
}
|
||
|
|
||
|
double get_minvolume(uint64_t assetid)
|
||
|
{
|
||
|
return(dstr(get_assetmult(assetid)));
|
||
|
}
|
||
|
|
||
|
int64_t get_asset_quantity(int64_t *unconfirmedp,char *NXTaddr,char *assetidstr)
|
||
|
{
|
||
|
char cmd[2*MAX_JSON_FIELD],*jsonstr; struct destbuf assetid; int32_t i,n,iter; cJSON *array,*item,*obj,*json; int64_t quantity,qty = 0;
|
||
|
uint64_t assetidbits = calc_nxt64bits(assetidstr);
|
||
|
quantity = *unconfirmedp = 0;
|
||
|
if ( assetidbits == NXT_ASSETID )
|
||
|
{
|
||
|
sprintf(cmd,"requestType=getBalance&account=%s",NXTaddr);
|
||
|
if ( (jsonstr= issue_NXTPOST(cmd)) != 0 )
|
||
|
{
|
||
|
//printf("(%s) -> (%s)\n",cmd,jsonstr);
|
||
|
if ( (json= cJSON_Parse(jsonstr)) != 0 )
|
||
|
{
|
||
|
qty = get_API_nxt64bits(cJSON_GetObjectItem(json,"balanceNQT"));
|
||
|
*unconfirmedp = get_API_nxt64bits(cJSON_GetObjectItem(json,"unconfirmedBalanceNQT"));
|
||
|
printf("(%s)\n",jsonstr);
|
||
|
free_json(json);
|
||
|
}
|
||
|
free(jsonstr);
|
||
|
}
|
||
|
return(qty);
|
||
|
}
|
||
|
sprintf(cmd,"requestType=getAccount&account=%s",NXTaddr);
|
||
|
if ( (jsonstr= issue_NXTPOST(cmd)) != 0 )
|
||
|
{
|
||
|
//printf("(%s) -> (%s)\n",cmd,jsonstr);
|
||
|
if ( (json= cJSON_Parse(jsonstr)) != 0 )
|
||
|
{
|
||
|
for (iter=0; iter<2; iter++)
|
||
|
{
|
||
|
qty = 0;
|
||
|
array = cJSON_GetObjectItem(json,iter==0?"assetBalances":"unconfirmedAssetBalances");
|
||
|
if ( is_cJSON_Array(array) != 0 )
|
||
|
{
|
||
|
n = cJSON_GetArraySize(array);
|
||
|
for (i=0; i<n; i++)
|
||
|
{
|
||
|
item = cJSON_GetArrayItem(array,i);
|
||
|
obj = cJSON_GetObjectItem(item,"asset");
|
||
|
copy_cJSON(&assetid,obj);
|
||
|
//printf("i.%d of %d: %s(%s)\n",i,n,assetid,cJSON_Print(item));
|
||
|
if ( strcmp(assetid.buf,assetidstr) == 0 )
|
||
|
{
|
||
|
qty = get_cJSON_int(item,iter==0?"balanceQNT":"unconfirmedBalanceQNT");
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if ( iter == 0 )
|
||
|
quantity = qty;
|
||
|
else *unconfirmedp = qty;
|
||
|
}
|
||
|
free_json(json);
|
||
|
}
|
||
|
free(jsonstr);
|
||
|
}
|
||
|
return(quantity);
|
||
|
}
|
||
|
|
||
|
uint64_t calc_asset_qty(uint64_t *availp,uint64_t *priceNQTp,char *NXTaddr,int32_t checkflag,uint64_t assetid,double price,double vol)
|
||
|
{
|
||
|
char assetidstr[64];
|
||
|
uint64_t ap_mult,priceNQT,quantityQNT = 0;
|
||
|
int64_t unconfirmed,balance;
|
||
|
*priceNQTp = *availp = 0;
|
||
|
if ( assetid != NXT_ASSETID )
|
||
|
{
|
||
|
expand_nxt64bits(assetidstr,assetid);
|
||
|
if ( (ap_mult= get_assetmult(assetid)) != 0 )
|
||
|
{
|
||
|
//price = (double)get_satoshi_obj(srcitem,"priceNQT") / ap_mult;
|
||
|
//vol = (double)get_satoshi_obj(srcitem,"quantityQNT") * ((double)ap_mult / SATOSHIDEN);
|
||
|
priceNQT = (price * ap_mult + (ap_mult/2)/SATOSHIDEN);
|
||
|
quantityQNT = (vol * SATOSHIDEN) / ap_mult;
|
||
|
balance = get_asset_quantity(&unconfirmed,NXTaddr,assetidstr);
|
||
|
//printf("%s balance %.8f unconfirmed %.8f vs price %llu qty %llu for asset.%s | price_vol.(%f * %f) * (%lld / %llu)\n",NXTaddr,dstr(balance),dstr(unconfirmed),(long long)priceNQT,(long long)quantityQNT,assetidstr,price,vol,(long long)SATOSHIDEN,(long long)ap_mult);
|
||
|
//getchar();
|
||
|
if ( checkflag != 0 && (balance < quantityQNT || unconfirmed < quantityQNT) )
|
||
|
{
|
||
|
printf("balance %.8f < qty %.8f || unconfirmed %.8f < qty %llu\n",dstr(balance),dstr(quantityQNT),dstr(unconfirmed),(long long)quantityQNT);
|
||
|
return(0);
|
||
|
}
|
||
|
*priceNQTp = priceNQT;
|
||
|
*availp = unconfirmed;
|
||
|
} else printf("%llu null apmult\n",(long long)assetid);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
*priceNQTp = price * SATOSHIDEN;
|
||
|
quantityQNT = vol;
|
||
|
}
|
||
|
return(quantityQNT);
|
||
|
}
|
||
|
|
||
|
char *fill_nxtae(int32_t dotrade,uint64_t *txidp,uint64_t nxt64bits,char *secret,int32_t dir,double price,double volume,uint64_t baseid,uint64_t relid)
|
||
|
{
|
||
|
uint64_t txid,assetid,avail,qty,priceNQT,ap_mult; char retbuf[512],*errstr;
|
||
|
if ( nxt64bits != IGUANA_MY64BITS )
|
||
|
return(clonestr("{\"error\":\"must use your NXT address\"}"));
|
||
|
else if ( baseid == NXT_ASSETID )
|
||
|
dir = -dir, assetid = relid;
|
||
|
else if ( relid == NXT_ASSETID )
|
||
|
assetid = baseid;
|
||
|
else return(clonestr("{\"error\":\"NXT AE order without NXT\"}"));
|
||
|
if ( (ap_mult= get_assetmult(assetid)) == 0 )
|
||
|
return(clonestr("{\"error\":\"assetid not found\"}"));
|
||
|
qty = calc_asset_qty(&avail,&priceNQT,secret,0,assetid,price,volume);
|
||
|
txid = submit_triggered_nxtae(dotrade,&errstr,0,dir > 0 ? "placeBidOrder" : "placeAskOrder",nxt64bits,secret,assetid,qty,priceNQT,0,0,0,0);
|
||
|
if ( errstr != 0 )
|
||
|
sprintf(retbuf,"{\"error\":\"%s\"}",errstr), free(errstr);
|
||
|
else sprintf(retbuf,"{\"result\":\"success\",\"txid\":\"%llu\"}",(long long)txid);
|
||
|
if ( txidp != 0 )
|
||
|
*txidp = txid;
|
||
|
return(clonestr(retbuf));
|
||
|
}
|
||
|
|
||
|
uint64_t submit_to_exchange(void **cHandlep,int32_t dotrade,int32_t exchangeid,char **jsonstrp,uint64_t assetid,uint64_t qty,uint64_t priceNQT,int32_t dir,uint64_t nxt64bits,char *NXTACCTSECRET,char *triggerhash,char *comment,uint64_t otherNXT,char *base,char *rel,double price,double volume,uint32_t triggerheight)
|
||
|
{
|
||
|
uint64_t txid = 0;
|
||
|
char assetidstr[64],*cmd,*retstr = 0;
|
||
|
int32_t ap_type,decimals;
|
||
|
struct exchange_info *exchange;
|
||
|
*jsonstrp = 0;
|
||
|
expand_nxt64bits(assetidstr,assetid);
|
||
|
ap_type = get_assettype(&decimals,assetidstr);
|
||
|
if ( dir == 0 || priceNQT == 0 )
|
||
|
cmd = (ap_type == 2 ? "transferAsset" : "transferCurrency"), priceNQT = 0;
|
||
|
else cmd = ((dir > 0) ? (ap_type == 2 ? "placeBidOrder" : "currencyBuy") : (ap_type == 2 ? "placeAskOrder" : "currencySell")), otherNXT = 0;
|
||
|
if ( exchangeid == INSTANTDEX_NXTAEID || exchangeid == INSTANTDEX_UNCONFID )
|
||
|
{
|
||
|
if ( assetid != NXT_ASSETID && qty != 0 && (dir == 0 || priceNQT != 0) )
|
||
|
{
|
||
|
printf("submit to exchange.%s (%s) dir.%d\n",Exchanges[exchangeid].name,comment,dir);
|
||
|
txid = submit_triggered_nxtae(dotrade,jsonstrp,ap_type == 5,cmd,nxt64bits,NXTACCTSECRET,assetid,qty,priceNQT,triggerhash,comment,otherNXT,triggerheight);
|
||
|
if ( *jsonstrp != 0 )
|
||
|
txid = 0;
|
||
|
}
|
||
|
}
|
||
|
else if ( exchangeid < MAX_EXCHANGES && (exchange= &Exchanges[exchangeid]) != 0 && exchange->exchangeid == exchangeid && exchange->issue.trade != 0 )
|
||
|
{
|
||
|
printf("submit_to_exchange.(%d) dir.%d price %f vol %f | inv %f %f (%s)\n",exchangeid,dir,price,volume,1./price,price*volume,comment);
|
||
|
if ( (txid= (*exchange->issue.trade)(cHandlep,dotrade,&retstr,exchange,base,rel,dir,price,volume)) == 0 )
|
||
|
printf("error trading (%s/%s) dir.%d price %f vol %f ret.(%s)\n",base,rel,dir,price,volume,retstr!=0?retstr:"");
|
||
|
if ( jsonstrp != 0 )
|
||
|
*jsonstrp = retstr;
|
||
|
}
|
||
|
return(txid);
|
||
|
}
|
||
|
|
||
|
uint64_t InstantDEX_tradestub(void **cHandlep,int32_t dotrade,char **retstrp,struct exchange_info *exchange,char *base,char *rel,int32_t dir,double price,double volume)
|
||
|
{
|
||
|
printf("this is just a InstantDEX_tradestub\n");
|
||
|
return(0);
|
||
|
}
|
||
|
|
||
|
uint64_t NXT_tradestub(void **cHandlep,int32_t dotrade,char **retstrp,struct exchange_info *exchange,char *base,char *rel,int32_t dir,double price,double volume)
|
||
|
{
|
||
|
printf("this is just a NXT_tradestub\n");
|
||
|
return(0);
|
||
|
}
|
||
|
|
||
|
#endif
|