/****************************************************************************** * 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_exchangeparse_h #define xcode_exchangeparse_h char *Supported_exchanges[] = { INSTANTDEX_NAME, INSTANTDEX_NXTAEUNCONF, INSTANTDEX_NXTAENAME, INSTANTDEX_BASKETNAME, "basketNXT", "basketUSD", "basketBTC", "basketCNY", INSTANTDEX_ACTIVENAME, "wallet", "jumblr", "pangea", "peggy", // peggy MUST be last of special exchanges "bitfinex", "btc38", "bitstamp", "btce", "poloniex", "bittrex", "huobi", "coinbase", "okcoin", "lakebtc", "quadriga", //"bityes", "kraken", "gatecoin", "quoine", "jubi", "hitbtc" // no trading for these exchanges yet }; // "bter" <- orderbook is backwards and all entries are needed, later to support, "exmo" flakey apiservers void init_exchanges() { int32_t i; for (FIRST_EXTERNAL=0; FIRST_EXTERNAL %llu BTC -> %llu\n",(long long)stringbits("NXT"),(long long)stringbits("BTC")); //INSTANTDEX.readyflag = 1; } int32_t supported_exchange(char *exchangestr) { int32_t i; for (i=0; iname[0] == 0 ) break; cJSON_AddItemToObject(item,"name",cJSON_CreateString(exchange->name)); memset(api,0,sizeof(api)); n = 0; if ( exchange->issue.trade != 0 ) { //printf("%s.(%s/%s/%s).%p\n",exchange->name,exchange->apikey,exchange->apisecret,exchange->userid,exchange); if ( exchange->apikey[0] != 0 ) api[n++] = 'K'; if ( exchange->apisecret[0] != 0 ) api[n++] = 'S'; if ( exchange->userid[0] != 0 ) api[n++] = 'U'; api[n] = 0; cJSON_AddItemToObject(item,"trade",cJSON_CreateString(api)); } cJSON_AddItemToArray(array,item); } return(array); } int32_t is_exchange_nxt64bits(uint64_t nxt64bits) { int32_t exchangeid; struct exchange_info *exchange = 0; for (exchangeid=0; exchangeidname,(long long)exchange->nxt64bits,(long long)nxt64bits); if ( exchange->name[0] == 0 ) return(0); if ( exchange->nxt64bits == nxt64bits ) return(1); } printf("no exchangebits match\n"); return(0); } struct exchange_info *get_exchange(int32_t exchangeid) { return(&Exchanges[exchangeid]); } char *exchange_str(int32_t exchangeid) { return(Exchanges[exchangeid].name); } struct exchange_info *exchange_find(char *exchangestr) { int32_t exchangeid; struct exchange_info *exchange = 0; for (exchangeid=0; exchangeidname) == 0 ) return(exchange); } return(0); } struct exchange_info *find_exchange(int32_t *exchangeidp,char *exchangestr) { int32_t exchangeid; struct exchange_info *exchange = 0; if ( supported_exchange(exchangestr) < 0 ) { if ( exchangeidp != 0 ) *exchangeidp = -1; return(0); } for (exchangeid=0; exchangeidname); if ( exchange->name[0] == 0 ) { portable_mutex_init(&exchange->mutex); strcpy(exchange->name,exchangestr); exchange->exchangeid = exchangeid; exchange->nxt64bits = stringbits(exchangestr); printf("CREATE EXCHANGE.(%s) id.%d %llu\n",exchangestr,exchangeid,(long long)exchange->nxt64bits); //if ( exchangestr[0] == 0 ) // getchar(); break; } if ( strcmp(exchangestr,exchange->name) == 0 ) break; } if ( exchange != 0 && exchangeidp != 0 ) *exchangeidp = exchange->exchangeid; return(exchange); } int32_t baserel_polarity(char *pairs[][2],int32_t n,char *_base,char *_rel) { int32_t i; char base[16],rel[16]; strcpy(base,_base), tolowercase(base); strcpy(rel,_rel), tolowercase(rel); for (i=0; i (%s)\n",url,jsonstr); if ( (json= cJSON_Parse(jsonstr)) != 0 ) { hbla = prices777_json_orderbook(exchangestr,prices,maxdepth,json,field,"bids","asks",price,volume); free_json(json); } free(jsonstr); } return(hbla); } int32_t InstantDEX_supports(char *base,char *rel) { return(1); } int32_t NXT_supports(char *base,char *rel) { if ( strcmp(rel,"NXT") == 0 ) return(1); else if ( strcmp(base,"NXT") == 0 ) return(-1); else return(0); } #ifdef notnow char *bittrex_parsebalance(struct exchange_info *exchange,double *balancep,char *coinstr) { int32_t i,n; char *str,*itemstr = 0; cJSON *item,*array,*obj; double total,pending; *balancep = 0.; if ( exchange->balancejson != 0 && (array= jarray(&n,exchange->balancejson,"result")) != 0 ) { for (i=0; i 5 || strlen(rel) > 5 || strcmp(rel,"CNY") == 0 || strcmp(base,"CNY") == 0 || strcmp(rel,"USD") == 0 || strcmp(base,"USD") == 0 ) return(0); if ( strcmp(rel,"BTC") == 0 ) return(1); else if ( strcmp(base,"BTC") == 0 ) return(-1); else return(0); } double prices777_bittrex(struct prices777 *prices,int32_t maxdepth) // "BTC-BTCD" { cJSON *json,*obj; char *jsonstr,market[128]; double hbla = 0.; if ( prices->url[0] == 0 ) { sprintf(market,"%s-%s",prices->rel,prices->base); sprintf(prices->url,"https://bittrex.com/api/v1.1/public/getorderbook?market=%s&type=both&depth=%d",market,maxdepth); } jsonstr = issue_curl(prices->url); if ( jsonstr != 0 ) { if ( (json = cJSON_Parse(jsonstr)) != 0 ) { if ( (obj= cJSON_GetObjectItem(json,"success")) != 0 && is_cJSON_True(obj) != 0 ) hbla = prices777_json_orderbook("bittrex",prices,maxdepth,json,"result","buy","sell","Rate","Quantity"); free_json(json); } free(jsonstr); } return(hbla); } /*int32_t bter_supports(char *base,char *rel) { return(0); if ( strcmp(rel,"BTC") == 0 || strcmp(rel,"CNY") == 0 ) return(1); else if ( strcmp(base,"BTC") == 0 || strcmp(base,"CNY") == 0 ) return(-1); else return(0); char *bterassets[][8] = { { "UNITY", "12071612744977229797" }, { "ATOMIC", "11694807213441909013" }, { "DICE", "18184274154437352348" }, { "MRKT", "134138275353332190" }, { "MGW", "10524562908394749924" } }; uint64_t unityid = calc_nxt64bits("12071612744977229797"); n = add_exchange_assetids(assetids,n,BTC_ASSETID,baseid,relid,exchangeid,bterassets,(int32_t)(sizeof(bterassets)/sizeof(*bterassets))); if ( baseid == unityid || relid == unityid ) { n = add_exchange_assetid(assetids,n,unityid,BTC_ASSETID,exchangeid); n = add_exchange_assetid(assetids,n,unityid,NXT_ASSETID,exchangeid); n = add_exchange_assetid(assetids,n,unityid,CNY_ASSETID,exchangeid); } return(n); } double prices777_bter(struct prices777 *prices,int32_t maxdepth) { cJSON *json,*obj; char resultstr[MAX_JSON_FIELD],*jsonstr; double hbla = 0.; if ( prices->url[0] == 0 ) sprintf(prices->url,"http://data.bter.com/api/1/depth/%s_%s",prices->base,prices->rel); jsonstr = issue_curl(prices->url); //printf("(%s) -> (%s)\n",ep->url,jsonstr); //{"result":"true","asks":[["0.00008035",100],["0.00008030",2030],["0.00008024",100],["0.00008018",643.41783554],["0.00008012",100] if ( jsonstr != 0 ) { //printf("BTER.(%s)\n",jsonstr); if ( (json = cJSON_Parse(jsonstr)) != 0 ) { if ( (obj= cJSON_GetObjectItem(json,"result")) != 0 ) { copy_cJSON(resultstr,obj); if ( strcmp(resultstr,"true") == 0 ) { maxdepth = MAX_DEPTH;//1000; // since bter ask is wrong order, need to scan entire list hbla = prices777_json_orderbook("bter",prices,maxdepth,json,0,"bids","asks",0,0); } } free_json(json); } free(jsonstr); } return(hbla); }*/ char *poloniex_parsebalance(struct exchange_info *exchange,double *balancep,char *coinstr) { char *itemstr = 0; cJSON *item,*obj; double onorders,btcvalue; *balancep = 0.; if ( exchange->balancejson != 0 && (item= jobj(exchange->balancejson,coinstr)) != 0 ) { itemstr = jprint(item,0); *balancep = jdouble(item,"available"); onorders = jdouble(item,"onOrders"); btcvalue = jdouble(item,"btcValue"); if ( (obj= cJSON_Parse(itemstr)) != 0 ) { free(itemstr); jaddstr(obj,"base",coinstr); jaddnum(obj,"balance",*balancep); jaddnum(obj,"onOrders",onorders); jaddnum(obj,"btcvalue",btcvalue); itemstr = jprint(obj,1); } } if ( itemstr == 0 ) return(clonestr("{\"error\":\"cant find coin balance\"}")); return(itemstr); } int32_t poloniex_supports(char *base,char *rel) { if ( strlen(base) > 5 || strlen(rel) > 5 || strcmp(rel,"CNY") == 0 || strcmp(base,"CNY") == 0 || strcmp(rel,"USD") == 0 || strcmp(base,"USD") == 0 ) return(0); if ( strcmp(rel,"BTC") == 0 ) return(1); else if ( strcmp(base,"BTC") == 0 ) return(-1); else return(0); //char *poloassets[][8] = { { "UNITY", "12071612744977229797" }, { "JLH", "6932037131189568014" }, { "XUSD", "12982485703607823902" }, { "LQD", "4630752101777892988" }, { "NXTI", "14273984620270850703" }, { "CNMT", "7474435909229872610", "6220108297598959542" } }; //return(add_exchange_assetids(assetids,n,BTC_ASSETID,baseid,relid,exchangeid,poloassets,(int32_t)(sizeof(poloassets)/sizeof(*poloassets)))); } double prices777_poloniex(struct prices777 *prices,int32_t maxdepth) { char market[128]; if ( prices->url[0] == 0 ) { sprintf(market,"%s_%s",prices->rel,prices->base); sprintf(prices->url,"https://poloniex.com/public?command=returnOrderBook¤cyPair=%s&depth=%d",market,maxdepth); } return(prices777_standard("poloniex",prices->url,prices,0,0,maxdepth,0)); } int32_t kraken_supports(char *_base,char *_rel) { char *supports[] = { "BTC", "ETH", "LTC", "NMC", "STR", "DOGE", "XVN", "XRP", "USD", "CAD", "JPY", "GBP", "KRW" }; int32_t i,j; char base[64],rel[64]; strcpy(base,_base), strcpy(rel,_rel); touppercase(base), touppercase(rel); if ( strlen(base) > 5 || strlen(rel) > 5 ) return(0); for (i=0; ibase), strcpy(rel,prices->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(field,"X%sZ%s",base,rel); if ( prices->url[0] == 0 ) { sprintf(market,"%s%s",base,rel); sprintf(prices->url,"https://api.kraken.com/0/public/Depth?pair=%s&count=%d",market,maxdepth); } if ( (jsonstr= issue_curl(prices->url)) != 0 ) { //{"error":[],"result":{"XXBTZUSD":{"asks":[["230.31677","1.438",1440886427],["230.31678","7.229",1440886068],["230.77732","0.012",1440876801],["230.77833","9.642",1440885707],["231.24081","9.719",1440884428]],"bids":[["228.04086","3.052",1440886443],["228.04085","0.590",1440886446],["228.04076","9.550",1440886434],["227.58559","10.214",1440800610],["227.56018","5.000",1440881811]]}}} if ( (json= cJSON_Parse(jsonstr)) != 0 ) { //printf("got.(%s)\n",jsonstr); hbla = prices777_json_orderbook("kraken",prices,maxdepth,jobj(json,"result"),field,"bids","asks",0,0); free_json(json); } free(jsonstr); } return(hbla); } char *bitfinex_parsebalance(struct exchange_info *exchange,double *balancep,char *coinstr) { //[[{"type":"deposit","currency":"btc","amount":"0.0","available":"0.0"},{"type":"deposit","currency":"usd","amount":"0.0","available":"0.0"},{"type":"exchange","currency":"btc","amount":"0.01065851","available":"0.01065851"},{"type":"exchange","currency":"usd","amount":"23386.37278962","available":"0.00378962"},{"type":"trading","currency":"btc","amount":"0.0","available":"0.0"},{"type":"trading","currency":"usd","amount":"0.0","available":"0.0"}]] int32_t i,n,ind; char field[64],*str,*typestr,*itemstr = 0; cJSON *item,*obj,*array; double amounts[3],avail[3],val0,val1; *balancep = 0.; strcpy(field,coinstr), tolowercase(field); memset(amounts,0,sizeof(amounts)); memset(avail,0,sizeof(avail)); if ( exchange->balancejson != 0 && is_cJSON_Array(exchange->balancejson) != 0 && (n= cJSON_GetArraySize(exchange->balancejson)) > 0 ) { for (i=0; ibalancejson,i)) != 0 ) { if ( (str= jstr(item,"currency")) != 0 && strcmp(field,str) == 0 ) { val0 = jdouble(item,"amount"); val1 = jdouble(item,"available"); if ( (typestr= jstr(item,"type")) != 0 ) { if ( strcmp(typestr,"deposit") == 0 ) ind = 0; else if ( strcmp(typestr,"exchange") == 0 ) ind = 1; else if ( strcmp(typestr,"trading") == 0 ) ind = 2; else ind = -1; if ( ind >= 0 ) { amounts[ind] = val0; avail[ind] = val1; } } } } } if ( (obj= cJSON_CreateObject()) != 0 ) { touppercase(field); *balancep = avail[0] + avail[1] + avail[2]; jaddstr(obj,"base",field); jaddnum(obj,"balance",*balancep); jaddnum(obj,"total",amounts[0]+amounts[1]+amounts[2]); array = cJSON_CreateArray(), jaddinum(array,avail[0]), jaddinum(array,amounts[0]), jadd(obj,"deposit",array); array = cJSON_CreateArray(), jaddinum(array,avail[1]), jaddinum(array,amounts[1]), jadd(obj,"exchange",array); array = cJSON_CreateArray(), jaddinum(array,avail[2]), jaddinum(array,amounts[2]), jadd(obj,"trading",array); itemstr = jprint(obj,1); } } if ( itemstr == 0 ) return(clonestr("{\"error\":\"cant find coin balance\"}")); return(itemstr); } int32_t bitfinex_supports(char *base,char *rel) { char *baserels[][2] = { {"btc","usd"}, {"ltc","usd"}, {"ltc","btc"} }; return(baserel_polarity(baserels,(int32_t)(sizeof(baserels)/sizeof(*baserels)),base,rel)); } double prices777_bitfinex(struct prices777 *prices,int32_t maxdepth) { if ( prices->url[0] == 0 ) sprintf(prices->url,"https://api.bitfinex.com/v1/book/%s%s",prices->base,prices->rel); return(prices777_standard("bitfinex",prices->url,prices,"price","amount",maxdepth,0)); } char *btce_parsebalance(struct exchange_info *exchange,double *balancep,char *coinstr) { //btce.({"success":1,"return":{"funds":{"usd":73.02571846,"btc":0,"ltc":0,"nmc":0,"rur":0,"eur":0,"nvc":0.0000322,"trc":0,"ppc":0.00000002,"ftc":0,"xpm":2.28605349,"cnh":0,"gbp":0},"rights":{"info":1,"trade":1,"withdraw":0},"transaction_count":0,"open_orders":3,"server_time":1441918649}}) char field[128],*itemstr = 0; cJSON *obj,*item; *balancep = 0.; strcpy(field,coinstr); tolowercase(field); if ( exchange->balancejson != 0 && (obj= jobj(exchange->balancejson,"return")) != 0 && (item= jobj(obj,"funds")) != 0 ) { *balancep = jdouble(item,field); obj = cJSON_CreateObject(); touppercase(field); jaddstr(obj,"base",field); jaddnum(obj,"balance",*balancep); itemstr = jprint(obj,1); } if ( itemstr == 0 ) return(clonestr("{\"error\":\"cant find coin balance\"}")); return(itemstr); } int32_t btce_supports(char *base,char *rel) { char *baserels[][2] = { {"btc","usd"}, {"btc","rur"}, {"btc","eur"}, {"ltc","btc"}, {"ltc","usd"}, {"ltc","rur"}, {"ltc","eur"}, {"nmc","btc"}, {"nmc","usd"}, {"nvc","btc"}, {"nvc","usd"}, {"eur","usd"}, {"eur","rur"}, {"ppc","btc"}, {"ppc","usd"} }; return(baserel_polarity(baserels,(int32_t)(sizeof(baserels)/sizeof(*baserels)),base,rel)); } double prices777_btce(struct prices777 *prices,int32_t maxdepth) { char field[64]; sprintf(field,"%s_%s",prices->lbase,prices->lrel); if ( prices->url[0] == 0 ) sprintf(prices->url,"https://btc-e.com/api/3/depth/%s",field); return(prices777_standard("btce",prices->url,prices,0,0,maxdepth,field)); } char *bitstamp_parsebalance(struct exchange_info *exchange,double *balancep,char *coinstr) { char field[128],*itemstr = 0; cJSON *obj,*item; *balancep = 0.; strcpy(field,coinstr); tolowercase(field); if ( exchange->balancejson != 0 && (obj= jobj(exchange->balancejson,"return")) != 0 && (item= jobj(obj,"funds")) != 0 ) { *balancep = jdouble(item,field); obj = cJSON_CreateObject(); touppercase(field); jaddstr(obj,"base",field); jaddnum(obj,"balance",*balancep); itemstr = jprint(obj,1); } if ( itemstr == 0 ) return(clonestr("{\"error\":\"cant find coin balance\"}")); return(itemstr); } int32_t bitstamp_supports(char *base,char *rel) { if ( strcmp(base,"BTC") == 0 && strcmp(rel,"USD") == 0 ) return(1); else if ( strcmp(rel,"BTC") == 0 && strcmp(base,"USD") == 0 ) return(-1); else return(0); } double prices777_bitstamp(struct prices777 *prices,int32_t maxdepth) { if ( prices->url[0] == 0 ) sprintf(prices->url,"https://www.bitstamp.net/api/order_book/"); return(prices777_standard("bitstamp",prices->url,prices,0,0,maxdepth,0)); } char *okcoin_parsebalance(struct exchange_info *exchange,double *balancep,char *coinstr) { //okcoin.({"info":{"funds":{"asset":{"net":"0","total":"0"},"free":{"btc":"0","ltc":"0","usd":"0"},"freezed":{"btc":"0","ltc":"0","usd":"0"}}},"result":true}) char field[128],*itemstr = 0; cJSON *obj,*item,*avail,*locked; double lockval = 0; *balancep = 0.; strcpy(field,coinstr); tolowercase(field); if ( exchange->balancejson != 0 && (obj= jobj(exchange->balancejson,"info")) != 0 && (item= jobj(obj,"funds")) != 0 ) { if ( (avail= jobj(item,"free")) != 0 ) *balancep = jdouble(avail,field); if ( (locked= jobj(item,"freezed")) != 0 ) lockval = jdouble(locked,field); obj = cJSON_CreateObject(); touppercase(field); jaddstr(obj,"base",field); jaddnum(obj,"balance",*balancep); jaddnum(obj,"locked",lockval); itemstr = jprint(obj,1); } if ( itemstr == 0 ) return(clonestr("{\"error\":\"cant find coin balance\"}")); return(itemstr); } int32_t okcoin_supports(char *base,char *rel) { char *baserels[][2] = { {"btc","usd"}, {"ltc","usd"} }; return(baserel_polarity(baserels,(int32_t)(sizeof(baserels)/sizeof(*baserels)),base,rel)); } double prices777_okcoin(struct prices777 *prices,int32_t maxdepth) { if ( prices->url[0] == 0 ) sprintf(prices->url,"https://www.okcoin.com/api/v1/depth.do?symbol=%s_%s",prices->lbase,prices->lrel); if ( strcmp(prices->rel,"USD") != 0 && strcmp(prices->rel,"BTC") != 0 ) { fprintf(stderr,">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> FATAL ERROR OKCOIN.(%s) only supports USD\n",prices->url); printf(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> FATAL ERROR OKCOIN.(%s) only supports USD\n",prices->url); exit(-1); return(0); } return(prices777_standard("okcoin",prices->url,prices,0,0,maxdepth,0)); } char *huobi_parsebalance(struct exchange_info *exchange,double *balancep,char *coinstr) { char field[128],*itemstr = 0; cJSON *obj,*item; *balancep = 0.; strcpy(field,coinstr); tolowercase(field); if ( exchange->balancejson != 0 && (obj= jobj(exchange->balancejson,"return")) != 0 && (item= jobj(obj,"funds")) != 0 ) { *balancep = jdouble(item,field); obj = cJSON_CreateObject(); touppercase(field); jaddstr(obj,"base",field); jaddnum(obj,"balance",*balancep); itemstr = jprint(obj,1); } if ( itemstr == 0 ) return(clonestr("{\"error\":\"cant find coin balance\"}")); return(itemstr); } int32_t huobi_supports(char *base,char *rel) { char *baserels[][2] = { {"btc","cny"}, {"ltc","cny"} }; return(baserel_polarity(baserels,(int32_t)(sizeof(baserels)/sizeof(*baserels)),base,rel)); } double prices777_huobi(struct prices777 *prices,int32_t maxdepth) { if ( prices->url[0] == 0 ) sprintf(prices->url,"http://api.huobi.com/staticmarket/depth_%s_json.js ",prices->lbase); return(prices777_standard("huobi",prices->url,prices,0,0,maxdepth,0)); } int32_t bityes_supports(char *base,char *rel) { char *baserels[][2] = { {"btc","usd"}, {"ltc","usd"} }; return(baserel_polarity(baserels,(int32_t)(sizeof(baserels)/sizeof(*baserels)),base,rel)); } double prices777_bityes(struct prices777 *prices,int32_t maxdepth) { //if ( prices->url[0] == 0 ) sprintf(prices->url,"https://market.bityes.com/%s_%s/depth.js?time=%ld",prices->lrel,prices->lbase,(long)time(NULL)); return(prices777_standard("bityes",prices->url,prices,0,0,maxdepth,0)); } char *coinbase_parsebalance(struct exchange_info *exchange,double *balancep,char *coinstr) { char field[128],*itemstr = 0; cJSON *obj,*item; *balancep = 0.; strcpy(field,coinstr); tolowercase(field); if ( exchange->balancejson != 0 && (obj= jobj(exchange->balancejson,"return")) != 0 && (item= jobj(obj,"funds")) != 0 ) { *balancep = jdouble(item,field); obj = cJSON_CreateObject(); touppercase(field); jaddstr(obj,"base",field); jaddnum(obj,"balance",*balancep); itemstr = jprint(obj,1); } if ( itemstr == 0 ) return(clonestr("{\"error\":\"cant find coin balance\"}")); return(itemstr); } int32_t coinbase_supports(char *base,char *rel) { if ( strcmp(base,"BTC") == 0 && strcmp(rel,"USD") == 0 ) return(1); else if ( strcmp(rel,"BTC") == 0 && strcmp(base,"USD") == 0 ) return(-1); else return(0); } double prices777_coinbase(struct prices777 *prices,int32_t maxdepth) { if ( prices->url[0] == 0 ) sprintf(prices->url,"https://api.exchange.coinbase.com/products/%s-%s/book?level=2",prices->base,prices->rel); return(prices777_standard("coinbase",prices->url,prices,0,0,maxdepth,0)); } char *lakebtc_parsebalance(struct exchange_info *exchange,double *balancep,char *coinstr) { char field[128],*str,*itemstr = 0; cJSON *obj=0,*item=0,*prof=0; double locked = 0; *balancep = 0.; strcpy(field,coinstr); touppercase(field); if ( exchange->balancejson != 0 && (obj= jobj(exchange->balancejson,"balance")) != 0 && (item= jobj(exchange->balancejson,"locked")) != 0 && (prof= jobj(exchange->balancejson,"profile")) != 0 ) { *balancep = jdouble(obj,field); locked = jdouble(item,field); obj = cJSON_CreateObject(); jaddstr(obj,"base",field); jaddnum(obj,"balance",*balancep); jaddnum(obj,"locked",locked); if ( (str= jstr(prof,"btc_deposit_addres")) != 0 ) jaddstr(obj,"deposit_address",str); itemstr = jprint(obj,1); } if ( itemstr == 0 ) return(clonestr("{\"error\":\"cant find coin balance\"}")); return(itemstr); } int32_t lakebtc_supports(char *base,char *rel) { char *baserels[][2] = { {"btc","usd"}, {"btc","cny"} }; return(baserel_polarity(baserels,(int32_t)(sizeof(baserels)/sizeof(*baserels)),base,rel)); } double prices777_lakebtc(struct prices777 *prices,int32_t maxdepth) { if ( prices->url[0] == 0 ) { if ( strcmp(prices->rel,"USD") == 0 ) sprintf(prices->url,"https://www.LakeBTC.com/api_v1/bcorderbook"); else if ( strcmp(prices->rel,"CNY") == 0 ) sprintf(prices->url,"https://www.LakeBTC.com/api_v1/bcorderbook_cny"); else printf("illegal lakebtc pair.(%s/%s)\n",prices->base,prices->rel); } return(prices777_standard("lakebtc",prices->url,prices,0,0,maxdepth,0)); } #ifdef exmo_supported int32_t exmo_supports(char *base,char *rel) { if ( strcmp(base,"BTC") == 0 && (strcmp(rel,"USD") == 0 || strcmp(rel,"EUR") == 0 || strcmp(rel,"RUR") == 0) ) return(1); else if ( strcmp(rel,"BTC") == 0 && (strcmp(base,"USD") == 0 || strcmp(base,"EUR") == 0 || strcmp(base,"RUR") == 0) ) return(-1); else return(0); } double prices777_exmo(struct prices777 *prices,int32_t maxdepth) { if ( prices->url[0] == 0 ) sprintf(prices->url,"https://api.exmo.com/api_v2/orders_book?pair=%s_%s",prices->base,prices->rel); return(prices777_standard("exmo",prices->url,prices,0,0,maxdepth,0)); } #endif // "gatecoin", "quoine", "jubi", "hitbtc" char *btc38_parsebalance(struct exchange_info *exchange,double *balancep,char *coinstr) { char field[128],*str,*itemstr = 0; cJSON *obj; double lockbalance,imma; *balancep = 0.; strcpy(field,coinstr); tolowercase(field); strcat(field,"_balance"); if ( exchange->balancejson != 0 && (str= jstr(exchange->balancejson,field)) != 0 ) { *balancep = jdouble(exchange->balancejson,field); strcpy(field,coinstr), tolowercase(field), strcat(field,"_balance_lock"); lockbalance = jdouble(exchange->balancejson,field); strcpy(field,coinstr), tolowercase(field), strcat(field,"_balance_imma"); imma = jdouble(exchange->balancejson,field); obj = cJSON_CreateObject(); jaddnum(obj,"balance",*balancep); jaddnum(obj,"locked_balance",lockbalance); jaddnum(obj,"imma_balance",imma); itemstr = jprint(obj,1); } if ( itemstr == 0 ) return(clonestr("{\"error\":\"cant find coin balance\"}")); return(itemstr); } int32_t btc38_supports(char *_base,char *_rel) { char *cnypairs[] = { "BTC", "LTC", "DOGE", "XRP", "BTS", "STR", "NXT", "BLK", "YBC", "BILS", "BOST", "PPC", "APC", "ZCC", "XPM", "DGC", "MEC", "WDC", "QRK", "BEC", "ANC", "UNC", "RIC", "SRC", "TAG" }; char *btcpairs[] = { "TMC", "LTC", "DOGE", "XRP", "BTS", "STR", "NXT", "BLK", "XEM", "VPN", "BILS", "BOST", "WDC", "ANC", "XCN", "VOOT", "SYS", "NRS", "NAS", "SYNC", "MED", "EAC" }; int32_t i; char base[64],rel[64]; strcpy(base,_base), strcpy(rel,_rel); touppercase(base), touppercase(rel); if ( strlen(base) > 5 || strlen(rel) > 5 ) return(0); if ( strcmp(base,"BTC") == 0 && strcmp(rel,"CNY") == 0 ) return(1); else if ( strcmp(base,"CNY") == 0 && strcmp(rel,"BTC") == 0 ) return(-1); else if ( strcmp(base,"BTC") == 0 ) { for (i=0; iurl[0] == 0 ) { if ( strcmp(prices->lbase,"cny") == 0 && strcmp(prices->lrel,"btc") == 0 ) sprintf(prices->url,"http://api.btc38.com/v1/depth.php?c=%s&mk_type=%s","btc","cny"); else sprintf(prices->url,"http://api.btc38.com/v1/depth.php?c=%s&mk_type=%s",prices->lbase,prices->lrel); } return(prices777_standard("btc38",prices->url,prices,0,0,maxdepth,0)); } char *quadriga_parsebalance(struct exchange_info *exchange,double *balancep,char *coinstr) { //[{"btc_available":"0.00000000","btc_reserved":"0.00000000","btc_balance":"0.00000000","cad_available":"0.00","cad_reserved":"0.00","cad_balance":"0.00","usd_available":"0.00","usd_reserved":"0.00","usd_balance":"0.00","xau_available":"0.000000","xau_reserved":"0.000000","xau_balance":"0.000000","fee":"0.5000"}] char field[128],*str,*itemstr = 0; cJSON *obj; double reserv,total; *balancep = 0.; strcpy(field,coinstr); tolowercase(field); strcat(field,"_available"); if ( exchange->balancejson != 0 && (str= jstr(exchange->balancejson,field)) != 0 ) { *balancep = jdouble(exchange->balancejson,field); strcpy(field,coinstr), tolowercase(field), strcat(field,"_reserved"); reserv = jdouble(exchange->balancejson,field); strcpy(field,coinstr), tolowercase(field), strcat(field,"_balance"); total = jdouble(exchange->balancejson,field); obj = cJSON_CreateObject(); jaddnum(obj,"balance",*balancep); jaddnum(obj,"locked_balance",reserv); jaddnum(obj,"total",total); itemstr = jprint(obj,1); } if ( itemstr == 0 ) return(clonestr("{\"error\":\"cant find coin balance\"}")); return(itemstr); } int32_t quadriga_supports(char *base,char *rel) { char *baserels[][2] = { {"btc","usd"}, {"btc","cad"} }; return(baserel_polarity(baserels,(int32_t)(sizeof(baserels)/sizeof(*baserels)),base,rel)); } double prices777_quadriga(struct prices777 *prices,int32_t maxdepth) { if ( prices->url[0] == 0 ) sprintf(prices->url,"https://api.quadrigacx.com/v2/order_book?book=%s_%s",prices->lbase,prices->lrel); return(prices777_standard("quadriga",prices->url,prices,0,0,maxdepth,0)); } /*void prices777_kraken(struct prices777 *prices,int32_t maxdepth) { if ( prices->url[0] == 0 ) sprintf(prices->url,"https://api.kraken.com/0/public/Depth"); // need POST prices777_standard("kraken",prices->url,prices,0,0,maxdepth); }*/ /*void prices777_itbit(struct prices777 *prices,int32_t maxdepth) { if ( prices->url[0] == 0 ) sprintf(prices->url,"https://www.itbit.com/%s%s",prices->base,prices->rel); prices777_standard("itbit",prices->url,prices,0,0,maxdepth); }*/ #endif uint64_t prices777_truefx(uint64_t *millistamps,double *bids,double *asks,double *opens,double *highs,double *lows,char *username,char *password,uint64_t idnum) { char *truefxfmt = "http://webrates.truefx.com/rates/connect.html?f=csv&id=jl777:truefxtest:poll:1437671654417&c=EUR/USD,USD/JPY,GBP/USD,EUR/GBP,USD/CHF,AUD/NZD,CAD/CHF,CHF/JPY,EUR/AUD,EUR/CAD,EUR/JPY,EUR/CHF,USD/CAD,AUD/USD,GBP/JPY,AUD/CAD,AUD/CHF,AUD/JPY,EUR/NOK,EUR/NZD,GBP/CAD,GBP/CHF,NZD/JPY,NZD/USD,USD/NOK,USD/SEK"; // EUR/USD,1437569931314,1.09,034,1.09,038,1.08922,1.09673,1.09384 USD/JPY,1437569932078,123.,778,123.,781,123.569,123.903,123.860 GBP/USD,1437569929008,1.56,332,1.56,337,1.55458,1.56482,1.55538 EUR/GBP,1437569931291,0.69,742,0.69,750,0.69710,0.70383,0.70338 USD/CHF,1437569932237,0.96,142,0.96,153,0.95608,0.96234,0.95748 EUR/JPY,1437569932237,134.,960,134.,972,134.842,135.640,135.476 EUR/CHF,1437569930233,1.04,827,1.04,839,1.04698,1.04945,1.04843 USD/CAD,1437569929721,1.30,231,1.30,241,1.29367,1.30340,1.29466 AUD/USD,1437569931700,0.73,884,0.73,890,0.73721,0.74395,0.74200 GBP/JPY,1437569931924,193.,500,193.,520,192.298,193.670,192.649 char url[1024],userpass[1024],buf[128],base[64],rel[64],*str; cJSON *array; int32_t jpyflag,i,c,n = 0; double pre,pre2,bid,ask,open,high,low; long millistamp; //printf("truefx.(%s)(%s).%llu\n",username,password,(long long)idnum); url[0] = 0; if ( username[0] != 0 && password[0] != 0 ) { if ( idnum == 0 ) { sprintf(userpass,"http://webrates.truefx.com/rates/connect.html?f=csv&s=y&u=%s&p=%s&q=poll",username,password); if ( (str= issue_curl(userpass)) != 0 ) { _stripwhite(str,0); printf("(%s) -> (%s)\n",userpass,str); sprintf(userpass,"%s:%s:poll:",username,password); idnum = calc_nxt64bits(str + strlen(userpass)); free(str); printf("idnum.%llu\n",(long long)idnum); } } if ( idnum != 0 ) sprintf(url,truefxfmt,username,password,(long long)idnum); } if ( url[0] == 0 ) sprintf(url,"http://webrates.truefx.com/rates/connect.html?f=csv&s=y"); if ( (str= issue_curl(url)) != 0 ) { //printf("(%s) -> (%s)\n",url,str); while ( str[n + 0] != 0 && str[n] != '\n' && str[n] != '\r' ) { for (i=jpyflag=0; str[n + i]!=' '&&str[n + i]!='\n'&&str[n + i]!='\r'&&str[n + i]!=0; i++) { if ( i > 0 && str[n+i] == ',' && str[n+i-1] == '.' ) str[n+i-1] = ' ', jpyflag = 1; else if ( i > 0 && str[n+i-1] == ',' && str[n+i] == '0' && str[n+i+1+2] == ',' ) { str[n+i] = ' '; if ( str[n+i+1] == '0' ) str[n+i+1] = ' ', i++; } } memcpy(base,str+n,3), base[3] = 0; memcpy(rel,str+n+4,3), rel[3] = 0; str[n + i] = 0; //printf("str.(%s) (%s/%s) %d n.%d i.%d\n",str+n,base,rel,str[n],n,i); sprintf(buf,"[%s]",str+n+7+1); n += i + 1; if ( (array= cJSON_Parse(buf)) != 0 ) { if ( is_cJSON_Array(array) != 0 ) { millistamp = (uint64_t)get_API_float(jitem(array,0)); pre = get_API_float(jitem(array,1)); bid = get_API_float(jitem(array,2)); pre2 = get_API_float(jitem(array,3)); ask = get_API_float(jitem(array,4)); open = get_API_float(jitem(array,5)); high = get_API_float(jitem(array,6)); low = get_API_float(jitem(array,7)); if ( jpyflag != 0 ) bid = pre + (bid / 1000.), ask = pre2 + (ask / 1000.); else bid = pre + (bid / 100000.), ask = pre2 + (ask / 100000.); if ( (c= prices777_contractnum(base,rel)) >= 0 ) { char name[64]; strcpy(name,base), strcat(name,rel); if ( BUNDLE.truefx[c] == 0 ) BUNDLE.truefx[c] = prices777_initpair(0,"truefx",base,rel,0,name,stringbits(base),stringbits(rel),0); millistamps[c] = millistamp,opens[c] = open, highs[c] = high, lows[c] = low, bids[c] = bid, asks[c] = ask; if ( Debuglevel > 2 ) { if ( jpyflag != 0 ) printf("%s%s.%-2d %llu: %.3f %.3f %.3f | %.3f %.3f\n",base,rel,c,(long long)millistamp,open,high,low,bid,ask); else printf("%s%s.%-2d %llu: %.5f %.5f %.5f | %.5f %.5f\n",base,rel,c,(long long)millistamp,open,high,low,bid,ask); } } else printf("unknown basepair.(%s) (%s)\n",base,rel); } free_json(array); } else printf("cant parse.(%s)\n",buf); } free(str); } return(idnum); } double prices777_fxcm(double lhlogmatrix[8][8],double logmatrix[8][8],double bids[64],double asks[64],double highs[64],double lows[64]) { char name[64],*xmlstr,*str; cJSON *json,*obj; int32_t i,j,c,flag,k,n = 0; double bid,ask,high,low; struct destbuf numstr; memset(bids,0,sizeof(*bids) * NUM_CONTRACTS), memset(asks,0,sizeof(*asks) * NUM_CONTRACTS); if ( (xmlstr= issue_curl("http://rates.fxcm.com/RatesXML")) != 0 ) { _stripwhite(xmlstr,0); //printf("(%s)\n",xmlstr); i = 0; if ( strncmp("'&&xmlstr[i]!=0; i++) ; if ( xmlstr[i] == '>' ) i++; for (j=0; xmlstr[i]!=0; i++) { if ( strncmp("",&xmlstr[i],strlen("")) == 0 ) xmlstr[j++] = '[', i += strlen("")-1; else if ( strncmp(" 1 ) xmlstr[j++] = ','; memcpy(&xmlstr[j],"{\"Symbol\":",strlen("{\"Symbol\":")), i += strlen("", "\"Bid\":" }, { "", "\"Ask\":" }, { "", "\"High\":" }, { "", "\"Low\":" }, { "", "\"Direction\":" }, { "", "\"Last\":\"" } }; for (k=0; k", "", "", "", "", "", "", "", ">" }; for (k=0; k",ends[k]) == 0 ) xmlstr[j++] = '}'; else if ( strcmp("",ends[k]) == 0 ) xmlstr[j++] = ']'; else if ( strcmp("",ends[k]) == 0 ) xmlstr[j++] = '\"'; else xmlstr[j++] = ','; break; } if ( k == sizeof(ends)/sizeof(*ends) ) xmlstr[j++] = xmlstr[i]; } } } xmlstr[j] = 0; if ( (json= cJSON_Parse(xmlstr)) != 0 ) { /* 123.763 123.786 123.956 123.562 -1 08:49:15*/ //printf("Parsed stupid XML! (%s)\n",xmlstr); if ( is_cJSON_Array(json) != 0 && (n= cJSON_GetArraySize(json)) != 0 ) { for (i=0; i= 0 ) { bids[c] = bid, asks[c] = ask, highs[c] = high, lows[c] = low; //printf("c.%d (%s) %f %f\n",c,name,bid,ask); flag = 1; if ( BUNDLE.fxcm[c] == 0 ) { //printf("max.%ld FXCM: not initialized.(%s) %d\n",sizeof(CONTRACTS)/sizeof(*CONTRACTS),name,c); BUNDLE.fxcm[c] = prices777_initpair(0,"fxcm",name,0,0,name,peggy_basebits(name),peggy_relbits(name),0); } } else printf("cant find.%s\n",name);//, getchar(); } if ( flag == 0 ) printf("FXCM: Error finding.(%s) c.%d (%s)\n",name,c,cJSON_Print(obj)); } } free_json(json); } else printf("couldnt parse.(%s)\n",xmlstr); free(xmlstr); } calc_primary_currencies(lhlogmatrix,lows,highs); return(calc_primary_currencies(logmatrix,bids,asks)); } double prices777_instaforex(double logmatrix[8][8],uint32_t timestamps[NUM_COMBINED+1],double bids[128],double asks[128]) { //{"NZDUSD":{"symbol":"NZDUSD","lasttime":1437580206,"digits":4,"change":"-0.0001","bid":"0.6590","ask":"0.6593"}, char *jsonstr,*str; cJSON *json,*item; int32_t i,c; struct destbuf numstr; memset(timestamps,0,sizeof(*timestamps) * (NUM_COMBINED + 1)), memset(bids,0,sizeof(*bids) * (NUM_COMBINED + 1)), memset(asks,0,sizeof(*asks) * (NUM_COMBINED + 1)); if ( (jsonstr= issue_curl("https://quotes.instaforex.com/get_quotes.php?q=NZDUSD,NZDCHF,NZDCAD,NZDJPY,GBPNZD,EURNZD,AUDNZD,CADJPY,CADCHF,USDCAD,EURCAD,GBPCAD,AUDCAD,USDCHF,CHFJPY,EURCHF,GBPCHF,AUDCHF,EURUSD,EURAUD,EURJPY,EURGBP,GBPUSD,GBPJPY,GBPAUD,USDJPY,AUDJPY,AUDUSD,XAUUSD&m=json")) != 0 ) { // printf("(%s)\n",jsonstr); if ( (json= cJSON_Parse(jsonstr)) != 0 ) { for (i=0; i<=NUM_CONTRACTS; i++) { if ( i < NUM_CONTRACTS ) str = CONTRACTS[i], c = i; else str = "XAUUSD", c = prices777_contractnum(str,0); if ( (item= jobj(json,str)) != 0 ) { timestamps[c] = juint(item,"lasttime"); copy_cJSON(&numstr,jobj(item,"bid")), bids[c] = atof(numstr.buf); copy_cJSON(&numstr,jobj(item,"ask")), asks[c] = atof(numstr.buf); //if ( c < NUM_CONTRACTS && Contract_rel[c] == JPY ) // bids[i] /= 100., asks[i] /= 100.; if ( Debuglevel > 2 ) printf("%s.(%.6f %.6f) ",str,bids[c],asks[c]); if ( BUNDLE.instaforex[c] == 0 ) BUNDLE.instaforex[c] = prices777_initpair(0,"instaforex",str,0,0,str,peggy_basebits(str),peggy_relbits(str),0); } } free_json(json); } free(jsonstr); } return(calc_primary_currencies(logmatrix,bids,asks)); } int32_t prices777_ecbparse(char *date,double *prices,char *url,int32_t basenum) { char *jsonstr,*relstr,*basestr; int32_t count=0,i,relnum; cJSON *json,*ratesobj,*item; struct destbuf tmp; if ( (jsonstr= issue_curl(url)) != 0 ) { if ( Debuglevel > 2 ) printf("(%s)\n",jsonstr); if ( (json= cJSON_Parse(jsonstr)) != 0 ) { copy_cJSON(&tmp,jobj(json,"date")), safecopy(date,tmp.buf,64); if ( (basestr= jstr(json,"base")) != 0 && strcmp(basestr,CURRENCIES[basenum]) == 0 && (ratesobj= jobj(json,"rates")) != 0 && (item= ratesobj->child) != 0 ) { while ( item != 0 ) { if ( (relstr= get_cJSON_fieldname(item)) != 0 && (relnum= prices777_basenum(relstr)) >= 0 ) { i = basenum*MAX_CURRENCIES + relnum; prices[i] = item->valuedouble; //if ( basenum == JPYNUM ) // prices[i] *= 100.; // else if ( relnum == JPYNUM ) // prices[i] /= 100.; count++; if ( Debuglevel > 2 ) printf("(%02d:%02d %f) ",basenum,relnum,prices[i]); } else printf("cant find.(%s)\n",relstr);//, getchar(); item = item->next; } } free_json(json); } free(jsonstr); } return(count); } int32_t prices777_ecb(char *date,double *prices,int32_t year,int32_t month,int32_t day) { // http://api.fixer.io/latest?base=CNH // http://api.fixer.io/2000-01-03?base=USD // "USD", "EUR", "JPY", "GBP", "AUD", "CAD", "CHF", "NZD" char baseurl[512],tmpdate[64],url[512],checkdate[16]; int32_t basenum,count,i,iter,nonz; checkdate[0] = 0; if ( year == 0 ) strcpy(baseurl,"http://api.fixer.io/latest?base="); else { sprintf(checkdate,"%d-%02d-%02d",year,month,day); sprintf(baseurl,"http://api.fixer.io/%s?base=",checkdate); } count = 0; for (iter=0; iter<2; iter++) { for (basenum=0; basenum 2 ) printf("%8.5f ",prices[MAX_CURRENCIES*basenum + i]); } if ( Debuglevel > 2 ) printf("%s.%d %d\n",CURRENCIES[basenum],basenum,nonz); } } } return(count); } #endif