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.
3457 lines
161 KiB
3457 lines
161 KiB
/******************************************************************************
|
|
* 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_orderbooks_h
|
|
#define xcode_orderbooks_h
|
|
|
|
char *peggy_contracts[64] =
|
|
{
|
|
"BTCD", "USD", "EUR", "JPY", "GBP", "AUD", "CAD", "CHF", "NZD", // major currencies
|
|
"CNY", "RUB", "MXN", "BRL", "INR", "HKD", "TRY", "ZAR", "PLN", "NOK", "SEK", "DKK", "CZK", "HUF", "ILS", "KRW", "MYR", "PHP", "RON", "SGD", "THB", "BGN", "IDR", "HRK",
|
|
"BTCUSD", "NXTBTC", "SuperNET", "ETHBTC", "LTCBTC", "XMRBTC", "BTSBTC", "XCPBTC", // BTC priced
|
|
"XAUUSD", "XAGUSD", "XPTUSD", "XPDUSD", "Copper", "NGAS", "UKOil", "USOil", // USD priced
|
|
"Bund", "NAS100", "SPX500", "US30", "EUSTX50", "UK100", "JPN225", "GER30", "SUI30", "AUS200", "HKG33", "XAUUSD", "BTCRUB", "BTCCNY", "BTCUSD" // abstract
|
|
};
|
|
|
|
char *MGWassets[][3] =
|
|
{
|
|
{ "12659653638116877017", "BTC", "8" },
|
|
{ "17554243582654188572", "BTC", "8" }, // assetid, name, decimals
|
|
{ "4551058913252105307", "BTC", "8" },
|
|
{ "6918149200730574743", "BTCD", "4" },
|
|
{ "11060861818140490423", "BTCD", "4" },
|
|
{ "13120372057981370228", "BITS", "6" },
|
|
{ "16344939950195952527", "DOGE", "4" },
|
|
{ "2303962892272487643", "DOGE", "4" },
|
|
{ "6775076774325697454", "OPAL", "8" },
|
|
{ "7734432159113182240", "VPN", "4" },
|
|
{ "9037144112883608562", "VRC", "8" },
|
|
{ "1369181773544917037", "BBR", "8" },
|
|
{ "17353118525598940144", "DRK", "8" },
|
|
{ "2881764795164526882", "LTC", "4" },
|
|
{ "7117580438310874759", "BC", "4" },
|
|
{ "275548135983837356", "VIA", "4" },
|
|
{ "6220108297598959542", "CNMT", "0" },
|
|
{ "7474435909229872610", "CNMT", "0" },
|
|
};
|
|
|
|
char *Tradedassets[][4] =
|
|
{
|
|
{ "6220108297598959542", "CNMT", "0", "poloniex" },
|
|
{ "7474435909229872610", "CNMT", "0", "poloniex" },
|
|
{ "979292558519844732", "MMNXT", "0", "poloniex" },
|
|
{ "12982485703607823902", "XUSD", "0", "poloniex" },
|
|
{ "13634675574519917918", "INDEX", "0", "poloniex" },
|
|
{ "6932037131189568014", "JLH", "0", "poloniex" },
|
|
{ "14273984620270850703", "NXTI", "0", "poloniex" },
|
|
{ "12071612744977229797", "UNITY", "4", "poloniex" },
|
|
};
|
|
|
|
char *is_tradedasset(char *exchange,char *assetidstr)
|
|
{
|
|
int32_t i;
|
|
for (i=0; i<(int32_t)(sizeof(Tradedassets)/sizeof(*Tradedassets)); i++)
|
|
if ( strcmp(Tradedassets[i][0],assetidstr) == 0 )
|
|
{
|
|
strcpy(exchange,Tradedassets[i][3]);
|
|
return(Tradedassets[i][1]);
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
uint64_t is_MGWcoin(char *name)
|
|
{
|
|
int32_t i;
|
|
for (i=0; i<(int32_t)(sizeof(MGWassets)/sizeof(*MGWassets)); i++)
|
|
if ( strcmp(MGWassets[i][1],name) == 0 )
|
|
return(calc_nxt64bits(MGWassets[i][0]));
|
|
return(0);
|
|
}
|
|
|
|
char *is_MGWasset(uint64_t assetid)
|
|
{
|
|
int32_t i; char assetidstr[64];
|
|
expand_nxt64bits(assetidstr,assetid);
|
|
for (i=0; i<(int32_t)(sizeof(MGWassets)/sizeof(*MGWassets)); i++)
|
|
if ( strcmp(MGWassets[i][0],assetidstr) == 0 )
|
|
return(MGWassets[i][1]);
|
|
return(0);
|
|
}
|
|
|
|
uint64_t prices777_equiv(uint64_t assetid)
|
|
{
|
|
char *str;
|
|
if ( (str= is_MGWasset(assetid)) != 0 )
|
|
return(stringbits(str));
|
|
return(assetid);
|
|
}
|
|
|
|
struct prices777 *prices777_find(int32_t *invertedp,uint64_t baseid,uint64_t relid,char *exchange)
|
|
{
|
|
int32_t i; struct prices777 *prices;
|
|
*invertedp = 0;
|
|
for (i=0; i<BUNDLE.num; i++)
|
|
{
|
|
if ( (prices= BUNDLE.ptrs[i]) != 0 && strcmp(prices->exchange,exchange) == 0 )
|
|
{
|
|
//printf("FOUND.(%s)\n",exchange);
|
|
if ( prices777_equiv(prices->baseid) == prices777_equiv(baseid) && prices777_equiv(prices->relid) == prices777_equiv(relid) )
|
|
return(prices);
|
|
else if ( prices777_equiv(prices->relid) == prices777_equiv(baseid) && prices777_equiv(prices->baseid) == prices777_equiv(relid) )
|
|
{
|
|
*invertedp = 1;
|
|
return(prices);
|
|
}
|
|
//else printf("(%llu/%llu) != (%llu/%llu)\n",(long long)baseid,(long long)relid,(long long)prices->baseid,(long long)prices->relid);
|
|
} //else fprintf(stderr,"(%s).%d ",prices->exchange,i);
|
|
}
|
|
//printf("CANTFIND.(%s) %llu/%llu\n",exchange,(long long)baseid,(long long)relid);
|
|
return(0);
|
|
}
|
|
|
|
struct prices777 *prices777_createbasket(int32_t addbasket,char *name,char *base,char *rel,uint64_t baseid,uint64_t relid,struct prices777_basket *basket,int32_t n,char *typestr)
|
|
{
|
|
int32_t i,j,m,iter,max = 0; double firstwt,wtsum; struct prices777 *prices,*feature;
|
|
printf("createbasket.%s n.%d (%s/%s)\n",typestr,n,base,rel);
|
|
prices = prices777_initpair(1,typestr,base,rel,0.,name,baseid,relid,n);
|
|
for (iter=0; iter<2; iter++)
|
|
{
|
|
for (i=0; i<n; i++)
|
|
{
|
|
feature = basket[i].prices;
|
|
if ( addbasket*iter != 0 )
|
|
{
|
|
feature->dependents = realloc(feature->dependents,sizeof(*feature->dependents) * (feature->numdependents + 1));
|
|
feature->dependents[feature->numdependents++] = &prices->changed;
|
|
printf("%p i.%d/%d addlink.%s groupid.%d wt.%f (%s.%llu/%llu -> %s.%llu/%llu).%s\n",feature,i,n,feature->exchange,basket[i].groupid,basket[i].wt,feature->contract,(long long)feature->baseid,(long long)feature->relid,prices->contract,(long long)prices->baseid,(long long)prices->relid,prices->exchange);
|
|
}
|
|
if ( basket[i].groupid > max )
|
|
max = basket[i].groupid;
|
|
if ( fabs(basket[i].wt) < SMALLVAL )
|
|
{
|
|
printf("all basket features.%s i.%d must have nonzero wt\n",feature->contract,i);
|
|
free(prices);
|
|
return(0);
|
|
}
|
|
if ( strcmp(feature->base,feature->rel) == 0 || feature->baseid == feature->relid )
|
|
{
|
|
printf("base rel cant be the same (%s %s) %llu %llu\n",feature->base,feature->rel,(long long)feature->baseid,(long long)feature->relid);
|
|
free(prices);
|
|
return(0);
|
|
}
|
|
}
|
|
if ( (max+1) > MAX_GROUPS )
|
|
{
|
|
printf("baskets limited to %d, %d is too many for %s.(%s/%s)\n",MAX_GROUPS,n,name,base,rel);
|
|
return(0);
|
|
}
|
|
}
|
|
prices->numgroups = (max + 1);
|
|
for (j=0; j<prices->numgroups; j++)
|
|
{
|
|
for (firstwt=i=m=0; i<n; i++)
|
|
{
|
|
//printf("i.%d groupid.%d wt %f m.%d\n",i,basket[i].groupid,basket[i].wt,m);
|
|
if ( basket[i].groupid == j )
|
|
{
|
|
if ( firstwt == 0. )
|
|
prices->groupwts[j] = firstwt = basket[i].wt;
|
|
else if ( basket[i].wt != firstwt )
|
|
{
|
|
printf("warning features of same group.%d different wt: %d %f != %f\n",j,i,firstwt,basket[i].wt);
|
|
// free(prices);
|
|
// return(0);
|
|
}
|
|
m++;
|
|
}
|
|
}
|
|
//printf("m.%d\n",m);
|
|
for (i=0; i<n; i++)
|
|
if ( basket[i].groupid == j )
|
|
basket[i].groupsize = m, printf("basketsize.%d n.%d j.%d groupsize[%d] <- m.%d\n",prices->basketsize,n,j,i,m);
|
|
}
|
|
for (j=0; j<prices->numgroups; j++)
|
|
for (i=0; i<n; i++)
|
|
if ( basket[i].groupid == j )
|
|
prices->basket[prices->basketsize++] = basket[i];
|
|
for (i=-1; i<=1; i+=2)
|
|
{
|
|
for (wtsum=j=m=0; j<prices->numgroups; j++)
|
|
{
|
|
if ( prices->groupwts[j]*i > 0 )
|
|
wtsum += prices->groupwts[j], m++;
|
|
}
|
|
if ( 0 && wtsum != 0. )
|
|
{
|
|
if ( wtsum < 0. )
|
|
wtsum = -wtsum;
|
|
for (j=0; j<prices->numgroups; j++)
|
|
prices->groupwts[j] /= wtsum;
|
|
}
|
|
}
|
|
if ( prices->numgroups == 1 )
|
|
prices->groupwts[0] = 1.;
|
|
for (j=0; j<prices->numgroups; j++)
|
|
printf("%9.6f ",prices->groupwts[j]);
|
|
printf("groupwts %s\n",typestr);
|
|
return(prices);
|
|
}
|
|
|
|
double prices777_price_volume(double *volumep,uint64_t baseamount,uint64_t relamount)
|
|
{
|
|
*volumep = (((double)baseamount + 0.000000009999999) / SATOSHIDEN);
|
|
if ( baseamount > 0. )
|
|
return((double)relamount / (double)baseamount);
|
|
else return(0.);
|
|
}
|
|
|
|
void prices777_best_amounts(uint64_t *baseamountp,uint64_t *relamountp,double price,double volume)
|
|
{
|
|
double checkprice,checkvol,distA,distB,metric,bestmetric = (1. / SMALLVAL);
|
|
uint64_t baseamount,relamount,bestbaseamount = 0,bestrelamount = 0;
|
|
int32_t i,j;
|
|
baseamount = volume * SATOSHIDEN;
|
|
relamount = ((price * volume) * SATOSHIDEN);
|
|
//*baseamountp = baseamount, *relamountp = relamount;
|
|
//return;
|
|
for (i=-1; i<=1; i++)
|
|
for (j=-1; j<=1; j++)
|
|
{
|
|
checkprice = prices777_price_volume(&checkvol,baseamount+i,relamount+j);
|
|
distA = (checkprice - price);
|
|
distA *= distA;
|
|
distB = (checkvol - volume);
|
|
distB *= distB;
|
|
metric = sqrt(distA + distB);
|
|
if ( metric < bestmetric )
|
|
{
|
|
bestmetric = metric;
|
|
bestbaseamount = baseamount + i;
|
|
bestrelamount = relamount + j;
|
|
//printf("i.%d j.%d metric. %f\n",i,j,metric);
|
|
}
|
|
}
|
|
*baseamountp = bestbaseamount;
|
|
*relamountp = bestrelamount;
|
|
}
|
|
|
|
void prices777_additem(cJSON **highbidp,cJSON **lowaskp,cJSON *bids,cJSON *asks,int32_t ind,cJSON *item,int32_t bidask)
|
|
{
|
|
if ( bidask == 0 )
|
|
{
|
|
cJSON_AddItemToArray(bids,item);
|
|
if ( ind == 0 )
|
|
*highbidp = item;
|
|
}
|
|
else
|
|
{
|
|
cJSON_AddItemToArray(asks,item);
|
|
if ( ind == 0 )
|
|
*lowaskp = item;
|
|
}
|
|
}
|
|
|
|
uint64_t calc_qty(uint64_t mult,uint64_t assetid,uint64_t amount)
|
|
{
|
|
if ( assetid != NXT_ASSETID )
|
|
return(amount / mult);
|
|
else return(amount);
|
|
}
|
|
|
|
int32_t verify_NXTtx(cJSON *json,uint64_t refasset,uint64_t qty,uint64_t destNXTbits)
|
|
{
|
|
int32_t typeval,subtypeval,n = 0;
|
|
uint64_t quantity,price,assetidbits;
|
|
cJSON *attachmentobj;
|
|
char sender[MAX_JSON_FIELD],recipient[MAX_JSON_FIELD],deadline[MAX_JSON_FIELD],feeNQT[MAX_JSON_FIELD],amountNQT[MAX_JSON_FIELD],type[MAX_JSON_FIELD],subtype[MAX_JSON_FIELD],verify[MAX_JSON_FIELD],referencedTransaction[MAX_JSON_FIELD],quantityQNT[MAX_JSON_FIELD],priceNQT[MAX_JSON_FIELD],assetidstr[MAX_JSON_FIELD],sighash[MAX_JSON_FIELD],fullhash[MAX_JSON_FIELD],timestamp[MAX_JSON_FIELD],transaction[MAX_JSON_FIELD];
|
|
if ( json == 0 )
|
|
{
|
|
printf("verify_NXTtx cant parse json\n");
|
|
return(-1);
|
|
}
|
|
if ( extract_cJSON_str(sender,sizeof(sender),json,"sender") > 0 ) n++;
|
|
if ( extract_cJSON_str(recipient,sizeof(recipient),json,"recipient") > 0 ) n++;
|
|
if ( extract_cJSON_str(referencedTransaction,sizeof(referencedTransaction),json,"referencedTransactionFullHash") > 0 ) n++;
|
|
if ( extract_cJSON_str(amountNQT,sizeof(amountNQT),json,"amountNQT") > 0 ) n++;
|
|
if ( extract_cJSON_str(feeNQT,sizeof(feeNQT),json,"feeNQT") > 0 ) n++;
|
|
if ( extract_cJSON_str(deadline,sizeof(deadline),json,"deadline") > 0 ) n++;
|
|
if ( extract_cJSON_str(type,sizeof(type),json,"type") > 0 ) n++;
|
|
if ( extract_cJSON_str(subtype,sizeof(subtype),json,"subtype") > 0 ) n++;
|
|
if ( extract_cJSON_str(verify,sizeof(verify),json,"verify") > 0 ) n++;
|
|
if ( extract_cJSON_str(sighash,sizeof(sighash),json,"signatureHash") > 0 ) n++;
|
|
if ( extract_cJSON_str(fullhash,sizeof(fullhash),json,"fullHash") > 0 ) n++;
|
|
if ( extract_cJSON_str(timestamp,sizeof(timestamp),json,"timestamp") > 0 ) n++;
|
|
if ( extract_cJSON_str(transaction,sizeof(transaction),json,"transaction") > 0 ) n++;
|
|
if ( calc_nxt64bits(recipient) != destNXTbits )
|
|
{
|
|
if ( Debuglevel > 2 )
|
|
fprintf(stderr,"recipient.%s != %llu\n",recipient,(long long)destNXTbits);
|
|
return(-2);
|
|
}
|
|
typeval = myatoi(type,256), subtypeval = myatoi(subtype,256);
|
|
if ( refasset == NXT_ASSETID )
|
|
{
|
|
if ( typeval != 0 || subtypeval != 0 )
|
|
{
|
|
fprintf(stderr,"unexpected typeval.%d subtypeval.%d\n",typeval,subtypeval);
|
|
return(-3);
|
|
}
|
|
if ( qty != calc_nxt64bits(amountNQT) )
|
|
{
|
|
fprintf(stderr,"unexpected qty.%llu vs.%s\n",(long long)qty,amountNQT);
|
|
return(-4);
|
|
}
|
|
return(0);
|
|
}
|
|
else
|
|
{
|
|
if ( typeval != 2 || subtypeval != 1 )
|
|
{
|
|
if ( Debuglevel > 2 )
|
|
fprintf(stderr,"refasset.%llu qty %lld\n",(long long)refasset,(long long)qty);
|
|
return(-11);
|
|
}
|
|
price = quantity = assetidbits = 0;
|
|
attachmentobj = cJSON_GetObjectItem(json,"attachment");
|
|
if ( attachmentobj != 0 )
|
|
{
|
|
if ( extract_cJSON_str(assetidstr,sizeof(assetidstr),attachmentobj,"asset") > 0 )
|
|
assetidbits = calc_nxt64bits(assetidstr);
|
|
//else if ( extract_cJSON_str(assetidstr,sizeof(assetidstr),attachmentobj,"currency") > 0 )
|
|
// assetidbits = calc_nxt64bits(assetidstr);
|
|
if ( extract_cJSON_str(quantityQNT,sizeof(quantityQNT),attachmentobj,"quantityQNT") > 0 )
|
|
quantity = calc_nxt64bits(quantityQNT);
|
|
//else if ( extract_cJSON_str(quantityQNT,sizeof(quantityQNT),attachmentobj,"units") > 0 )
|
|
// quantity = calc_nxt64bits(quantityQNT);
|
|
if ( extract_cJSON_str(priceNQT,sizeof(priceNQT),attachmentobj,"priceNQT") > 0 )
|
|
price = calc_nxt64bits(priceNQT);
|
|
}
|
|
if ( assetidbits != refasset )
|
|
{
|
|
fprintf(stderr,"assetidbits %llu != %llu refasset\n",(long long)assetidbits,(long long)refasset);
|
|
return(-12);
|
|
}
|
|
if ( qty != quantity )
|
|
{
|
|
fprintf(stderr,"qty.%llu != %llu\n",(long long)qty,(long long)quantity);
|
|
return(-13);
|
|
}
|
|
return(0);
|
|
}
|
|
return(-1);
|
|
}
|
|
|
|
int32_t InstantDEX_verify(uint64_t destNXTaddr,uint64_t sendasset,uint64_t sendqty,cJSON *txobj,uint64_t recvasset,uint64_t recvqty)
|
|
{
|
|
int32_t err;
|
|
// verify recipient, amounts in txobj
|
|
if ( (err= verify_NXTtx(txobj,recvasset,recvqty,destNXTaddr)) != 0 )
|
|
{
|
|
if ( Debuglevel > 2 )
|
|
printf("InstantDEX_verify dest.(%llu) tx mismatch %d (%llu %lld) -> (%llu %lld)\n",(long long)destNXTaddr,err,(long long)sendasset,(long long)sendqty,(long long)recvasset,(long long)recvqty);
|
|
return(-1);
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
cJSON *wallet_swapjson(char *recv,uint64_t recvasset,char *send,uint64_t sendasset,uint64_t orderid,uint64_t quoteid)
|
|
{
|
|
return(cJSON_Parse(clonestr("{\"error\":\"notyet\"}")));
|
|
#ifdef notyet
|
|
int32_t iter; uint64_t assetid; struct coin777 *coin; struct InstantDEX_quote *iQ;
|
|
char account[128],walletstr[512],*addr,*str; cJSON *walletitem = 0;
|
|
printf("wallet_swapjson is not yet\n");
|
|
if ( (iQ= find_iQ(quoteid)) != 0 && iQ->s.wallet != 0 )
|
|
{
|
|
walletitem = cJSON_Parse(iQ->walletstr);
|
|
//printf("start with (%s)\n",iQ->walletstr);
|
|
}
|
|
for (iter=0; iter<2; iter++)
|
|
{
|
|
addr = 0;
|
|
str = (iter == 0) ? recv : send;
|
|
assetid = (iter == 0) ? recvasset : sendasset;
|
|
if ( (coin= coin777_find(str,1)) != 0 )
|
|
{
|
|
if ( is_NXT_native(assetid) == 0 )
|
|
{
|
|
if ( (walletitem= set_walletstr(walletitem,walletstr,iQ)) != 0 )
|
|
{
|
|
|
|
}
|
|
} // else printf("%s is NXT\n",coin->name);
|
|
if ( is_NXT_native(assetid) != 0 )
|
|
addr = SUPERNET.NXTADDR;
|
|
else
|
|
{
|
|
addr = (iter == 0) ? coin->atomicrecv : coin->atomicsend;
|
|
if ( addr[0] == 0 )
|
|
addr = get_acct_coinaddr(addr,str,coin->serverport,coin->userpass,account);
|
|
}
|
|
if ( addr != 0 )
|
|
{
|
|
} else printf("%s no addr\n",coin->name);
|
|
} else printf("cant find coin.(%s)\n",iter == 0 ? recv : send);
|
|
}
|
|
if ( walletitem == 0 )
|
|
walletitem = cJSON_CreateObject(), jaddstr(walletitem,"error","cant find local coin daemons");
|
|
return(walletitem);
|
|
#endif
|
|
}
|
|
|
|
void _prices777_item(cJSON *item,int32_t group,struct prices777 *prices,int32_t bidask,double price,double volume,uint64_t orderid,uint64_t quoteid)
|
|
{
|
|
uint64_t baseqty,relqty; int32_t iswallet = 0; char basec,relc; struct InstantDEX_quote *iQ;
|
|
jaddnum(item,"group",group);
|
|
jaddstr(item,"exchange",prices->exchange);
|
|
jaddstr(item,"base",prices->base), jaddstr(item,"rel",prices->rel);
|
|
if ( (iQ= find_iQ(quoteid)) != 0 )
|
|
jadd64bits(item,"offerNXT",iQ->s.offerNXT);
|
|
if ( strcmp(prices->exchange,"nxtae") == 0 || strcmp(prices->exchange,"unconf") == 0 || strcmp(prices->exchange,"InstantDEX") == 0 || strcmp(prices->exchange,"wallet") == 0 )
|
|
{
|
|
jadd64bits(item,prices->type == 5 ? "currency" : "asset",prices->baseid);
|
|
//else if ( quoteid != 0 ) printf("cant find offerNXT.%llu\n",(long long)quoteid);
|
|
jadd64bits(item,"baseid",prices->baseid), jadd64bits(item,"relid",prices->relid);
|
|
iswallet = (strcmp(prices->exchange,"wallet") == 0);
|
|
if ( strcmp(prices->exchange,"InstantDEX") == 0 || iswallet != 0 )
|
|
{
|
|
jaddstr(item,"trade","swap");
|
|
baseqty = calc_qty(prices->basemult,prices->baseid,SATOSHIDEN * volume + 0.5/SATOSHIDEN);
|
|
//printf("baseid.%llu basemult.%llu -> %llu\n",(long long)prices->baseid,(long long)prices->basemult,(long long)baseqty);
|
|
relqty = calc_qty(prices->relmult,prices->relid,SATOSHIDEN * volume * price + 0.5/SATOSHIDEN);
|
|
if ( bidask != 0 )
|
|
{
|
|
basec = '+', relc = '-';
|
|
jadd64bits(item,"recvbase",baseqty);
|
|
jadd64bits(item,"sendrel",relqty);
|
|
if ( iswallet != 0 )
|
|
jadd(item,"wallet",wallet_swapjson(prices->base,prices->baseid,prices->rel,prices->relid,orderid,quoteid));
|
|
}
|
|
else
|
|
{
|
|
basec = '-', relc = '+';
|
|
jadd64bits(item,"sendbase",baseqty);
|
|
jadd64bits(item,"recvrel",relqty);
|
|
if ( iswallet != 0 )
|
|
jadd(item,"wallet",wallet_swapjson(prices->rel,prices->relid,prices->base,prices->baseid,orderid,quoteid));
|
|
}
|
|
//printf("(%s %cbaseqty.%llu <-> %s %crelqty.%llu) basemult.%llu baseid.%llu vol %f amount %llu\n",prices->base,basec,(long long)baseqty,prices->rel,relc,(long long)relqty,(long long)prices->basemult,(long long)prices->baseid,volume,(long long)volume*SATOSHIDEN);
|
|
}
|
|
else
|
|
{
|
|
//printf("alternate path\n");
|
|
jaddstr(item,"trade",bidask == 0 ? "sell" : "buy");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//printf("alternate path\n");
|
|
jaddstr(item,"trade",bidask == 0 ? "sell" : "buy");
|
|
jaddstr(item,"name",prices->contract);
|
|
}
|
|
jaddnum(item,"orderprice",price);
|
|
jaddnum(item,"ordervolume",volume);
|
|
if ( orderid != 0 )
|
|
jadd64bits(item,"orderid",orderid);
|
|
if ( quoteid != 0 )
|
|
jadd64bits(item,"quoteid",quoteid);
|
|
}
|
|
|
|
cJSON *prices777_item(int32_t rootbidask,struct prices777 *prices,int32_t group,int32_t bidask,double origprice,double origvolume,double rootwt,double groupwt,double wt,uint64_t orderid,uint64_t quoteid)
|
|
{
|
|
cJSON *item; double price,volume,oppo = 1.;
|
|
item = cJSON_CreateObject();
|
|
jaddstr(item,"basket",rootbidask == 0 ? "bid":"ask");
|
|
//jaddnum(item,"rootwt",rootwt);
|
|
//jaddnum(item,"groupwt",groupwt);
|
|
//jaddnum(item,"wt",wt);
|
|
if ( wt*groupwt < 0. )
|
|
oppo = -1.;
|
|
if ( wt*groupwt < 0 )
|
|
{
|
|
volume = origprice * origvolume;
|
|
price = 1./origprice;
|
|
} else price = origprice, volume = origvolume;
|
|
jaddnum(item,"price",price);
|
|
jaddnum(item,"volume",volume);
|
|
if ( groupwt*wt < 0 )
|
|
{
|
|
volume = origprice * origvolume;
|
|
price = 1./origprice;
|
|
} else price = origprice, volume = origvolume;
|
|
_prices777_item(item,group,prices,bidask,price,volume,orderid,quoteid);
|
|
return(item);
|
|
}
|
|
|
|
cJSON *prices777_tradeitem(int32_t rootbidask,struct prices777 *prices,int32_t group,int32_t bidask,int32_t slot,uint32_t timestamp,double price,double volume,double rootwt,double groupwt,double wt,uint64_t orderid,uint64_t quoteid)
|
|
{
|
|
static uint32_t match,error;
|
|
if ( prices->O.timestamp == timestamp )
|
|
{
|
|
//printf("tradeitem.(%s %f %f)\n",prices->exchange,price,volume);
|
|
if ( bidask == 0 && prices->O.book[MAX_GROUPS][slot].bid.s.price == price && prices->O.book[MAX_GROUPS][slot].bid.s.vol == volume )
|
|
match++;
|
|
else if ( bidask != 0 && prices->O.book[MAX_GROUPS][slot].ask.s.price == price && prices->O.book[MAX_GROUPS][slot].ask.s.vol == volume )
|
|
match++;
|
|
}
|
|
else if ( prices->O2.timestamp == timestamp )
|
|
{
|
|
//printf("2tradeitem.(%s %f %f)\n",prices->exchange,price,volume);
|
|
if ( bidask == 0 && prices->O2.book[MAX_GROUPS][slot].bid.s.price == price && prices->O2.book[MAX_GROUPS][slot].bid.s.vol == volume )
|
|
match++;
|
|
else if ( bidask != 0 && prices->O2.book[MAX_GROUPS][slot].ask.s.price == price && prices->O2.book[MAX_GROUPS][slot].ask.s.vol == volume )
|
|
match++;
|
|
} else error++, printf("mismatched tradeitem error.%d match.%d\n",error,match);
|
|
return(prices777_item(rootbidask,prices,group,bidask,price,volume,rootwt,groupwt,wt,orderid,quoteid));
|
|
}
|
|
|
|
cJSON *prices777_tradesequence(struct prices777 *prices,int32_t bidask,struct prices777_order *orders[],double rootwt,double groupwt,double wt,int32_t refgroup)
|
|
{
|
|
int32_t i,j,srcslot,srcbidask,err = 0; cJSON *array; struct prices777_order *suborders[MAX_GROUPS];
|
|
struct prices777_order *order; struct prices777 *src;
|
|
array = cJSON_CreateArray();
|
|
for (i=0; i<prices->numgroups; i++)
|
|
{
|
|
order = orders[i];
|
|
groupwt = prices->groupwts[i];
|
|
memset(suborders,0,sizeof(suborders));
|
|
srcbidask = (order->slot_ba & 1); srcslot = order->slot_ba >> 1;
|
|
if ( (src= order->source) != 0 )
|
|
{
|
|
if ( src->basketsize == 0 )
|
|
jaddi(array,prices777_tradeitem(bidask,src,refgroup*10+i,srcbidask,srcslot,order->s.timestamp,order->s.price,order->ratio*order->s.vol,rootwt,groupwt/groupwt,order->wt,order->id,order->s.quoteid));
|
|
else if ( src->O.timestamp == order->s.timestamp )
|
|
{
|
|
for (j=0; j<src->numgroups; j++)
|
|
suborders[j] = (srcbidask == 0) ? &src->O.book[j][srcslot].bid : &src->O.book[j][srcslot].ask;
|
|
jaddi(array,prices777_tradesequence(src,bidask,suborders,rootwt,groupwt/groupwt,order->wt,refgroup*10 + i));
|
|
}
|
|
else if ( src->O2.timestamp == order->s.timestamp )
|
|
{
|
|
for (j=0; j<src->numgroups; j++)
|
|
suborders[j] = (srcbidask == 0) ? &src->O2.book[j][srcslot].bid : &src->O2.book[j][srcslot].ask;
|
|
jaddi(array,prices777_tradesequence(src,bidask,suborders,rootwt,groupwt/groupwt,order->wt,refgroup*10 + i));
|
|
}
|
|
else err = 1;
|
|
}
|
|
if ( src == 0 || err != 0 )
|
|
{
|
|
//jaddi(array,prices777_item(prices,bidask,price,volume,wt,orderid));
|
|
//printf("prices777_tradesequence warning cant match timestamp %u (%s %s/%s)\n",order->timestamp,prices->contract,prices->base,prices->rel);
|
|
}
|
|
}
|
|
return(array);
|
|
}
|
|
|
|
void prices777_orderbook_item(struct prices777 *prices,int32_t bidask,struct prices777_order *suborders[],cJSON *array,int32_t invert,int32_t allflag,double origprice,double origvolume,uint64_t orderid,uint64_t quoteid)
|
|
{
|
|
cJSON *item,*obj,*tarray,*walletitem; double price,volume; struct InstantDEX_quote *iQ;
|
|
item = cJSON_CreateObject();
|
|
if ( invert != 0 )
|
|
volume = (origvolume * origprice), price = 1./origprice;
|
|
else price = origprice, volume = origvolume;
|
|
if ( strcmp(prices->exchange,"jumblr") == 0 || strcmp(prices->exchange,"pangea") == 0 )
|
|
{
|
|
jaddstr(item,"plugin",prices->exchange), jaddstr(item,"method","start");
|
|
jaddnum(item,"dotrade",1), jaddnum(item,"volume",volume);
|
|
jaddnum(item,"timeout",20000);
|
|
jaddstr(item,"base",prices->base);
|
|
if ( (iQ= find_iQ(quoteid)) != 0 )
|
|
jadd64bits(item,"offerNXT",iQ->s.offerNXT);
|
|
jadd64bits(item,"quoteid",iQ->s.quoteid);
|
|
if ( strcmp(prices->exchange,"pangea") == 0 && iQ->s.wallet != 0 && (walletitem= cJSON_Parse(iQ->walletstr)) != 0 )
|
|
jadd(item,"wallet",walletitem);
|
|
jaddi(array,item);
|
|
return;
|
|
}
|
|
jaddstr(item,"plugin","InstantDEX"), jaddstr(item,"method","tradesequence");
|
|
jaddnum(item,"dotrade",1), jaddnum(item,"price",price), jaddnum(item,"volume",volume);
|
|
//jaddnum(item,"invert",invert), jaddnum(item,"origprice",origprice), jaddnum(item,"origvolume",origvolume);
|
|
//jaddstr(item,"base",prices->base), jaddstr(item,"rel",prices->rel);
|
|
if ( allflag != 0 )
|
|
{
|
|
if ( prices->basketsize == 0 )
|
|
{
|
|
tarray = cJSON_CreateArray();
|
|
obj = cJSON_CreateObject();
|
|
_prices777_item(obj,0,prices,bidask,origprice,origvolume,orderid,quoteid);
|
|
jaddi(tarray,obj);
|
|
} else tarray = prices777_tradesequence(prices,bidask,suborders,invert!=0?-1:1.,1.,1.,0);
|
|
jadd(item,"trades",tarray);
|
|
}
|
|
jaddi(array,item);
|
|
}
|
|
|
|
char *prices777_orderbook_jsonstr(int32_t invert,uint64_t nxt64bits,struct prices777 *prices,struct prices777_basketinfo *OB,int32_t maxdepth,int32_t allflag)
|
|
{
|
|
struct prices777_orderentry *gp; struct prices777_order *suborders[MAX_GROUPS]; cJSON *json,*bids,*asks;
|
|
int32_t i,slot; char baserel[64],base[64],rel[64],assetA[64],assetB[64],NXTaddr[64];
|
|
if ( invert == 0 )
|
|
sprintf(baserel,"%s/%s",prices->base,prices->rel);
|
|
else sprintf(baserel,"%s/%s",prices->rel,prices->base);
|
|
if ( Debuglevel > 2 )
|
|
printf("ORDERBOOK %s/%s iQsize.%ld numbids.%d numasks.%d maxdepth.%d (%llu %llu)\n",prices->base,prices->rel,(long)sizeof(struct InstantDEX_quote),OB->numbids,OB->numasks,maxdepth,(long long)prices->baseid,(long long)prices->relid);
|
|
json = cJSON_CreateObject(), bids = cJSON_CreateArray(), asks = cJSON_CreateArray();
|
|
gp = &OB->book[MAX_GROUPS][0];
|
|
memset(suborders,0,sizeof(suborders));
|
|
for (slot=0; (slot<OB->numbids || slot<OB->numasks) && slot<maxdepth; slot++,gp++)
|
|
{
|
|
//printf("slot.%d\n",slot);
|
|
if ( slot < OB->numbids )
|
|
{
|
|
for (i=0; i<prices->numgroups; i++)
|
|
suborders[i] = &OB->book[i][slot].bid;
|
|
prices777_orderbook_item(prices,0,suborders,(invert==0) ? bids : asks,invert,allflag,gp->bid.s.price,gp->bid.s.vol,gp->bid.id,gp->bid.s.quoteid);
|
|
}
|
|
if ( slot < OB->numasks )
|
|
{
|
|
for (i=0; i<prices->numgroups; i++)
|
|
suborders[i] = &OB->book[i][slot].ask;
|
|
prices777_orderbook_item(prices,1,suborders,(invert==0) ? asks : bids,invert,allflag,gp->ask.s.price,gp->ask.s.vol,gp->ask.id,gp->ask.s.quoteid);
|
|
}
|
|
}
|
|
expand_nxt64bits(NXTaddr,nxt64bits);
|
|
if ( invert != 0 )
|
|
strcpy(base,prices->rel), strcpy(rel,prices->base);
|
|
else strcpy(base,prices->base), strcpy(rel,prices->rel);
|
|
expand_nxt64bits(assetA,invert==0 ? prices->baseid : prices->relid);
|
|
expand_nxt64bits(assetB,invert!=0 ? prices->baseid : prices->relid);
|
|
cJSON_AddItemToObject(json,"exchange",cJSON_CreateString(prices->exchange));
|
|
cJSON_AddItemToObject(json,"inverted",cJSON_CreateNumber(invert));
|
|
cJSON_AddItemToObject(json,"contract",cJSON_CreateString(prices->contract));
|
|
cJSON_AddItemToObject(json,"baseid",cJSON_CreateString(assetA));
|
|
if ( assetB[0] != 0 )
|
|
cJSON_AddItemToObject(json,"relid",cJSON_CreateString(assetB));
|
|
cJSON_AddItemToObject(json,"base",cJSON_CreateString(base));
|
|
if ( rel[0] != 0 )
|
|
cJSON_AddItemToObject(json,"rel",cJSON_CreateString(rel));
|
|
cJSON_AddItemToObject(json,"bids",bids);
|
|
cJSON_AddItemToObject(json,"asks",asks);
|
|
if ( invert == 0 )
|
|
{
|
|
cJSON_AddItemToObject(json,"numbids",cJSON_CreateNumber(OB->numbids));
|
|
cJSON_AddItemToObject(json,"numasks",cJSON_CreateNumber(OB->numasks));
|
|
cJSON_AddItemToObject(json,"lastbid",cJSON_CreateNumber(prices->lastbid));
|
|
cJSON_AddItemToObject(json,"lastask",cJSON_CreateNumber(prices->lastask));
|
|
}
|
|
else
|
|
{
|
|
cJSON_AddItemToObject(json,"numbids",cJSON_CreateNumber(OB->numasks));
|
|
cJSON_AddItemToObject(json,"numasks",cJSON_CreateNumber(OB->numbids));
|
|
if ( prices->lastask != 0 )
|
|
cJSON_AddItemToObject(json,"lastbid",cJSON_CreateNumber(1. / prices->lastask));
|
|
if ( prices->lastbid != 0 )
|
|
cJSON_AddItemToObject(json,"lastask",cJSON_CreateNumber(1. / prices->lastbid));
|
|
}
|
|
cJSON_AddItemToObject(json,"NXT",cJSON_CreateString(NXTaddr));
|
|
cJSON_AddItemToObject(json,"timestamp",cJSON_CreateNumber(time(NULL)));
|
|
cJSON_AddItemToObject(json,"maxdepth",cJSON_CreateNumber(maxdepth));
|
|
return(jprint(json,1));
|
|
}
|
|
|
|
void prices777_jsonstrs(struct prices777 *prices,struct prices777_basketinfo *OB)
|
|
{
|
|
int32_t allflag; char *strs[4];
|
|
if ( OB->numbids == 0 && OB->numasks == 0 )
|
|
{
|
|
printf("warning: updating null orderbook ignored for %s (%s/%s)\n",prices->contract,prices->base,prices->rel);
|
|
return;
|
|
}
|
|
for (allflag=0; allflag<4; allflag++)
|
|
{
|
|
strs[allflag] = prices777_orderbook_jsonstr(allflag/2,IGUANA_MY64BITS,prices,OB,MAX_DEPTH,allflag%2);
|
|
if ( Debuglevel > 2 )
|
|
printf("strs[%d].(%s) prices.%p\n",allflag,strs[allflag],prices);
|
|
}
|
|
portable_mutex_lock(&prices->mutex);
|
|
for (allflag=0; allflag<4; allflag++)
|
|
{
|
|
if ( prices->orderbook_jsonstrs[allflag/2][allflag%2] != 0 )
|
|
free(prices->orderbook_jsonstrs[allflag/2][allflag%2]);
|
|
prices->orderbook_jsonstrs[allflag/2][allflag%2] = strs[allflag];
|
|
}
|
|
portable_mutex_unlock(&prices->mutex);
|
|
}
|
|
|
|
char *orderbook_clonestr(struct prices777 *prices,int32_t invert,int32_t allflag)
|
|
{
|
|
char *str,*clone = 0;
|
|
portable_mutex_lock(&prices->mutex);
|
|
if ( (str= prices->orderbook_jsonstrs[invert][allflag]) != 0 )
|
|
clone = clonestr(str);
|
|
portable_mutex_unlock(&prices->mutex);
|
|
return(clone);
|
|
}
|
|
|
|
void prices777_json_quotes(double *hblap,struct prices777 *prices,cJSON *bids,cJSON *asks,int32_t maxdepth,char *pricefield,char *volfield,uint32_t reftimestamp)
|
|
{
|
|
cJSON *item; int32_t i,slot,n=0,m=0,dir,bidask,numitems; uint64_t orderid,quoteid; uint32_t timestamp; double price,volume,hbla = 0.;
|
|
struct prices777_basketinfo OB; struct prices777_orderentry *gp; struct prices777_order *order;
|
|
memset(&OB,0,sizeof(OB));
|
|
if ( reftimestamp == 0 )
|
|
reftimestamp = (uint32_t)time(NULL);
|
|
OB.timestamp = reftimestamp;
|
|
if ( bids != 0 )
|
|
{
|
|
n = cJSON_GetArraySize(bids);
|
|
if ( maxdepth != 0 && n > maxdepth )
|
|
n = maxdepth;
|
|
}
|
|
if ( asks != 0 )
|
|
{
|
|
m = cJSON_GetArraySize(asks);
|
|
if ( maxdepth != 0 && m > maxdepth )
|
|
m = maxdepth;
|
|
}
|
|
for (i=0; i<n||i<m; i++)
|
|
{
|
|
gp = &OB.book[MAX_GROUPS][i];
|
|
gp->bid.source = gp->ask.source = prices;
|
|
for (bidask=0; bidask<2; bidask++)
|
|
{
|
|
price = volume = 0.;
|
|
orderid = quoteid = 0;
|
|
dir = (bidask == 0) ? 1 : -1;
|
|
if ( bidask == 0 && i >= n )
|
|
continue;
|
|
else if ( bidask == 1 && i >= m )
|
|
continue;
|
|
if ( strcmp(prices->exchange,"bter") == 0 && dir < 0 )
|
|
slot = ((bidask==0?n:m) - 1) - i;
|
|
else slot = i;
|
|
timestamp = 0;
|
|
item = jitem(bidask==0?bids:asks,slot);
|
|
if ( pricefield != 0 && volfield != 0 )
|
|
price = jdouble(item,pricefield), volume = jdouble(item,volfield);
|
|
else if ( is_cJSON_Array(item) != 0 && (numitems= cJSON_GetArraySize(item)) != 0 ) // big assumptions about order within nested array!
|
|
{
|
|
price = jdouble(jitem(item,0),0), volume = jdouble(jitem(item,1),0);
|
|
if ( strcmp(prices->exchange,"kraken") == 0 )
|
|
timestamp = juint(jitem(item,2),0);
|
|
else orderid = j64bits(jitem(item,2),0);
|
|
}
|
|
else continue;
|
|
if ( quoteid == 0 )
|
|
quoteid = orderid;
|
|
if ( price > SMALLVAL && volume > SMALLVAL )
|
|
{
|
|
if ( prices->commission != 0. )
|
|
{
|
|
//printf("price %f fee %f -> ",price,prices->commission * price);
|
|
if ( bidask == 0 )
|
|
price -= prices->commission * price;
|
|
else price += prices->commission * price;
|
|
//printf("%f\n",price);
|
|
}
|
|
order = (bidask == 0) ? &gp->bid : &gp->ask;
|
|
order->s.price = price, order->s.vol = volume, order->source = prices, order->s.timestamp = OB.timestamp, order->wt = 1, order->id = orderid, order->s.quoteid = quoteid;
|
|
if ( bidask == 0 )
|
|
order->slot_ba = (OB.numbids++ << 1);
|
|
else order->slot_ba = (OB.numasks++ << 1) | 1;
|
|
if ( i == 0 )
|
|
{
|
|
if ( bidask == 0 )
|
|
prices->lastbid = price;
|
|
else prices->lastask = price;
|
|
if ( hbla == 0. )
|
|
hbla = price;
|
|
else hbla = 0.5 * (hbla + price);
|
|
}
|
|
if ( Debuglevel > 2 )//|| prices->basketsize > 0 || strcmp("unconf",prices->exchange) == 0 )
|
|
printf("%d,%d: %-8s %s %5s/%-5s %13.8f vol %13.8f | invert %13.8f vol %13.8f | timestamp.%u\n",OB.numbids,OB.numasks,prices->exchange,dir>0?"bid":"ask",prices->base,prices->rel,price,volume,1./price,volume*price,timestamp);
|
|
}
|
|
}
|
|
}
|
|
if ( hbla != 0. )
|
|
*hblap = hbla;
|
|
prices->O2 = prices->O;
|
|
//prices->O = OB;
|
|
for (i=0; i<MAX_GROUPS; i++)
|
|
memcpy(prices->O.book[i],prices->O.book[i+1],sizeof(prices->O.book[i]));
|
|
memcpy(prices->O.book[MAX_GROUPS],OB.book[MAX_GROUPS],sizeof(OB.book[MAX_GROUPS]));
|
|
prices->O.numbids = OB.numbids, prices->O.numasks = OB.numasks, prices->O.timestamp = OB.timestamp;
|
|
}
|
|
|
|
double prices777_json_orderbook(char *exchangestr,struct prices777 *prices,int32_t maxdepth,cJSON *json,char *resultfield,char *bidfield,char *askfield,char *pricefield,char *volfield)
|
|
{
|
|
cJSON *obj = 0,*bidobj=0,*askobj=0; double hbla = 0.; int32_t numasks=0,numbids=0;
|
|
if ( resultfield == 0 )
|
|
obj = json;
|
|
if ( maxdepth == 0 )
|
|
maxdepth = MAX_DEPTH;
|
|
if ( resultfield == 0 || (obj= jobj(json,resultfield)) != 0 )
|
|
{
|
|
bidobj = jarray(&numbids,obj,bidfield);
|
|
askobj = jarray(&numasks,obj,askfield);
|
|
if ( bidobj != 0 || askobj != 0 )
|
|
{
|
|
prices777_json_quotes(&hbla,prices,bidobj,askobj,maxdepth,pricefield,volfield,0);
|
|
prices777_jsonstrs(prices,&prices->O);
|
|
}
|
|
}
|
|
return(hbla);
|
|
}
|
|
|
|
void prices777_hbla(uint64_t *bidorderid,uint64_t *askorderid,int32_t *lowaski,int32_t *highbidi,double *highbid,double *bidvol,double *lowask,double *askvol,double groupwt,int32_t i,int32_t bidask,double price,double vol,uint64_t orderid)
|
|
{
|
|
if ( groupwt > SMALLVAL && (*lowask == 0. || price < *lowask) )
|
|
*askorderid = orderid, *lowask = price, *askvol = vol, *lowaski = (i << 1) | bidask;
|
|
else if ( groupwt < -SMALLVAL && (*highbid == 0. || price > *highbid) )
|
|
*bidorderid = orderid, *highbid = price, *bidvol = vol, *highbidi = (i << 1) | bidask;
|
|
//printf("hbla.(%f %f)\n",price,vol);
|
|
}
|
|
|
|
void prices777_setorder(struct prices777_order *order,struct prices777_basket *group,int32_t coordinate,uint64_t orderid,double refprice,double refvol)
|
|
{
|
|
int32_t bidask; struct prices777 *prices; double price=0,vol=0;
|
|
bidask = (coordinate & 1), coordinate >>= 1;
|
|
prices = group[coordinate].prices;
|
|
if ( bidask != 0 && group[coordinate].aski < prices->O.numasks )
|
|
price = prices->O.book[MAX_GROUPS][group[coordinate].aski].ask.s.price, vol = prices->O.book[MAX_GROUPS][group[coordinate].aski].ask.s.vol, order->slot_ba = (group[coordinate].aski++ << 1) | 1;
|
|
else if ( group[coordinate].bidi < prices->O.numbids )
|
|
price = prices->O.book[MAX_GROUPS][group[coordinate].bidi].bid.s.price, vol = prices->O.book[MAX_GROUPS][group[coordinate].bidi].bid.s.vol,order->slot_ba = (group[coordinate].bidi++ << 1);
|
|
else printf("illegal coordinate.%d bidask.%d when bidi.%d aski.%d numbids.%d numasks.%d\n",coordinate,bidask,group[coordinate].bidi,group[coordinate].aski,prices->O.numbids,prices->O.numasks);
|
|
order->source = prices;
|
|
order->wt = group[coordinate].wt;
|
|
order->s.timestamp = prices->O.timestamp;
|
|
order->id = orderid;
|
|
if ( order->wt < 0. )
|
|
vol *= price, price = (1. / price);
|
|
if ( fabs(price - refprice) > SMALLVAL || fabs(vol - refvol) > SMALLVAL )
|
|
{
|
|
printf("[ERROR] ");
|
|
printf("%s group.%d (%s/%s) bidask.%d coordinate.%d wt %.8f (%.8f %.8f) vs (%.8f %.8f)\n",prices->exchange,group[coordinate].groupid,prices->base,prices->rel,bidask,coordinate,order->wt,price,vol,refprice,refvol);
|
|
}
|
|
}
|
|
|
|
|
|
int32_t prices777_groupbidasks(struct prices777_orderentry *gp,double groupwt,double minvol,struct prices777_basket *group,int32_t groupsize)
|
|
{
|
|
int32_t i,highbidi,lowaski; double highbid,lowask,bidvol,askvol,vol,price,polarity; uint64_t bidorderid,askorderid;
|
|
struct prices777 *feature; struct prices777_order *order;
|
|
memset(gp,0,sizeof(*gp));
|
|
highbidi = lowaski = -1;
|
|
for (bidvol=askvol=highbid=lowask=bidorderid=askorderid=i=0; i<groupsize; i++)
|
|
{
|
|
if ( (feature= group[i].prices) != 0 )
|
|
{
|
|
//if ( strcmp(feature->base,group[0].rel) == 0 && strcmp(feature->rel,group[0].base) == 0 )
|
|
// polarity = -1.;
|
|
//else polarity = 1.;
|
|
//if ( group[i].wt * groupwt < 0 ) fixes supernet/BTC
|
|
// polarity *= -1;
|
|
polarity = group[i].wt;// * groupwt;
|
|
order = &feature->O.book[MAX_GROUPS][group[i].bidi].bid;
|
|
if ( group[i].bidi < feature->O.numbids && (vol= order->s.vol) > minvol && (price= order->s.price) > SMALLVAL )
|
|
{
|
|
//printf("%d/%d: (%s/%s) %s bidi.%d price.%f polarity.%f groupwt.%f -> ",i,groupsize,feature->base,feature->rel,feature->exchange,group[i].bidi,price,polarity,groupwt);
|
|
if ( polarity < 0. )
|
|
vol *= price, price = (1. / price);
|
|
prices777_hbla(&bidorderid,&askorderid,&lowaski,&highbidi,&highbid,&bidvol,&lowask,&askvol,-polarity,i,0,price,vol,order->id);
|
|
}
|
|
order = &feature->O.book[MAX_GROUPS][group[i].aski].ask;
|
|
if ( group[i].aski < feature->O.numasks && (vol= order->s.vol) > minvol && (price= order->s.price) > SMALLVAL )
|
|
{
|
|
//printf("%d/%d: (%s/%s) %s aski.%d price.%f polarity.%f groupwt.%f -> ",i,groupsize,feature->base,feature->rel,feature->exchange,group[i].aski,price,polarity,groupwt);
|
|
if ( polarity < 0. )
|
|
vol *= price, price = (1. / price);
|
|
prices777_hbla(&bidorderid,&askorderid,&lowaski,&highbidi,&highbid,&bidvol,&lowask,&askvol,polarity,i,1,price,vol,order->id);
|
|
}
|
|
} else printf("null feature.%p\n",feature);
|
|
}
|
|
gp->bid.s.price = highbid, gp->bid.s.vol = bidvol, gp->ask.s.price = lowask, gp->ask.s.vol = askvol;
|
|
if ( highbidi >= 0 )
|
|
prices777_setorder(&gp->bid,group,highbidi,bidorderid,highbid,bidvol);
|
|
if ( lowaski >= 0 )
|
|
prices777_setorder(&gp->ask,group,lowaski,askorderid,lowask,askvol);
|
|
// if ( lowaski >= 0 && highbidi >= 0 )
|
|
//printf("groupwt %f groupsize.%d %s highbidi.%d %f %f %s lowaski.%d wts.(%f %f)\n",groupwt,groupsize,gp->bid.source->exchange,highbidi,gp->bid.s.price,gp->ask.s.price,gp->ask.source->exchange,lowaski,gp->bid.wt,gp->ask.wt);
|
|
if ( gp->bid.s.price > SMALLVAL && gp->ask.s.price > SMALLVAL )
|
|
return(0);
|
|
return(-1);
|
|
}
|
|
|
|
double prices777_volcalc(double *basevols,uint64_t *baseids,uint64_t baseid,double basevol)
|
|
{
|
|
int32_t i;
|
|
//printf("(add %llu %f) ",(long long)baseid,basevol);
|
|
for (i=0; i<MAX_GROUPS*2; i++)
|
|
{
|
|
if ( baseids[i] == baseid )
|
|
{
|
|
if ( basevols[i] == 0. || basevol < basevols[i] )
|
|
basevols[i] = basevol;//, printf("set %llu <= %f ",(long long)baseid,basevol);
|
|
// else printf("missed basevols[%d] %f, ",i,basevols[i]);
|
|
break;
|
|
}
|
|
}
|
|
return(1);
|
|
}
|
|
|
|
double prices777_volratio(double *basevols,uint64_t *baseids,uint64_t baseid,double vol)
|
|
{
|
|
int32_t i;
|
|
for (i=0; i<MAX_GROUPS*2; i++)
|
|
{
|
|
if ( baseids[i] == baseid )
|
|
{
|
|
if ( basevols[i] > 0. )
|
|
{
|
|
//printf("(vol %f vs %f) ",vol,basevols[i]);
|
|
if ( vol > basevols[i] )
|
|
return(basevols[i]/vol);
|
|
else return(1.);
|
|
}
|
|
printf("unexpected zero vol basevols.%d\n",i);
|
|
return(1.);
|
|
break;
|
|
}
|
|
}
|
|
printf("unexpected cant find baseid.%llu\n",(long long)baseid);
|
|
return(1.);
|
|
}
|
|
|
|
double prices777_basket(struct prices777 *prices,int32_t maxdepth)
|
|
{
|
|
int32_t i,j,groupsize,slot; uint64_t baseids[MAX_GROUPS*2];
|
|
double basevols[MAX_GROUPS*2],relvols[MAX_GROUPS*2],baseratio,relratio,a,av,b,bv,gap,bid,ask,minvol,bidvol,askvol,hbla = 0.;
|
|
struct prices777_basketinfo OB; uint32_t timestamp; struct prices777 *feature; struct prices777_orderentry *gp;
|
|
a = av = b = bv = 0;
|
|
timestamp = (uint32_t)time(NULL);
|
|
memset(&OB,0,sizeof(OB));
|
|
memset(baseids,0,sizeof(baseids));
|
|
OB.timestamp = timestamp;
|
|
//printf("prices777_basket.(%s) %s (%s/%s) %llu/%llu basketsize.%d\n",prices->exchange,prices->contract,prices->base,prices->rel,(long long)prices->baseid,(long long)prices->relid,prices->basketsize);
|
|
for (i=0; i<prices->basketsize; i++)
|
|
{
|
|
if ( 0 && strcmp(prices->exchange,"active") == 0 && prices->basket[i].prices != 0 )
|
|
printf("%s.group.%d %10s %10s/%10s wt %3.0f %.8f %.8f\n",prices->exchange,i,prices->basket[i].prices->exchange,prices->basket[i].prices->base,prices->basket[i].rel,prices->basket[i].wt,prices->basket[i].prices->O.book[MAX_GROUPS][0].bid.s.price,prices->basket[i].prices->O.book[MAX_GROUPS][0].ask.s.price);
|
|
if ( (feature= prices->basket[i].prices) != 0 )
|
|
{
|
|
if ( 0 && (gap= (prices->lastupdate - feature->lastupdate)) < 0 )
|
|
{
|
|
if ( prices->lastupdate != 0 )
|
|
printf("you can ignore this harmless warning about unexpected time traveling feature %f vs %f or laggy feature\n",prices->lastupdate,feature->lastupdate);
|
|
return(0.);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
printf("unexpected null basket item %s[%d]\n",prices->contract,i);
|
|
return(0.);
|
|
}
|
|
prices->basket[i].aski = prices->basket[i].bidi = 0;
|
|
for (j=0; j<MAX_GROUPS*2; j++)
|
|
{
|
|
if ( prices->basket[i].prices == 0 || prices->basket[i].prices->baseid == baseids[j] )
|
|
break;
|
|
if ( baseids[j] == 0 )
|
|
{
|
|
baseids[j] = prices->basket[i].prices->baseid;
|
|
break;
|
|
}
|
|
}
|
|
for (j=0; j<MAX_GROUPS*2; j++)
|
|
{
|
|
if ( prices->basket[i].prices == 0 || prices->basket[i].prices->relid == baseids[j] )
|
|
break;
|
|
if ( baseids[j] == 0 )
|
|
{
|
|
baseids[j] = prices->basket[i].prices->relid;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
//printf("%s basketsize.%d numgroups.%d maxdepth.%d group0size.%d\n",prices->contract,prices->basketsize,prices->numgroups,maxdepth,prices->basket[0].groupsize);
|
|
for (slot=0; slot<maxdepth; slot++)
|
|
{
|
|
memset(basevols,0,sizeof(basevols));
|
|
memset(relvols,0,sizeof(relvols));
|
|
groupsize = prices->basket[0].groupsize;
|
|
minvol = (1. / SATOSHIDEN);
|
|
bid = ask = 1.; bidvol = askvol = 0.;
|
|
for (j=i=0; j<prices->numgroups; j++,i+=groupsize)
|
|
{
|
|
groupsize = prices->basket[i].groupsize;
|
|
gp = &OB.book[j][slot];
|
|
if ( prices777_groupbidasks(gp,prices->groupwts[j],minvol,&prices->basket[i],groupsize) != 0 )
|
|
{
|
|
//printf("prices777_groupbidasks i.%d j.%d error\n",i,j);
|
|
break;
|
|
}
|
|
//printf("%s j%d slot.%d %s numgroups.%d groupsize.%d\n",prices->exchange,j,slot,prices->contract,prices->numgroups,groupsize);
|
|
if ( bid > SMALLVAL && (b= gp->bid.s.price) > SMALLVAL && (bv= gp->bid.s.vol) > SMALLVAL )
|
|
{
|
|
//if ( gp->bid.wt*prices->groupwts[j] < 0 )
|
|
// bid /= b;
|
|
//else
|
|
bid *= b;
|
|
prices777_volcalc(basevols,baseids,gp->bid.source->baseid,bv);
|
|
prices777_volcalc(basevols,baseids,gp->bid.source->relid,b*bv);
|
|
//printf("bid %f b %f bv %f %s %s %f\n",bid,b,bv,gp->bid.source->base,gp->bid.source->rel,bv*b);
|
|
} else bid = 0.;
|
|
if ( ask > SMALLVAL && (a= gp->ask.s.price) > SMALLVAL && (av= gp->ask.s.vol) > SMALLVAL )
|
|
{
|
|
//if ( gp->ask.wt*prices->groupwts[j] < 0 )
|
|
// ask /= a;
|
|
//else
|
|
ask *= a;
|
|
prices777_volcalc(relvols,baseids,gp->ask.source->baseid,av);
|
|
prices777_volcalc(relvols,baseids,gp->ask.source->relid,a*av);
|
|
//printf("ask %f b %f bv %f %s %s %f\n",ask,a,av,gp->ask.source->base,gp->ask.source->rel,av*a);
|
|
} else ask = 0.;
|
|
if ( Debuglevel > 2 )
|
|
printf("%10s %10s/%10s %s (%s %s) wt:%f %2.0f/%2.0f j.%d: b %.8f %12.6f a %.8f %12.6f, bid %.8f ask %.8f inv %f %f\n",prices->exchange,gp->bid.source->exchange,gp->ask.source->exchange,prices->contract,gp->bid.source->contract,gp->ask.source->contract,prices->groupwts[j],gp->bid.wt,gp->ask.wt,j,b,bv,a,av,bid,ask,1/bid,1/ask);
|
|
}
|
|
for (j=0; j<prices->numgroups; j++)
|
|
{
|
|
gp = &OB.book[j][slot];
|
|
if ( gp->bid.source == 0 || gp->ask.source == 0 )
|
|
{
|
|
printf("%s: (%s/%s) null source slot.%d j.%d\n",prices->exchange,prices->base,prices->rel,slot,j);
|
|
break;
|
|
}
|
|
baseratio = prices777_volratio(basevols,baseids,gp->bid.source->baseid,gp->bid.s.vol);
|
|
relratio = prices777_volratio(basevols,baseids,gp->bid.source->relid,gp->bid.s.vol * gp->bid.s.price);
|
|
gp->bid.ratio = (baseratio < relratio) ? baseratio : relratio;
|
|
if ( j == 0 )
|
|
bidvol = (gp->bid.ratio * gp->bid.s.vol);
|
|
//printf("(%f %f) (%f %f) bid%d bidratio %f bidvol %f ",gp->bid.s.vol,baseratio,gp->bid.s.vol * gp->bid.s.price,relratio,j,gp->bid.ratio,bidvol);
|
|
baseratio = prices777_volratio(relvols,baseids,gp->ask.source->baseid,gp->ask.s.vol);
|
|
relratio = prices777_volratio(relvols,baseids,gp->ask.source->relid,gp->ask.s.vol * gp->ask.s.price);
|
|
gp->ask.ratio = (baseratio < relratio) ? baseratio : relratio;
|
|
if ( j == 0 )
|
|
askvol = (gp->ask.ratio * gp->ask.s.vol);
|
|
}
|
|
if ( j != prices->numgroups )
|
|
{
|
|
//printf("%s: j.%d != numgroups.%d\n",prices->exchange,j,prices->numgroups);
|
|
break;
|
|
}
|
|
for (j=0; j<MAX_GROUPS*2; j++)
|
|
{
|
|
if ( baseids[j] == 0 )
|
|
break;
|
|
//printf("{%llu %f %f} ",(long long)baseids[j],basevols[j],relvols[j]);
|
|
}
|
|
//printf("basevols bidvol %f, askvol %f\n",bidvol,askvol);
|
|
gp = &OB.book[MAX_GROUPS][slot];
|
|
if ( bid > SMALLVAL && bidvol > SMALLVAL )
|
|
{
|
|
if ( slot == 0 )
|
|
prices->lastbid = bid;
|
|
gp->bid.s.timestamp = OB.timestamp, gp->bid.s.price = bid, gp->bid.s.vol = bidvol, gp->bid.slot_ba = (OB.numbids++ << 1);
|
|
gp->bid.source = prices, gp->bid.wt = prices->groupwts[j];
|
|
}
|
|
if ( ask > SMALLVAL && askvol > SMALLVAL )
|
|
{
|
|
if ( slot == 0 )
|
|
prices->lastask = ask;
|
|
gp->ask.s.timestamp = OB.timestamp, gp->ask.s.price = ask, gp->ask.s.vol = askvol, gp->ask.slot_ba = (OB.numasks++ << 1) | 1;
|
|
gp->ask.source = prices, gp->ask.wt = prices->groupwts[j];
|
|
}
|
|
//printf("%s %s slot.%d (%.8f %.6f %.8f %.6f) (%d %d)\n",prices->exchange,prices->contract,slot,gp->bid.s.price,gp->bid.s.vol,gp->ask.s.price,gp->ask.s.vol,OB.numbids,OB.numasks);
|
|
}
|
|
//fprintf(stderr,"%s basket.%s slot.%d numbids.%d numasks.%d %f %f\n",prices->exchange,prices->contract,slot,prices->O.numbids,prices->O.numasks,prices->O.book[MAX_GROUPS][0].bid.s.price,prices->O.book[MAX_GROUPS][0].ask.s.price);
|
|
if ( slot > 0 )
|
|
{
|
|
prices->O2 = prices->O;
|
|
prices->O = OB;
|
|
if ( prices->lastbid > SMALLVAL && prices->lastask > SMALLVAL )
|
|
hbla = 0.5 * (prices->lastbid + prices->lastask);
|
|
}
|
|
return(hbla);
|
|
}
|
|
|
|
struct prices777 *prices777_addbundle(int32_t *validp,int32_t loadprices,struct prices777 *prices,char *exchangestr,uint64_t baseid,uint64_t relid)
|
|
{
|
|
int32_t j; struct prices777 *ptr; struct exchange_info *exchange;
|
|
*validp = -1;
|
|
if ( prices != 0 )
|
|
{
|
|
exchangestr = prices->exchange;
|
|
baseid = prices->baseid, relid = prices->relid;
|
|
}
|
|
for (j=0; j<BUNDLE.num; j++)
|
|
{
|
|
if ( (ptr= BUNDLE.ptrs[j]) != 0 && ((ptr->baseid == baseid && ptr->relid == relid) || (ptr->relid == baseid && ptr->baseid == relid)) && strcmp(ptr->exchange,exchangestr) == 0 )
|
|
return(ptr);
|
|
}
|
|
if ( j == BUNDLE.num )
|
|
{
|
|
if ( prices != 0 )
|
|
{
|
|
exchange = &Exchanges[prices->exchangeid];
|
|
if ( loadprices != 0 && exchange->issue.update != 0 )
|
|
{
|
|
portable_mutex_lock(&exchange->mutex);
|
|
(exchange->issue.update)(prices,MAX_DEPTH);
|
|
portable_mutex_unlock(&exchange->mutex);
|
|
}
|
|
printf("total polling.%d added.(%s)\n",BUNDLE.num,prices->contract);
|
|
if ( exchange->polling == 0 )
|
|
{
|
|
printf("First pair for (%s), start polling]\n",exchange_str(prices->exchangeid));
|
|
exchange->polling = 1;
|
|
if ( strcmp(exchange->name,"wallet") != 0 )//&& strcmp(exchange->name,"jumblr") != 0 && strcmp(exchange->name,"pangea") != 0 )
|
|
iguana_launch(iguana_coinadd("BTCD"),"exchangeloop",(void *)prices777_exchangeloop,&Exchanges[prices->exchangeid],IGUANA_EXCHANGETHREAD);
|
|
}
|
|
BUNDLE.ptrs[BUNDLE.num] = prices;
|
|
printf("prices777_addbundle.(%s) (%s/%s).%s %llu %llu\n",prices->contract,prices->base,prices->rel,prices->exchange,(long long)prices->baseid,(long long)prices->relid);
|
|
BUNDLE.num++;
|
|
} else printf("no prices\n");
|
|
*validp = BUNDLE.num;
|
|
return(prices);
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
int32_t is_native_crypto(char *name,uint64_t bits)
|
|
{
|
|
int32_t i,n;
|
|
if ( (n= (int32_t)strlen(name)) > 0 || (n= unstringbits(name,bits)) <= 5 )
|
|
{
|
|
for (i=0; i<n; i++)
|
|
{
|
|
if ( (name[i] >= '0' && name[i] <= '9') || (name[i] >= 'A' && name[i] <= 'Z') )// || (name[i] >= '0' && name[i] <= '9') )
|
|
continue;
|
|
printf("(%s) is not native crypto\n",name);
|
|
return(0);
|
|
}
|
|
printf("(%s) is native crypto\n",name);
|
|
return(1);
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
char *_issue_getAsset(char *assetidstr)
|
|
{
|
|
char cmd[4096],*jsonstr;
|
|
//sprintf(cmd,"requestType=getAsset&asset=%s",assetidstr);
|
|
sprintf(cmd,"requestType=getAsset&asset=%s",assetidstr);
|
|
//printf("_cmd.(%s)\n",cmd);
|
|
jsonstr = issue_NXTPOST(cmd);
|
|
//printf("(%s) -> (%s)\n",cmd,jsonstr);
|
|
return(jsonstr);
|
|
}
|
|
|
|
char *_issue_getCurrency(char *assetidstr)
|
|
{
|
|
char cmd[4096];
|
|
//sprintf(cmd,"requestType=getAsset&asset=%s",assetidstr);
|
|
sprintf(cmd,"requestType=getCurrency¤cy=%s",assetidstr);
|
|
//printf("_cmd.(%s)\n",cmd);
|
|
return(issue_NXTPOST(cmd));
|
|
}
|
|
|
|
int32_t is_mscoin(char *assetidstr)
|
|
{
|
|
char *jsonstr; cJSON *json; int32_t retcode = 0;
|
|
if ( (jsonstr= _issue_getCurrency(assetidstr)) != 0 )
|
|
{
|
|
if ( (json= cJSON_Parse(jsonstr)) != 0 )
|
|
{
|
|
if ( get_cJSON_int(json,"errorCode") == 0 )
|
|
retcode = 1;
|
|
free_json(json);
|
|
}
|
|
free(jsonstr);
|
|
}
|
|
return(retcode);
|
|
}
|
|
|
|
int32_t get_assetname(char *name,uint64_t assetid)
|
|
{
|
|
char assetidstr[64],*jsonstr; cJSON *json;
|
|
name[0] = 0;
|
|
if ( is_native_crypto(name,assetid) != 0 )
|
|
return((int32_t)strlen(name));
|
|
expand_nxt64bits(assetidstr,assetid);
|
|
name[0] = 0;
|
|
if ( (jsonstr= _issue_getAsset(assetidstr)) != 0 )
|
|
{
|
|
if ( (json= cJSON_Parse(jsonstr)) != 0 )
|
|
{
|
|
extract_cJSON_str(name,15,json,"name");
|
|
free_json(json);
|
|
}
|
|
free(jsonstr);
|
|
}
|
|
return((int32_t)strlen(assetidstr));
|
|
}
|
|
|
|
uint32_t get_blockutime(uint32_t blocknum)
|
|
{
|
|
cJSON *json;
|
|
uint32_t timestamp = 0;
|
|
char cmd[4096],*jsonstr;
|
|
sprintf(cmd,"requestType=getBlock&height=%u",blocknum);
|
|
if ( (jsonstr= issue_NXTPOST(cmd)) != 0 )
|
|
{
|
|
//printf("(%s) -> (%s)\n",cmd,jsonstr);
|
|
if ( (json= cJSON_Parse(jsonstr)) != 0 )
|
|
{
|
|
if ( (timestamp= juint(json,"timestamp")) != 0 )
|
|
timestamp += NXT_GENESISTIME;
|
|
free_json(json);
|
|
}
|
|
free(jsonstr);
|
|
}
|
|
return(timestamp);
|
|
}
|
|
|
|
uint64_t calc_decimals_mult(int32_t decimals)
|
|
{
|
|
int32_t i; uint64_t mult = 1;
|
|
for (i=7-decimals; i>=0; i--)
|
|
mult *= 10;
|
|
return(mult);
|
|
}
|
|
|
|
int32_t _set_assetname(uint64_t *multp,char *buf,char *jsonstr,uint64_t assetid)
|
|
{
|
|
int32_t type = 0,decimals = -1; cJSON *json=0; char assetidstr[64],*str;
|
|
*multp = 1;
|
|
buf[0] = 0;
|
|
if ( assetid != 0 )
|
|
{
|
|
//fprintf(stderr,"assetid.%llu\n",(long long)assetid);
|
|
if ( (str= is_MGWasset(assetid)) != 0 )
|
|
{
|
|
strcpy(buf,str);
|
|
return(0);
|
|
}
|
|
if ( is_native_crypto(buf,assetid) != 0 )
|
|
{
|
|
unstringbits(buf,assetid);
|
|
return(0);
|
|
}
|
|
}
|
|
if ( jsonstr == 0 )
|
|
{
|
|
if ( assetid == 0 )
|
|
printf("_set_assetname null assetid\n"), getchar();
|
|
expand_nxt64bits(assetidstr,assetid);
|
|
type = 2;
|
|
if ( (jsonstr= _issue_getAsset(assetidstr)) != 0 )
|
|
{
|
|
//printf("%llu (%s) -> (%s)\n",(long long)assetid,assetidstr,jsonstr);
|
|
if ( (json= cJSON_Parse(jsonstr)) != 0 )
|
|
{
|
|
if ( get_cJSON_int(json,"errorCode") != 0 )
|
|
{
|
|
free_json(json), free(jsonstr);
|
|
if ( (jsonstr= _issue_getCurrency(assetidstr)) != 0 )
|
|
{
|
|
//printf("(%s) -> (%s)\n",assetidstr,jsonstr);
|
|
if ( (json= cJSON_Parse(jsonstr)) != 0 )
|
|
{
|
|
if ( get_cJSON_int(json,"errorCode") != 0 )
|
|
{
|
|
printf("(%s) not asset and not currency (%s)\n",assetidstr,jsonstr);//, getchar();
|
|
free_json(json), free(jsonstr);
|
|
return(-1);
|
|
}
|
|
type = 5;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
free(jsonstr), jsonstr = 0;
|
|
} else return(-1);
|
|
}
|
|
if ( multp != 0 )
|
|
*multp = 0;
|
|
if ( json == 0 )
|
|
json = cJSON_Parse(jsonstr);
|
|
if ( json != 0 )
|
|
{
|
|
if ( get_cJSON_int(json,"errorCode") == 0 )
|
|
{
|
|
decimals = (int32_t)get_cJSON_int(json,"decimals");
|
|
if ( multp != 0 && decimals >= 0 && decimals <= 8 )
|
|
*multp = calc_decimals_mult(decimals);
|
|
if ( extract_cJSON_str(buf,16,json,"name") <= 0 )
|
|
decimals = -1;
|
|
//printf("%s decimals.%d (%s)\n",assetidstr,decimals,buf);
|
|
}
|
|
free_json(json);
|
|
}
|
|
return(type);
|
|
}
|
|
|
|
char *peggy_mapname(char *basebuf,char *relbuf,int32_t i) // sorry it is messy thing
|
|
{
|
|
char *base,*rel,buf[16];
|
|
base = rel = 0;
|
|
strcpy(buf,peggy_contracts[i]);
|
|
base = buf, rel = "BTCD";
|
|
if ( strlen(buf) > 3 && strcmp(buf+strlen(buf)-3,"USD") == 0 )
|
|
{
|
|
if ( strcmp(buf,"BTCUSD") == 0 )
|
|
base = "BTC";
|
|
buf[strlen(buf)-3] = 0;
|
|
}
|
|
else if ( strcmp(buf,"Copper") == 0 || strcmp(buf,"NGAS") == 0 || strcmp(buf,"UKOil") == 0 || strcmp(buf,"USOil") == 0 || strcmp(buf,"US30") == 0 || strcmp(buf,"SPX500") == 0 || strcmp(buf,"NAS100") == 0 )
|
|
rel = "USD";
|
|
else if ( strcmp(buf,"Bund") == 0 )
|
|
rel = "yield";
|
|
else if ( strcmp(buf,"EUSTX50") == 0 )
|
|
rel = "EUR";
|
|
else if ( strcmp(buf,"JPN225") == 0 )
|
|
rel = "JPY";
|
|
else if ( strcmp(buf,"UK100") == 0 )
|
|
rel = "GBP";
|
|
else if ( strcmp(buf,"GER30") == 0 )
|
|
rel = "EUR";
|
|
else if ( strcmp(buf,"SUI30") == 0 )
|
|
rel = "CHF";
|
|
else if ( strcmp(buf,"AUS200") == 0 )
|
|
rel = "AUD";
|
|
else if ( strcmp(buf,"HKG33") == 0 )
|
|
rel = "HKD";
|
|
else if ( strlen(buf) > 3 && strcmp(buf+strlen(buf)-3,"BTC") == 0 )
|
|
base = buf, buf[strlen(buf)-3] = 0;
|
|
if ( i == sizeof(peggy_contracts)/sizeof(*peggy_contracts)-1 && strcmp(peggy_contracts[i],"BTCUSD") == 0 )
|
|
base = "BTC", rel = "USD";
|
|
else if ( i == sizeof(peggy_contracts)/sizeof(*peggy_contracts)-2 && strcmp(peggy_contracts[i],"BTCCNY") == 0 )
|
|
base = "BTC", rel = "CNY";
|
|
else if ( i == sizeof(peggy_contracts)/sizeof(*peggy_contracts)-3 && strcmp(peggy_contracts[i],"BTCRUB") == 0 )
|
|
base = "BTC", rel = "RUB";
|
|
else if ( i == sizeof(peggy_contracts)/sizeof(*peggy_contracts)-4 && strcmp(peggy_contracts[i],"XAUUSD") == 0 )
|
|
base = "XAU", rel = "USD";
|
|
else if ( i == 0 )
|
|
base = "BTCD", rel = "maincurrency peggy, price is BTCD/BTC for info only";
|
|
basebuf[0] = relbuf[0] = 0;
|
|
if ( rel != 0 )
|
|
strcpy(relbuf,rel);//, printf("rel.(%s) ",rel);
|
|
if ( base != 0 )
|
|
strcpy(basebuf,base);//, printf("base.(%s) ",base);
|
|
return(basebuf);
|
|
}
|
|
|
|
uint64_t peggy_basebits(char *name)
|
|
{
|
|
int32_t i; char basebuf[64],relbuf[64];
|
|
for (i=0; i<64; i++)
|
|
{
|
|
if ( strcmp(name,peggy_contracts[i]) == 0 )
|
|
{
|
|
peggy_mapname(basebuf,relbuf,i);
|
|
return(stringbits(basebuf));
|
|
}
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
uint64_t peggy_relbits(char *name)
|
|
{
|
|
int32_t i; char basebuf[64],relbuf[64];
|
|
for (i=0; i<64; i++)
|
|
{
|
|
if ( strcmp(name,peggy_contracts[i]) == 0 )
|
|
{
|
|
peggy_mapname(basebuf,relbuf,i);
|
|
return(stringbits(relbuf));
|
|
}
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
int32_t prices777_key(char *key,char *exchange,char *name,char *base,uint64_t baseid,char *rel,uint64_t relid)
|
|
{
|
|
int32_t len,keysize = 0;
|
|
memcpy(&key[keysize],&baseid,sizeof(baseid)), keysize += sizeof(baseid);
|
|
memcpy(&key[keysize],&relid,sizeof(relid)), keysize += sizeof(relid);
|
|
strcpy(&key[keysize],exchange), keysize += strlen(exchange) + 1;
|
|
strcpy(&key[keysize],name), keysize += strlen(name) + 1;
|
|
memcpy(&key[keysize],base,strlen(base)+1), keysize += strlen(base) + 1;
|
|
if ( rel != 0 && (len= (int32_t)strlen(rel)) > 0 )
|
|
memcpy(&key[keysize],rel,len+1), keysize += len+1;
|
|
return(keysize);
|
|
}
|
|
|
|
uint64_t InstantDEX_name(char *key,int32_t *keysizep,char *exchange,char *name,char *base,uint64_t *baseidp,char *rel,uint64_t *relidp)
|
|
{
|
|
uint64_t baseid,relid,assetbits = 0; char *s,*str;
|
|
baseid = *baseidp, relid = *relidp;
|
|
//printf(">>>>>> name.(%s) (%s/%s) %llu/%llu\n",name,base,rel,(long long)baseid,(long long)relid);
|
|
if ( strcmp(base,"5527630") == 0 || baseid == 5527630 )
|
|
strcpy(base,"NXT");
|
|
if ( strcmp(rel,"5527630") == 0 || relid == 5527630 )
|
|
strcpy(rel,"NXT");
|
|
if ( relid == 0 && rel[0] != 0 )
|
|
{
|
|
if ( is_decimalstr(rel) != 0 )
|
|
relid = calc_nxt64bits(rel);
|
|
else relid = is_MGWcoin(rel);
|
|
}
|
|
else if ( (str= is_MGWasset(relid)) != 0 )
|
|
strcpy(rel,str);
|
|
if ( baseid == 0 && base[0] != 0 )
|
|
{
|
|
if ( is_decimalstr(base) != 0 )
|
|
baseid = calc_nxt64bits(base);
|
|
else baseid = is_MGWcoin(base);
|
|
}
|
|
else if ( (str= is_MGWasset(baseid)) != 0 )
|
|
strcpy(base,str);
|
|
if ( strcmp("InstantDEX",exchange) == 0 || strcmp("nxtae",exchange) == 0 || strcmp("unconf",exchange) == 0 || (baseid != 0 && relid != 0) )
|
|
{
|
|
if ( strcmp(rel,"NXT") == 0 )
|
|
s = "+", relid = stringbits("NXT"), strcpy(rel,"NXT");
|
|
else if ( strcmp(base,"NXT") == 0 )
|
|
s = "-", baseid = stringbits("NXT"), strcpy(base,"NXT");
|
|
else s = "";
|
|
if ( base[0] == 0 )
|
|
{
|
|
get_assetname(base,baseid);
|
|
//printf("mapped %llu -> (%s)\n",(long long)baseid,base);
|
|
}
|
|
if ( rel[0] == 0 )
|
|
{
|
|
get_assetname(rel,relid);
|
|
//printf("mapped %llu -> (%s)\n",(long long)relid,rel);
|
|
}
|
|
if ( name[0] == 0 )
|
|
{
|
|
if ( relid == NXT_ASSETID )
|
|
sprintf(name,"%llu",(long long)baseid);
|
|
else if ( baseid == NXT_ASSETID )
|
|
sprintf(name,"-%llu",(long long)relid);
|
|
else sprintf(name,"%llu/%llu",(long long)baseid,(long long)relid);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ( base[0] != 0 && rel[0] != 0 && baseid == 0 && relid == 0 )
|
|
{
|
|
baseid = peggy_basebits(base), relid = peggy_basebits(rel);
|
|
if ( name[0] == 0 && baseid != 0 && relid != 0 )
|
|
{
|
|
strcpy(name,base); // need to be smarter
|
|
strcat(name,"/");
|
|
strcat(name,rel);
|
|
}
|
|
}
|
|
if ( name[0] == 0 || baseid == 0 || relid == 0 || base[0] == 0 || rel[0] == 0 )
|
|
{
|
|
if ( baseid == 0 && base[0] != 0 )
|
|
baseid = stringbits(base);
|
|
else if ( baseid != 0 && base[0] == 0 )
|
|
sprintf(base,"%llu",(long long)baseid);
|
|
if ( relid == 0 && rel[0] != 0 )
|
|
{
|
|
relid = stringbits(rel);
|
|
printf("set relid.%llu <- (%s)\n",(long long)relid,rel);
|
|
}
|
|
else if ( relid != 0 && rel[0] == 0 )
|
|
sprintf(rel,"%llu",(long long)relid);
|
|
if ( name[0] == 0 )
|
|
strcpy(name,base), strcat(name,"/"), strcat(name,rel);
|
|
}
|
|
}
|
|
*baseidp = baseid, *relidp = relid;
|
|
*keysizep = prices777_key(key,exchange,name,base,baseid,rel,relid);
|
|
//printf("<<<<<<< name.(%s) (%s/%s) %llu/%llu\n",name,base,rel,(long long)baseid,(long long)relid);
|
|
return(assetbits);
|
|
}
|
|
|
|
int32_t create_basketitem(struct prices777_basket *basketitem,cJSON *item,char *refbase,char *refrel,int32_t basketsize)
|
|
{
|
|
struct destbuf exchangestr,name,base,rel; char key[512]; uint64_t tmp,baseid,relid; int32_t groupid,keysize,valid; double wt; struct prices777 *prices;
|
|
copy_cJSON(&exchangestr,jobj(item,"exchange"));
|
|
if ( strcmp("jumblr",exchangestr.buf) == 0 || strcmp("pangea",exchangestr.buf) == 0 || strcmp("wallet",exchangestr.buf) == 0 || exchange_find(exchangestr.buf) == 0 )
|
|
{
|
|
printf("create_basketitem: illegal exchange.%s\n",exchangestr.buf);
|
|
return(-1);
|
|
}
|
|
copy_cJSON(&name,jobj(item,"name"));
|
|
copy_cJSON(&base,jobj(item,"base"));
|
|
copy_cJSON(&rel,jobj(item,"rel"));
|
|
if ( (baseid= j64bits(item,"baseid")) != 0 && base.buf[0] == 0 )
|
|
{
|
|
_set_assetname(&tmp,base.buf,0,baseid);
|
|
//printf("GOT.(%s) <- %llu\n",base.buf,(long long)baseid);
|
|
}
|
|
else if ( baseid == 0 )
|
|
baseid = stringbits(base.buf);
|
|
if ( (relid= j64bits(item,"relid")) != 0 && rel.buf[0] == 0 )
|
|
{
|
|
_set_assetname(&tmp,rel.buf,0,relid);
|
|
//printf("GOT.(%s) <- %llu\n",rel.buf,(long long)relid);
|
|
}
|
|
else if ( relid == 0 )
|
|
relid = stringbits(rel.buf);
|
|
groupid = juint(item,"group");
|
|
wt = jdouble(item,"wt");
|
|
if ( wt == 0. )
|
|
wt = 1.;
|
|
if ( strcmp(refbase,rel.buf) == 0 || strcmp(refrel,base.buf) == 0 )
|
|
{
|
|
if ( wt != -1 )
|
|
{
|
|
printf("need to flip wt %f for (%s/%s) ref.(%s/%s)\n",wt,base.buf,rel.buf,refbase,refrel);
|
|
wt = -1.;
|
|
}
|
|
}
|
|
else if ( wt != 1. )
|
|
{
|
|
printf("need to flip wt %f for (%s/%s) ref.(%s/%s)\n",wt,base.buf,rel.buf,refbase,refrel);
|
|
wt = 1.;
|
|
}
|
|
if ( name.buf[0] == 0 )
|
|
sprintf(name.buf,"%s/%s",base.buf,rel.buf);
|
|
if ( base.buf[0] == 0 )
|
|
strcpy(base.buf,refbase);
|
|
if ( rel.buf[0] == 0 )
|
|
strcpy(rel.buf,refrel);
|
|
InstantDEX_name(key,&keysize,exchangestr.buf,name.buf,base.buf,&baseid,rel.buf,&relid);
|
|
printf(">>>>>>>>>> create basketitem.(%s) name.(%s) %s (%s/%s) %llu/%llu wt %f\n",jprint(item,0),name.buf,exchangestr.buf,base.buf,rel.buf,(long long)baseid,(long long)relid,wt);
|
|
if ( (prices= prices777_initpair(1,exchangestr.buf,base.buf,rel.buf,0.,name.buf,baseid,relid,basketsize)) != 0 )
|
|
{
|
|
prices777_addbundle(&valid,0,prices,0,0,0);
|
|
basketitem->prices = prices;
|
|
basketitem->wt = wt;
|
|
basketitem->groupid = groupid;
|
|
strcpy(basketitem->base,base.buf);
|
|
strcpy(basketitem->rel,rel.buf);
|
|
return(0);
|
|
} else printf("couldnt create basketitem\n");
|
|
return(-1);
|
|
}
|
|
|
|
struct prices777 *prices777_makebasket(char *basketstr,cJSON *_basketjson,int32_t addbasket,char *typestr,struct prices777 *ptrs[],int32_t num)
|
|
{
|
|
//{"name":"NXT/BTC","base":"NXT","rel":"BTC","basket":[{"exchange":"poloniex"},{"exchange":"btc38"}]}
|
|
int32_t i,j,n,keysize,valid,basketsize,total = 0; struct destbuf refname,refbase,refrel; char key[8192]; uint64_t refbaseid=0,refrelid=0;
|
|
struct prices777_basket *basketitem,*basket = 0; cJSON *basketjson,*array,*item; struct prices777 *prices = 0;
|
|
if ( (basketjson= _basketjson) == 0 && (basketjson= cJSON_Parse(basketstr)) == 0 )
|
|
{
|
|
printf("cant parse basketstr.(%s)\n",basketstr);
|
|
return(0);
|
|
}
|
|
copy_cJSON(&refname,jobj(basketjson,"name"));
|
|
copy_cJSON(&refbase,jobj(basketjson,"base"));
|
|
copy_cJSON(&refrel,jobj(basketjson,"rel"));
|
|
refbaseid = j64bits(basketjson,"baseid");
|
|
refrelid = j64bits(basketjson,"relid");
|
|
if ( (array= jarray(&n,basketjson,"basket")) != 0 )
|
|
{
|
|
printf("MAKE/(%s) n.%d num.%d\n",jprint(basketjson,0),n,num);
|
|
basketsize = (n + num);
|
|
basket = calloc(1,sizeof(*basket) * basketsize);
|
|
for (i=0; i<n; i++)
|
|
{
|
|
item = jitem(array,i);
|
|
if ( create_basketitem(&basket[total],item,refbase.buf,refrel.buf,basketsize) < 0 )
|
|
printf("warning: >>>>>>>>>>>> skipped create_basketitem %d of %d of %d\n",i,n,basketsize);
|
|
else
|
|
{
|
|
printf("MAKE.%d: (%s) %p.%s\n",total,jprint(item,0),basket[total].prices,basket[total].prices->exchange);
|
|
total++;
|
|
}
|
|
}
|
|
if ( ptrs != 0 && num > 0 )
|
|
{
|
|
for (i=0; i<num; i++)
|
|
{
|
|
basketitem = &basket[total];
|
|
j = 0;
|
|
if ( total > 0 )
|
|
{
|
|
for (j=0; j<n+i; j++)
|
|
{
|
|
if ( basket[j].prices == ptrs[i] )
|
|
{
|
|
printf("skip duplicate basket[%d] == ptrs[%d]\n",j,i);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if ( j == n+i )
|
|
{
|
|
basketitem->prices = ptrs[i];
|
|
if ( strcmp(refbase.buf,ptrs[i]->rel) == 0 || strcmp(refrel.buf,ptrs[i]->base) == 0 )
|
|
basketitem->wt = -1;
|
|
else basketitem->wt = 1;
|
|
basketitem->groupid = 0;
|
|
strcpy(basketitem->base,ptrs[i]->base);
|
|
strcpy(basketitem->rel,ptrs[i]->rel);
|
|
total++;
|
|
printf("extrai.%d/%d total.%d wt.%f (%s/%s).%s\n",i,num,total,basketitem->wt,ptrs[i]->base,ptrs[i]->rel,ptrs[i]->exchange);
|
|
}
|
|
}
|
|
}
|
|
printf(">>>>> addbasket.%d (%s/%s).%s %llu %llu\n",addbasket,refbase.buf,refrel.buf,typestr,(long long)refbaseid,(long long)refrelid);
|
|
InstantDEX_name(key,&keysize,typestr,refname.buf,refbase.buf,&refbaseid,refrel.buf,&refrelid);
|
|
printf(">>>>> addbasket.%d (%s/%s).%s %llu %llu\n",addbasket,refbase.buf,refrel.buf,typestr,(long long)refbaseid,(long long)refrelid);
|
|
if ( addbasket != 0 )
|
|
{
|
|
prices777_addbundle(&valid,0,0,typestr,refbaseid,refrelid);
|
|
printf("<<<<< created.%s valid.%d refname.(%s) (%s/%s).%s %llu %llu\n",typestr,valid,refname.buf,refbase.buf,refrel.buf,typestr,(long long)refbaseid,(long long)refrelid);
|
|
} else valid = 0;
|
|
if ( valid >= 0 )
|
|
{
|
|
if ( (prices= prices777_createbasket(addbasket,refname.buf,refbase.buf,refrel.buf,refbaseid,refrelid,basket,total,typestr)) != 0 )
|
|
{
|
|
if ( addbasket != 0 )
|
|
BUNDLE.ptrs[BUNDLE.num] = prices;
|
|
prices->lastprice = prices777_basket(prices,MAX_DEPTH);
|
|
//printf("C.bsize.%d total polling.%d added.(%s/%s).%s updating basket lastprice %f changed.%p %d groupsize.%d numgroups.%d %p\n",total,BUNDLE.num,prices->base,prices->rel,prices->exchange,prices->lastprice,&prices->changed,prices->changed,prices->basket[0].groupsize,prices->numgroups,&prices->basket[0].groupsize);
|
|
BUNDLE.num++;
|
|
}
|
|
} else prices = 0;
|
|
if ( basketjson != _basketjson )
|
|
free_json(basketjson);
|
|
free(basket);
|
|
}
|
|
return(prices);
|
|
}
|
|
|
|
cJSON *inner_json(double price,double vol,uint32_t timestamp,uint64_t quoteid,uint64_t nxt64bits,uint64_t qty,uint64_t pqt,uint64_t baseamount,uint64_t relamount)
|
|
{
|
|
cJSON *inner = cJSON_CreateArray();
|
|
char numstr[64];
|
|
sprintf(numstr,"%.8f",price), cJSON_AddItemToArray(inner,cJSON_CreateString(numstr));
|
|
sprintf(numstr,"%.8f",vol), cJSON_AddItemToArray(inner,cJSON_CreateString(numstr));
|
|
sprintf(numstr,"%llu",(long long)quoteid), cJSON_AddItemToArray(inner,cJSON_CreateString(numstr));
|
|
cJSON_AddItemToArray(inner,cJSON_CreateNumber(timestamp));
|
|
sprintf(numstr,"%llu",(long long)nxt64bits), cJSON_AddItemToArray(inner,cJSON_CreateString(numstr));
|
|
sprintf(numstr,"%llu",(long long)qty), cJSON_AddItemToArray(inner,cJSON_CreateString(numstr));
|
|
sprintf(numstr,"%llu",(long long)pqt), cJSON_AddItemToArray(inner,cJSON_CreateString(numstr));
|
|
sprintf(numstr,"%llu",(long long)baseamount), cJSON_AddItemToArray(inner,cJSON_CreateString(numstr));
|
|
sprintf(numstr,"%llu",(long long)relamount), cJSON_AddItemToArray(inner,cJSON_CreateString(numstr));
|
|
// printf("(%s) ",jprint(inner,0));
|
|
return(inner);
|
|
}
|
|
|
|
double prices777_NXT(struct prices777 *prices,int32_t maxdepth)
|
|
{
|
|
uint32_t timestamp; int32_t flip,i,n; uint64_t baseamount,relamount,qty,pqt; char url[1024],*str,*cmd,*field;
|
|
cJSON *json,*bids,*asks,*srcobj,*item,*array; double price,vol,hbla = 0.;
|
|
if ( NXT_ASSETID != stringbits("NXT") || (strcmp(prices->rel,"NXT") != 0 && strcmp(prices->rel,"5527630") != 0) )
|
|
{
|
|
printf("NXT_ASSETID.%llu != %llu stringbits rel.%s\n",(long long)NXT_ASSETID,(long long)stringbits("NXT"),prices->rel);//, getchar();
|
|
return(0);
|
|
}
|
|
bids = cJSON_CreateArray(), asks = cJSON_CreateArray();
|
|
for (flip=0; flip<2; flip++)
|
|
{
|
|
/*{
|
|
"offer": "16959774565785265980",
|
|
"expirationHeight": 1000000,
|
|
"accountRS": "NXT-QFAF-GR4F-RBSR-AXW2G",
|
|
"limit": "9000000",
|
|
"currency": "5775213290661997199",
|
|
"supply": "0",
|
|
"account": "9728792749189838093",
|
|
"height": 348856,
|
|
"rateNQT": "650"
|
|
}*/
|
|
if ( prices->type != 5 )
|
|
{
|
|
if ( flip == 0 )
|
|
cmd = "getBidOrders", field = "bidOrders", array = bids;
|
|
else cmd = "getAskOrders", field = "askOrders", array = asks;
|
|
sprintf(url,"requestType=%s&asset=%llu&limit=%d",cmd,(long long)prices->baseid,maxdepth);
|
|
}
|
|
else
|
|
{
|
|
if ( flip == 0 )
|
|
cmd = "getBuyOffers", field = "offers", array = bids;
|
|
else cmd = "getSellOffers", field = "offers", array = asks;
|
|
sprintf(url,"requestType=%s¤cy=%llu&limit=%d",cmd,(long long)prices->baseid,maxdepth);
|
|
}
|
|
if ( (str= issue_NXTPOST(url)) != 0 )
|
|
{
|
|
//printf("{%s}\n",str);
|
|
if ( (json= cJSON_Parse(str)) != 0 )
|
|
{
|
|
if ( (srcobj= jarray(&n,json,field)) != 0 )
|
|
{
|
|
for (i=0; i<n && i<maxdepth; i++)
|
|
{
|
|
/*
|
|
"quantityQNT": "79",
|
|
"priceNQT": "13499000000",
|
|
"transactionHeight": 480173,
|
|
"accountRS": "NXT-FJQN-8QL2-BMY3-64VLK",
|
|
"transactionIndex": 1,
|
|
"asset": "15344649963748848799",
|
|
"type": "ask",
|
|
"account": "5245394173527769812",
|
|
"order": "17926122097022414596",
|
|
"height": 480173
|
|
*/
|
|
item = cJSON_GetArrayItem(srcobj,i);
|
|
if ( prices->type != 5 )
|
|
qty = j64bits(item,"quantityQNT"), pqt = j64bits(item,"priceNQT");
|
|
else qty = j64bits(item,"limit"), pqt = j64bits(item,"rateNQT");
|
|
baseamount = (qty * prices->ap_mult), relamount = (qty * pqt);
|
|
price = prices777_price_volume(&vol,baseamount,relamount);
|
|
if ( i == 0 )
|
|
{
|
|
hbla = (hbla == 0.) ? price : 0.5 * (price + hbla);
|
|
if ( flip == 0 )
|
|
prices->lastbid = price;
|
|
else prices->lastask = price;
|
|
}
|
|
//printf("(%llu %llu) %f %f mult.%llu qty.%llu pqt.%llu baseamount.%lld relamount.%lld\n",(long long)prices->baseid,(long long)prices->relid,price,vol,(long long)prices->ap_mult,(long long)qty,(long long)pqt,(long long)baseamount,(long long)relamount);
|
|
timestamp = get_blockutime(juint(item,"height"));
|
|
item = inner_json(price,vol,timestamp,j64bits(item,prices->type != 5 ? "order" : "offer"),j64bits(item,"account"),qty,pqt,baseamount,relamount);
|
|
cJSON_AddItemToArray(array,item);
|
|
}
|
|
}
|
|
free_json(json);
|
|
}
|
|
free(str);
|
|
} else printf("cant get.(%s)\n",url);
|
|
}
|
|
json = cJSON_CreateObject();
|
|
cJSON_AddItemToObject(json,"bids",bids);
|
|
cJSON_AddItemToObject(json,"asks",asks);
|
|
if ( Debuglevel > 2 )
|
|
printf("NXTAE.(%s)\n",jprint(json,0));
|
|
prices777_json_orderbook("nxtae",prices,maxdepth,json,0,"bids","asks",0,0);
|
|
free_json(json);
|
|
return(hbla);
|
|
}
|
|
|
|
double prices777_unconfNXT(struct prices777 *prices,int32_t maxdepth)
|
|
{
|
|
struct destbuf account,txidstr,comment,recipient; char url[1024],*str; uint32_t timestamp; int32_t type,i,subtype,n;
|
|
cJSON *json,*bids,*asks,*array,*txobj,*attachment;
|
|
double price,vol; uint64_t assetid,accountid,quoteid,baseamount,relamount,qty,priceNQT,amount;
|
|
bids = cJSON_CreateArray(), asks = cJSON_CreateArray();
|
|
prices->lastbid = prices->lastask = 0.;
|
|
prices->O.numbids = prices->O.numasks = 0;
|
|
sprintf(url,"requestType=getUnconfirmedTransactions");
|
|
if ( IGUANA_disableNXT == 0 && (str= issue_NXTPOST(url)) != 0 )
|
|
{
|
|
//printf("{%s}\n",str);
|
|
if ( (json= cJSON_Parse(str)) != 0 )
|
|
{
|
|
if ( (array= jarray(&n,json,"unconfirmedTransactions")) != 0 )
|
|
{
|
|
for (i=0; i<n; i++)
|
|
{
|
|
//{"senderPublicKey":"45c9266036e705a9559ccbd2b2c92b28ea6363d2723e8d42433b1dfaa421066c","signature":"9d6cefff4c67f8cf4e9487122e5e6b1b65725815127063df52e9061036e78c0b49ba38dbfc12f03c158697f0af5811ce9398702c4acb008323df37dc55c1b43d","feeNQT":"100000000","type":2,"fullHash":"6a2cd914b9d4a5d8ebfaecaba94ef4e7d2b681c236a4bee56023aafcecd9b704","version":1,"phased":false,"ecBlockId":"887016880740444200","signatureHash":"ba8eee4beba8edbb6973df4243a94813239bf57b91cac744cb8d6a5d032d5257","attachment":{"quantityQNT":"50","priceNQT":"18503000003","asset":"13634675574519917918","version.BidOrderPlacement":1},"senderRS":"NXT-FJQN-8QL2-BMY3-64VLK","subtype":3,"amountNQT":"0","sender":"5245394173527769812","ecBlockHeight":495983,"deadline":1440,"transaction":"15611117574733507690","timestamp":54136768,"height":2147483647},{"senderPublicKey":"c42956d0a9abc5a2e455e69c7e65ff9a53de2b697e913b25fcb06791f127af06","signature":"ca2c3f8e32d3aa003692fef423193053c751235a25eb5b67c21aefdeb7a41d0d37bc084bd2e33461606e25f09ced02d1e061420da7e688306e76de4d4cf90ae0","feeNQT":"100000000","type":2,"fullHash":"51c04de7106a5d5a2895db05305b53dd33fa8b9935d549f765aa829a23c68a6b","version":1,"phased":false,"ecBlockId":"887016880740444200","signatureHash":"d76fce4c081adc29f7e60eba2a930ab5050dd79b6a1355fae04863dddf63730c","attachment":{"version.AskOrderPlacement":1,"quantityQNT":"11570","priceNQT":"110399999","asset":"979292558519844732"},"senderRS":"NXT-ANWW-C5BZ-SGSB-8LGZY","subtype":2,"amountNQT":"0","sender":"8033808554894054300","ecBlockHeight":495983,"deadline":1440,"transaction":"6511477257080258641","timestamp":54136767,"height":2147483647}],"requestProcessingTime":0}
|
|
|
|
/* "senderRS": "NXT-M6QF-Q5WK-2UXK-5D3HR",
|
|
"subtype": 0,
|
|
"amountNQT": "137700000000",
|
|
"sender": "4304363382952792781",
|
|
"recipientRS": "NXT-6AC7-V9BD-NL5W-5BUWF",
|
|
"recipient": "3959589697280418117",
|
|
"ecBlockHeight": 506207,
|
|
"deadline": 1440,
|
|
"transaction": "5605109208989354417",
|
|
"timestamp": 55276659,
|
|
"height": 2147483647*/
|
|
if ( (txobj= jitem(array,i)) == 0 )
|
|
continue;
|
|
copy_cJSON(&txidstr,cJSON_GetObjectItem(txobj,"transaction"));
|
|
copy_cJSON(&recipient,cJSON_GetObjectItem(txobj,"recipient"));
|
|
copy_cJSON(&account,cJSON_GetObjectItem(txobj,"account"));
|
|
if ( account.buf[0] == 0 )
|
|
copy_cJSON(&account,cJSON_GetObjectItem(txobj,"sender"));
|
|
accountid = calc_nxt64bits(account.buf);
|
|
type = (int32_t)get_API_int(cJSON_GetObjectItem(txobj,"type"),-1);
|
|
subtype = (int32_t)get_API_int(cJSON_GetObjectItem(txobj,"subtype"),-1);
|
|
timestamp = juint(txobj,"timestamp");
|
|
amount = get_API_nxt64bits(cJSON_GetObjectItem(txobj,"amountNQT"));
|
|
qty = amount = assetid = 0;
|
|
if ( (attachment= cJSON_GetObjectItem(txobj,"attachment")) != 0 )
|
|
{
|
|
assetid = get_API_nxt64bits(cJSON_GetObjectItem(attachment,"asset"));
|
|
comment.buf[0] = 0;
|
|
qty = get_API_nxt64bits(cJSON_GetObjectItem(attachment,"quantityQNT"));
|
|
priceNQT = get_API_nxt64bits(cJSON_GetObjectItem(attachment,"priceNQT"));
|
|
baseamount = (qty * prices->ap_mult), relamount = (qty * priceNQT);
|
|
copy_cJSON(&comment,jobj(attachment,"message"));
|
|
if ( comment.buf[0] != 0 )
|
|
{
|
|
int32_t match_unconfirmed(char *sender,char *hexstr,cJSON *txobj,char *txidstr,char *account,uint64_t amount,uint64_t qty,uint64_t assetid,char *recipient);
|
|
//printf("sender.%s -> recv.(%s)\n",account,recipient);
|
|
match_unconfirmed(account.buf,comment.buf,txobj,txidstr.buf,account.buf,amount,qty,assetid,recipient.buf);
|
|
}
|
|
quoteid = calc_nxt64bits(txidstr.buf);
|
|
price = prices777_price_volume(&vol,baseamount,relamount);
|
|
if ( prices->baseid == assetid )
|
|
{
|
|
if ( Debuglevel > 2 )
|
|
printf("unconf.%d subtype.%d %s %llu (%llu %llu) %f %f mult.%llu qty.%llu pqt.%llu baseamount.%lld relamount.%lld\n",i,subtype,txidstr.buf,(long long)prices->baseid,(long long)assetid,(long long)NXT_ASSETID,price,vol,(long long)prices->ap_mult,(long long)qty,(long long)priceNQT,(long long)baseamount,(long long)relamount);
|
|
if ( subtype == 2 )
|
|
{
|
|
array = bids;
|
|
prices->lastbid = price;
|
|
}
|
|
else if ( subtype == 3 )
|
|
{
|
|
array = asks;
|
|
prices->lastask = price;
|
|
}
|
|
cJSON_AddItemToArray(array,inner_json(price,vol,timestamp,quoteid,accountid,qty,priceNQT,baseamount,relamount));
|
|
}
|
|
}
|
|
}
|
|
free_json(json);
|
|
}
|
|
free(str);
|
|
} else printf("cant get.(%s)\n",url);
|
|
}
|
|
json = cJSON_CreateObject();
|
|
cJSON_AddItemToObject(json,"bids",bids);
|
|
cJSON_AddItemToObject(json,"asks",asks);
|
|
prices777_json_orderbook("unconf",prices,maxdepth,json,0,"bids","asks",0,0);
|
|
if ( Debuglevel > 2 )//|| prices->O.numbids != 0 || prices->O.numasks != 0 )
|
|
printf("%s %s/%s unconf.(%s) %f %f (%d %d)\n",prices->contract,prices->base,prices->rel,jprint(json,0),prices->lastbid,prices->lastask,prices->O.numbids,prices->O.numasks);
|
|
free_json(json);
|
|
return(_pairaved(prices->lastbid,prices->lastask));
|
|
}
|
|
|
|
double prices777_InstantDEX(struct prices777 *prices,int32_t maxdepth)
|
|
{
|
|
cJSON *json; double hbla = 0.;
|
|
if ( (json= InstantDEX_orderbook(prices)) != 0 ) // strcmp(prices->exchange,INSTANTDEX_NAME) == 0 &&
|
|
{
|
|
if ( Debuglevel > 2 )
|
|
printf("InstantDEX.(%s)\n",jprint(json,0));
|
|
prices777_json_orderbook("InstantDEX",prices,maxdepth,json,0,"bids","asks",0,0);
|
|
free_json(json);
|
|
}
|
|
return(hbla);
|
|
}
|
|
|
|
#define BASE_ISNXT 1
|
|
#define BASE_ISASSET 2
|
|
#define BASE_ISNAME 4
|
|
#define BASE_ISMGW 8
|
|
#define BASE_EXCHANGEASSET 16
|
|
|
|
int32_t calc_baseflags(char *exchange,char *base,uint64_t *baseidp)
|
|
{
|
|
char assetidstr[64],tmpstr[64],*str; uint64_t tmp; int32_t flags = 0;
|
|
exchange[0] = 0;
|
|
printf("calc_baseflags.(%s/%llu) ",base,(long long)*baseidp);
|
|
if ( strcmp(base,"NXT") == 0 || *baseidp == NXT_ASSETID )
|
|
strcpy(base,"NXT"), *baseidp = NXT_ASSETID, flags |= BASE_ISNXT;
|
|
else
|
|
{
|
|
if ( *baseidp == 0 )
|
|
{
|
|
if ( is_decimalstr(base) != 0 )
|
|
{
|
|
*baseidp = calc_nxt64bits(base), flags |= BASE_ISASSET;
|
|
unstringbits(tmpstr,*baseidp);
|
|
if ( (tmp= is_MGWcoin(tmpstr)) != 0 )
|
|
*baseidp = tmp, flags |= (BASE_EXCHANGEASSET | BASE_ISMGW);
|
|
else
|
|
{
|
|
printf("set base.(%s) -> %llu\n",base,(long long)*baseidp);
|
|
if ( (str= is_MGWasset(*baseidp)) != 0 )
|
|
strcpy(base,str), flags |= (BASE_EXCHANGEASSET | BASE_ISMGW);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
*baseidp = stringbits(base), flags |= BASE_ISNAME;
|
|
printf("stringbits.(%s) -> %llu\n",base,(long long)*baseidp);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ( (str= is_MGWasset(*baseidp)) != 0 )
|
|
{
|
|
printf("is MGWasset.(%s)\n",str);
|
|
strcpy(base,str), flags |= (BASE_EXCHANGEASSET | BASE_ISMGW | BASE_ISASSET);
|
|
}
|
|
else
|
|
{
|
|
expand_nxt64bits(assetidstr,*baseidp);
|
|
if ( (str= is_tradedasset(exchange,assetidstr)) != 0 )
|
|
{
|
|
strcpy(base,str), flags |= (BASE_EXCHANGEASSET | BASE_ISASSET);
|
|
printf("%s is tradedasset at (%s) %llu\n",assetidstr,str,(long long)*baseidp);
|
|
}
|
|
else
|
|
{
|
|
unstringbits(tmpstr,*baseidp);
|
|
if ( (tmp= is_MGWcoin(tmpstr)) != 0 )
|
|
strcpy(base,tmpstr), *baseidp = tmp, flags |= (BASE_EXCHANGEASSET | BASE_ISMGW | BASE_ISASSET);
|
|
else
|
|
{
|
|
_set_assetname(&tmp,base,0,*baseidp), flags |= BASE_ISASSET;
|
|
printf("_set_assetname.(%s) from %llu\n",base,(long long)*baseidp);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if ( (flags & (BASE_ISASSET|BASE_EXCHANGEASSET|BASE_ISMGW)) == 0 )
|
|
*baseidp = stringbits(base);
|
|
}
|
|
printf("-> flags.%d (%s %llu) %s\n",flags,base,(long long)*baseidp,exchange);
|
|
return(flags);
|
|
}
|
|
|
|
void setitemjson(cJSON *item,char *name,char *base,uint64_t baseid,char *rel,uint64_t relid)
|
|
{
|
|
char numstr[64];
|
|
jaddstr(item,"name",name), jaddstr(item,"base",base), jaddstr(item,"rel",rel);
|
|
sprintf(numstr,"%llu",(long long)baseid), jaddstr(item,"baseid",numstr);
|
|
sprintf(numstr,"%llu",(long long)relid), jaddstr(item,"relid",numstr);
|
|
}
|
|
|
|
int32_t nxt_basketjson(cJSON *array,int32_t groupid,int32_t polarity,char *base,uint64_t baseid,char *rel,uint64_t relid,char *refbase,char *refrel)
|
|
{
|
|
cJSON *item,*item2,*item3; char name[64]; int32_t dir = 0;
|
|
item = cJSON_CreateObject(), jaddstr(item,"exchange",INSTANTDEX_NXTAENAME);
|
|
item2 = cJSON_CreateObject(), jaddstr(item2,"exchange",INSTANTDEX_NXTAEUNCONF);
|
|
item3 = cJSON_CreateObject(), jaddstr(item3,"exchange",INSTANTDEX_NAME);
|
|
if ( strcmp(base,"NXT") == 0 )
|
|
{
|
|
sprintf(name,"%s/%s",rel,"NXT");
|
|
setitemjson(item,name,rel,relid,"NXT",NXT_ASSETID);
|
|
setitemjson(item2,name,rel,relid,"NXT",NXT_ASSETID);
|
|
setitemjson(item3,name,rel,relid,"NXT",NXT_ASSETID);
|
|
}
|
|
else if ( strcmp(rel,"NXT") == 0 )
|
|
{
|
|
sprintf(name,"%s/%s",base,"NXT");
|
|
setitemjson(item,name,base,baseid,"NXT",NXT_ASSETID);
|
|
setitemjson(item2,name,base,baseid,"NXT",NXT_ASSETID);
|
|
setitemjson(item3,name,base,baseid,"NXT",NXT_ASSETID);
|
|
}
|
|
else
|
|
{
|
|
free_json(item);
|
|
free_json(item2);
|
|
free_json(item3);
|
|
return(0);
|
|
}
|
|
if ( strcmp(refbase,rel) == 0 || strcmp(refrel,base) == 0 )
|
|
dir = -1;
|
|
else dir = 1;
|
|
jaddnum(item,"wt",dir), jaddnum(item2,"wt",dir), jaddnum(item3,"wt",dir);
|
|
jaddnum(item,"group",groupid), jaddnum(item2,"group",groupid), jaddnum(item3,"group",groupid);
|
|
printf("nxt_basketjson (%s/%s) %llu/%llu ref.(%s/%s) dir.%d polarity.%d\n",base,rel,(long long)baseid,(long long)relid,refbase,refrel,dir,polarity);
|
|
jaddi(array,item), jaddi(array,item2), jaddi(array,item3);
|
|
return(dir * polarity);
|
|
}
|
|
|
|
void add_nxtbtc(cJSON *array,int32_t groupid,double wt)
|
|
{
|
|
char *btcnxt_xchgs[] = { "poloniex", "bittrex", "btc38" };
|
|
int32_t i; cJSON *item;
|
|
if ( wt != 0 )
|
|
{
|
|
printf("add NXT/BTC\n");
|
|
for (i=0; i<sizeof(btcnxt_xchgs)/sizeof(*btcnxt_xchgs); i++)
|
|
{
|
|
item = cJSON_CreateObject(), jaddstr(item,"exchange",btcnxt_xchgs[i]);
|
|
setitemjson(item,"NXT/BTC","NXT",NXT_ASSETID,"BTC",BTC_ASSETID);
|
|
jaddnum(item,"wt",wt);
|
|
jaddnum(item,"group",groupid);
|
|
jaddi(array,item);
|
|
}
|
|
}
|
|
}
|
|
|
|
int32_t get_duplicates(uint64_t *duplicates,uint64_t baseid)
|
|
{
|
|
int32_t i,j,n = 0; char assetidstr[64],name[64]; uint64_t tmp;
|
|
unstringbits(name,baseid);
|
|
if ( (tmp= is_MGWcoin(name)) != 0 )
|
|
baseid = tmp;
|
|
else
|
|
{
|
|
for (i=0; i<(int32_t)(sizeof(Tradedassets)/sizeof(*Tradedassets)); i++)
|
|
if ( strcmp(Tradedassets[i][1],name) == 0 )
|
|
{
|
|
baseid = calc_nxt64bits(Tradedassets[i][0]);
|
|
printf("baseid.%llu <- (%s)\n",(long long)baseid,name);
|
|
}
|
|
}
|
|
expand_nxt64bits(assetidstr,baseid);
|
|
duplicates[n++] = baseid;
|
|
for (i=0; i<(int32_t)(sizeof(Tradedassets)/sizeof(*Tradedassets)); i++)
|
|
if ( strcmp(Tradedassets[i][0],assetidstr) == 0 )
|
|
{
|
|
for (j=0; j<(int32_t)(sizeof(Tradedassets)/sizeof(*Tradedassets)); j++)
|
|
{
|
|
if ( i != j && strcmp(Tradedassets[i][1],Tradedassets[j][1]) == 0 )
|
|
{
|
|
duplicates[n++] = calc_nxt64bits(Tradedassets[j][0]);
|
|
printf("found duplicate.%s\n",Tradedassets[j][0]);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
for (i=0; i<(int32_t)(sizeof(MGWassets)/sizeof(*MGWassets)); i++)
|
|
if ( strcmp(MGWassets[i][0],assetidstr) == 0 )
|
|
{
|
|
for (j=0; j<(int32_t)(sizeof(MGWassets)/sizeof(*MGWassets)); j++)
|
|
{
|
|
if ( i != j && strcmp(MGWassets[i][1],MGWassets[j][1]) == 0 )
|
|
duplicates[n++] = calc_nxt64bits(MGWassets[j][0]);
|
|
}
|
|
break;
|
|
}
|
|
return(n);
|
|
}
|
|
|
|
cJSON *make_arrayNXT(cJSON *directarray,cJSON **arrayBTCp,char *base,char *rel,uint64_t baseid,uint64_t relid)
|
|
{
|
|
cJSON *item,*arrayNXT = 0; char tmpstr[64],baseexchange[64],relexchange[64],*str;
|
|
int32_t wt,baseflags,relflags,i,j,n,m; uint64_t duplicatebases[16],duplicaterels[16];
|
|
baseflags = calc_baseflags(baseexchange,base,&baseid);
|
|
relflags = calc_baseflags(relexchange,rel,&relid);
|
|
sprintf(tmpstr,"%s/%s",base,rel);
|
|
printf("make_arrayNXT base.(%s) %llu rel.(%s) %llu baseflags.%d relflags.%d\n",base,(long long)baseid,rel,(long long)relid,baseflags,relflags);
|
|
item = cJSON_CreateObject(), setitemjson(item,tmpstr,base,baseid,rel,relid);
|
|
jaddstr(item,"exchange",INSTANTDEX_NAME);
|
|
jaddnum(item,"wt",1), jaddnum(item,"group",0), jaddi(directarray,item);
|
|
if ( ((baseflags | relflags) & BASE_ISNXT) != 0 )
|
|
{
|
|
printf("one is NXT\n");
|
|
if ( strcmp(base,"NXT") == 0 )
|
|
n = get_duplicates(duplicatebases,relid), wt = -1, str = rel;
|
|
else n = get_duplicates(duplicatebases,baseid), wt = 1, str = base;
|
|
sprintf(tmpstr,"%s/%s",str,"NXT");
|
|
for (i=0; i<n; i++)
|
|
nxt_basketjson(directarray,0,wt,str,duplicatebases[i],"NXT",NXT_ASSETID,base,rel);
|
|
}
|
|
else if ( (baseflags & BASE_ISASSET) != 0 && (relflags & BASE_ISASSET) != 0 )
|
|
{
|
|
printf("both are assets (%s/%s)\n",base,rel);
|
|
arrayNXT = cJSON_CreateArray();
|
|
n = get_duplicates(duplicatebases,baseid);
|
|
for (i=0; i<n; i++)
|
|
nxt_basketjson(arrayNXT,0,1,base,duplicatebases[i],"NXT",NXT_ASSETID,base,rel);
|
|
if ( strcmp(base,"BTC") == 0 )
|
|
add_nxtbtc(arrayNXT,0,-1);
|
|
sprintf(tmpstr,"%s/%s",rel,"NXT");
|
|
m = get_duplicates(duplicaterels,relid);
|
|
for (j=0; j<m; j++)
|
|
nxt_basketjson(arrayNXT,1,-1,rel,duplicaterels[j],"NXT",NXT_ASSETID,base,rel);
|
|
if ( strcmp(rel,"BTC") == 0 )
|
|
add_nxtbtc(arrayNXT,1,1);
|
|
}
|
|
if ( (baseflags & BASE_EXCHANGEASSET) != 0 || (relflags & BASE_EXCHANGEASSET) != 0 )
|
|
{
|
|
printf("have exchange asset %d %d\n",baseflags,relflags);
|
|
if ( (baseflags & BASE_EXCHANGEASSET) != 0 && (relflags & BASE_EXCHANGEASSET) != 0 )
|
|
{
|
|
printf("both are exchange asset\n");
|
|
if ( *arrayBTCp == 0 )
|
|
*arrayBTCp = cJSON_CreateArray();
|
|
if ( strcmp(base,"BTC") != 0 && strcmp(rel,"BTC") != 0 )
|
|
{
|
|
printf("a both are exchange asset\n");
|
|
item = cJSON_CreateObject(), jaddstr(item,"exchange",baseexchange);
|
|
sprintf(tmpstr,"%s/%s",base,"BTC");
|
|
setitemjson(item,tmpstr,base,baseid,"BTC",stringbits("BTC"));
|
|
jaddi(*arrayBTCp,item);
|
|
item = cJSON_CreateObject(), jaddstr(item,"exchange",relexchange);
|
|
sprintf(tmpstr,"%s/%s",rel,"BTC");
|
|
setitemjson(item,tmpstr,rel,relid,"BTC",stringbits("BTC"));
|
|
jaddnum(item,"wt",-1);
|
|
jaddnum(item,"group",1);
|
|
jaddi(*arrayBTCp,item);
|
|
}
|
|
}
|
|
else if ( (baseflags & BASE_EXCHANGEASSET) != 0 )
|
|
{
|
|
if ( strcmp(base,"BTC") != 0 && strcmp(rel,"BTC") == 0 )
|
|
{
|
|
printf("base.(%s/%s) is exchangeasset\n",base,rel);
|
|
item = cJSON_CreateObject(), jaddstr(item,"exchange",baseexchange);
|
|
sprintf(tmpstr,"%s/%s",base,"BTC");
|
|
setitemjson(item,tmpstr,base,baseid,"BTC",stringbits("BTC"));
|
|
jaddi(directarray,item);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ( strcmp(rel,"BTC") != 0 && strcmp(base,"BTC") == 0 )
|
|
{
|
|
printf("rel.(%s/%s) is exchangeasset\n",base,rel);
|
|
item = cJSON_CreateObject(), jaddstr(item,"exchange",relexchange);
|
|
sprintf(tmpstr,"%s/%s",rel,"BTC");
|
|
setitemjson(item,tmpstr,rel,relid,"BTC",stringbits("BTC"));
|
|
jaddnum(item,"wt",-1);
|
|
jaddi(directarray,item);
|
|
}
|
|
}
|
|
}
|
|
return(arrayNXT);
|
|
}
|
|
|
|
int32_t centralexchange_items(int32_t group,double wt,cJSON *array,char *_base,char *_rel,int32_t tradeable,char *refbase,char *refrel)
|
|
{
|
|
int32_t exchangeid,inverted,n = 0; char base[64],rel[64],name[64]; cJSON *item;
|
|
for (exchangeid=FIRST_EXTERNAL; exchangeid<MAX_EXCHANGES; exchangeid++)
|
|
{
|
|
strcpy(base,_base), strcpy(rel,_rel);
|
|
if ( Exchanges[exchangeid].name[0] == 0 )
|
|
break;
|
|
//printf("check %s for (%s/%s) group.%d wt.%f\n",Exchanges[exchangeid].name,base,rel,group,wt);
|
|
if ( Exchanges[exchangeid].issue.supports != 0 && (inverted= (*Exchanges[exchangeid].issue.supports)(base,rel)) != 0 && (tradeable == 0 || Exchanges[exchangeid].apikey[0] != 0|| Exchanges[exchangeid].apisecret[0] != 0) )
|
|
{
|
|
if ( array != 0 )
|
|
{
|
|
item = cJSON_CreateObject(), jaddstr(item,"exchange",Exchanges[exchangeid].name);
|
|
//printf("ref.(%s/%s) vs (%s/%s) inverted.%d flipped.%d\n",refbase,refrel,base,rel,inverted,strcmp(refbase,rel) == 0 || strcmp(refrel,base) == 0);
|
|
if ( inverted < 0 )
|
|
jaddstr(item,"base",rel), jaddstr(item,"rel",base), sprintf(name,"%s/%s",rel,base);
|
|
else jaddstr(item,"base",base), jaddstr(item,"rel",rel), sprintf(name,"%s/%s",base,rel);
|
|
if ( strcmp(refbase,rel) == 0 || strcmp(refrel,base) == 0 )
|
|
jaddnum(item,"wt",-inverted);
|
|
else jaddnum(item,"wt",inverted);
|
|
jaddstr(item,"name",name), jaddnum(item,"group",group);
|
|
printf("ADDED.%s inverted.%d (%s) ref.(%s/%s)\n",Exchanges[exchangeid].name,inverted,name,refbase,refrel);
|
|
jaddi(array,item);
|
|
}
|
|
n++;
|
|
} //else printf("%s doesnt support.(%s/%s)\n",Exchanges[exchangeid].name,base,rel);
|
|
}
|
|
return(n);
|
|
}
|
|
|
|
cJSON *external_combo(char *base,char *rel,char *coinstr,int32_t tradeable)
|
|
{
|
|
cJSON *array = 0;
|
|
printf("check central jumper.(%s) for (%s/%s)\n",coinstr,base,rel);
|
|
//if ( (baseflags & (BASE_ISNAME|BASE_ISMGW)) != 0 && (relflags & (BASE_ISNAME|BASE_ISMGW)) != 0 )
|
|
{
|
|
if ( strcmp(base,coinstr) != 0 && strcmp(rel,coinstr) != 0 && centralexchange_items(0,1,0,base,coinstr,tradeable,base,rel) > 0 && centralexchange_items(0,1,0,rel,coinstr,tradeable,base,rel) > 0 )
|
|
{
|
|
array = cJSON_CreateArray();
|
|
printf("add central jumper.(%s) for (%s/%s)\n",coinstr,base,rel);
|
|
centralexchange_items(0,1,array,base,coinstr,tradeable,base,rel);
|
|
centralexchange_items(1,-1,array,rel,coinstr,tradeable,base,rel);
|
|
}
|
|
}
|
|
return(array);
|
|
}
|
|
|
|
int32_t make_subactive(struct prices777 *baskets[],int32_t n,cJSON *array,char *prefix,char *base,char *rel,uint64_t baseid,uint64_t relid,int32_t maxdepth)
|
|
{
|
|
char tmpstr[64],typestr[64]; struct prices777 *basket; cJSON *basketjson;
|
|
basketjson = cJSON_CreateObject();
|
|
sprintf(tmpstr,"%s/%s",base,rel);
|
|
setitemjson(basketjson,tmpstr,base,baseid,rel,relid);
|
|
jadd(basketjson,"basket",array);
|
|
printf("%s BASKETMAKE.(%s)\n",prefix,jprint(basketjson,0));
|
|
sprintf(typestr,"basket%s",prefix);
|
|
if ( (basket= prices777_makebasket(0,basketjson,1,typestr,0,0)) != 0 )
|
|
{
|
|
prices777_basket(basket,maxdepth);
|
|
prices777_jsonstrs(basket,&basket->O);
|
|
printf("add to baskets[%d].%s (%s/%s) (%s)\n",n,basket->exchange,basket->base,basket->rel,basket->contract);
|
|
baskets[n++] = basket;
|
|
}
|
|
free_json(basketjson);
|
|
return(n);
|
|
}
|
|
|
|
char *prices777_activebooks(char *name,char *_base,char *_rel,uint64_t baseid,uint64_t relid,int32_t maxdepth,int32_t allflag,int32_t tradeable)
|
|
{
|
|
cJSON *array,*arrayNXT,*arrayBTC,*arrayUSD,*arrayCNY,*basketjson; struct prices777 *active,*basket,*baskets[64];
|
|
int32_t inverted,keysize,baseflags,relflags,n = 0; char tmpstr[64],base[64],rel[64],bexchange[64],rexchange[64],key[512],*retstr = 0;
|
|
memset(baskets,0,sizeof(baskets));
|
|
strcpy(base,_base), strcpy(rel,_rel);
|
|
baseflags = calc_baseflags(bexchange,base,&baseid);
|
|
relflags = calc_baseflags(rexchange,rel,&relid);
|
|
InstantDEX_name(key,&keysize,"active",name,base,&baseid,rel,&relid);
|
|
printf("activebooks (%s/%s) (%llu/%llu)\n",base,rel,(long long)baseid,(long long)relid);
|
|
if ( (active= prices777_find(&inverted,baseid,relid,"active")) == 0 )
|
|
{
|
|
if ( ((baseflags & BASE_ISMGW) != 0 || (baseflags & BASE_ISASSET) == 0) && ((relflags & BASE_ISMGW) != 0 || (relflags & BASE_ISASSET) == 0) )
|
|
{
|
|
if ( (arrayUSD= external_combo(base,rel,"USD",tradeable)) != 0 )
|
|
n = make_subactive(baskets,n,arrayUSD,"USD",base,rel,baseid,relid,maxdepth);
|
|
if ( (arrayCNY= external_combo(base,rel,"CNY",tradeable)) != 0 )
|
|
n = make_subactive(baskets,n,arrayCNY,"CNY",base,rel,baseid,relid,maxdepth);
|
|
}
|
|
arrayBTC = external_combo(base,rel,"BTC",tradeable);
|
|
basketjson = cJSON_CreateObject(), array = cJSON_CreateArray();
|
|
sprintf(tmpstr,"%s/%s",base,rel);
|
|
setitemjson(basketjson,tmpstr,base,baseid,rel,relid);
|
|
//if ( baseflags != BASE_ISASSET && relflags != BASE_ISASSET )
|
|
centralexchange_items(0,1,array,base,rel,tradeable,base,rel);
|
|
if ( (arrayNXT= make_arrayNXT(array,&arrayBTC,base,rel,baseid,relid)) != 0 )
|
|
n = make_subactive(baskets,n,arrayNXT,"NXT",base,rel,baseid,relid,maxdepth);
|
|
if ( arrayBTC != 0 )
|
|
n = make_subactive(baskets,n,arrayBTC,"BTC",base,rel,baseid,relid,maxdepth);
|
|
if ( (basket= prices777_find(&inverted,baseid,relid,"basket")) != 0 )
|
|
baskets[n++] = basket;
|
|
jadd(basketjson,"basket",array);
|
|
printf(" ACTIVE MAKE.(%s)\n",jprint(basketjson,0));
|
|
if ( (active= prices777_makebasket(0,basketjson,1,"active",baskets,n)) != 0 )
|
|
{
|
|
prices777_basket(active,maxdepth);
|
|
prices777_jsonstrs(active,&active->O);
|
|
}
|
|
free_json(array);
|
|
}
|
|
if ( active != 0 && retstr == 0 )
|
|
{
|
|
prices777_basket(active,maxdepth);
|
|
prices777_jsonstrs(active,&active->O);
|
|
if ( (retstr= active->orderbook_jsonstrs[inverted][allflag]) != 0 )
|
|
retstr = clonestr(retstr);
|
|
}
|
|
if ( retstr == 0 )
|
|
retstr = clonestr("{\"error\":\"null active orderbook\"}");
|
|
return(retstr);
|
|
}
|
|
|
|
cJSON *basketitem_json(struct prices777 *prices)
|
|
{
|
|
int32_t i; char numstr[64]; cJSON *json,*array,*item;
|
|
json = cJSON_CreateObject();
|
|
if ( prices != 0 )
|
|
{
|
|
jaddstr(json,"exchange",prices->exchange);
|
|
jaddstr(json,"name",prices->contract);
|
|
jaddstr(json,"base",prices->base);
|
|
sprintf(numstr,"%llu",(long long)prices->baseid), jaddstr(json,"baseid",numstr);
|
|
jaddstr(json,"rel",prices->rel);
|
|
sprintf(numstr,"%llu",(long long)prices->relid), jaddstr(json,"relid",numstr);
|
|
jaddnum(json,"commission",prices->commission);
|
|
if ( prices->basketsize != 0 )
|
|
{
|
|
array = cJSON_CreateArray();
|
|
for (i=0; i<prices->basketsize; i++)
|
|
{
|
|
item = basketitem_json(prices->basket[i].prices);
|
|
if ( prices->basket[i].groupsize != 0 )
|
|
jaddnum(item,"groupsize",prices->basket[i].groupsize);
|
|
jaddnum(item,"group",prices->basket[i].groupid);
|
|
jaddnum(item,"wt",prices->basket[i].wt);
|
|
jaddi(array,item);
|
|
}
|
|
jadd(json,"basket",array);
|
|
}
|
|
}
|
|
return(json);
|
|
}
|
|
|
|
char *prices777_allorderbooks()
|
|
{
|
|
int32_t i; cJSON *json,*array = cJSON_CreateArray();
|
|
for (i=0; i<BUNDLE.num; i++)
|
|
jaddi(array,basketitem_json(BUNDLE.ptrs[i]));
|
|
json = cJSON_CreateObject();
|
|
cJSON_AddItemToObject(json,"orderbooks",array);
|
|
return(jprint(json,1));
|
|
}
|
|
|
|
struct prices777 *prices777_initpair(int32_t needfunc,char *exchange,char *_base,char *_rel,double decay,char *_name,uint64_t baseid,uint64_t relid,int32_t basketsize)
|
|
{
|
|
static long allocated;
|
|
struct exchange_funcs funcs[] =
|
|
{
|
|
{"nxtae", prices777_NXT, NXT_supports, NXT_tradestub },
|
|
{"unconf", prices777_unconfNXT, NXT_supports, NXT_tradestub },
|
|
{"InstantDEX", prices777_InstantDEX, InstantDEX_supports, InstantDEX_tradestub },
|
|
{"wallet", prices777_InstantDEX, InstantDEX_supports, InstantDEX_tradestub },
|
|
{"basket", prices777_basket, InstantDEX_supports, InstantDEX_tradestub },
|
|
{"basketNXT", prices777_basket, InstantDEX_supports, InstantDEX_tradestub },
|
|
{"basketBTC", prices777_basket, InstantDEX_supports, InstantDEX_tradestub },
|
|
{"basketUSD", prices777_basket, InstantDEX_supports, InstantDEX_tradestub },
|
|
{"basketCNY", prices777_basket, InstantDEX_supports, InstantDEX_tradestub },
|
|
{"active", prices777_basket, InstantDEX_supports, InstantDEX_tradestub },
|
|
{"peggy", prices777_InstantDEX, InstantDEX_supports, InstantDEX_tradestub },
|
|
{"jumblr", prices777_InstantDEX, InstantDEX_supports },
|
|
{"pangea", prices777_InstantDEX, InstantDEX_supports },
|
|
{"truefx", 0 }, {"ecb", 0 }, {"instaforex", 0 }, {"fxcm", 0 }, {"yahoo", 0 },
|
|
poloniex_funcs, bittrex_funcs, btce_funcs, bitfinex_funcs, btc38_funcs, huobi_funcs,
|
|
lakebtc_funcs, quadriga_funcs, okcoin_funcs, coinbase_funcs, bitstamp_funcs
|
|
};
|
|
int32_t i,rellen; char basebuf[64],relbuf[64],base[64],rel[64],name[64]; struct exchange_info *exchangeptr;
|
|
struct prices777 *prices;
|
|
safecopy(base,_base,sizeof(base));
|
|
safecopy(rel,_rel,sizeof(rel));
|
|
safecopy(name,_name,sizeof(name));
|
|
if ( needfunc < 0 )
|
|
{
|
|
for (i=0; i<sizeof(funcs)/sizeof(*funcs); i++)
|
|
{
|
|
if ( (exchangeptr= find_exchange(0,funcs[i].exchange)) != 0 )
|
|
{
|
|
printf("%p %s set supports.%p %p coinbalance.%p\n",exchangeptr,funcs[i].exchange,funcs[i].supports,funcs[i].trade,funcs[i].parsebalance);
|
|
exchangeptr->issue = funcs[i];
|
|
}
|
|
}
|
|
return(0);
|
|
}
|
|
//printf("init.(%s/%s) name.(%s) %llu %llu\n",base,rel,name,(long long)baseid,(long long)relid);
|
|
if ( strcmp(exchange,"nxtae") == 0 || strcmp(exchange,"unconf") == 0 )//|| strcmp(exchange,"InstantDEX") == 0 )
|
|
{
|
|
if ( strcmp(base,"NXT") == 0 || baseid == NXT_ASSETID )
|
|
{
|
|
strcpy(base,rel), baseid = relid;
|
|
strcpy(rel,"NXT"), relid = NXT_ASSETID;
|
|
printf("flip.(%s/%s) %llu %llu\n",base,rel,(long long)baseid,(long long)relid);
|
|
}
|
|
}
|
|
for (i=0; i<BUNDLE.num; i++)
|
|
{
|
|
if ( strcmp(BUNDLE.ptrs[i]->exchange,exchange) == 0 )
|
|
{
|
|
if ( baseid != 0 && relid != 0 && BUNDLE.ptrs[i]->baseid == baseid && BUNDLE.ptrs[i]->relid == relid )
|
|
return(BUNDLE.ptrs[i]);
|
|
if ( strcmp(BUNDLE.ptrs[i]->origbase,base) == 0 && strcmp(BUNDLE.ptrs[i]->origrel,rel) == 0 )
|
|
return(BUNDLE.ptrs[i]);
|
|
}
|
|
}
|
|
printf("cant find (%s) (%llu) (%llu) (%s) (%s)\n",exchange,(long long)baseid,(long long)relid,base,rel);
|
|
prices = calloc(1,sizeof(*prices) + basketsize*sizeof(*prices->basket));
|
|
// printf("new prices %ld\n",sizeof(*prices));
|
|
strcpy(prices->exchange,exchange), strcpy(prices->contract,name), strcpy(prices->base,base), strcpy(prices->rel,rel);
|
|
prices->baseid = baseid, prices->relid = relid;
|
|
prices->contractnum = InstantDEX_name(prices->key,&prices->keysize,exchange,prices->contract,prices->base,&prices->baseid,prices->rel,&prices->relid);
|
|
portable_mutex_init(&prices->mutex);
|
|
strcpy(prices->origbase,base);
|
|
if ( rel[0] != 0 )
|
|
strcpy(prices->origrel,rel);
|
|
allocated += sizeof(*prices);
|
|
safecopy(prices->exchange,exchange,sizeof(prices->exchange));
|
|
if ( strcmp(exchange,"nxtae") == 0 || strcmp(exchange,"unconf") == 0 || strcmp(exchange,INSTANTDEX_NAME) == 0 )
|
|
{
|
|
char tmp[16];
|
|
_set_assetname(&prices->basemult,tmp,0,prices->baseid);
|
|
_set_assetname(&prices->relmult,tmp,0,prices->relid);
|
|
if ( (prices->relid != NXT_ASSETID && prices->relid < (1LL << (5*8))) || (prices->baseid != NXT_ASSETID && prices->baseid == (1LL << (5*8))) )
|
|
{
|
|
printf("illegal baseid.%llu or relid.%llu\n",(long long)prices->baseid,(long long)prices->relid);
|
|
free(prices);
|
|
return(0);
|
|
}
|
|
//prices->nxtbooks = calloc(1,sizeof(*prices->nxtbooks));
|
|
safecopy(prices->lbase,base,sizeof(prices->lbase)), tolowercase(prices->lbase);
|
|
safecopy(prices->lrel,rel,sizeof(prices->lrel)), tolowercase(prices->lrel);
|
|
rellen = (int32_t)(strlen(prices->rel) + 1);
|
|
tmp[0] = 0;
|
|
prices->type = _set_assetname(&prices->ap_mult,tmp,0,prices->baseid);
|
|
printf("nxtbook.(%s) -> NXT %s %llu/%llu vs (%s) mult.%llu (%llu/%llu)\n",base,prices->contract,(long long)prices->baseid,(long long)prices->relid,tmp,(long long)prices->ap_mult,(long long)prices->basemult,(long long)prices->relmult);
|
|
}
|
|
else
|
|
{
|
|
prices->basemult = prices->relmult = 1;
|
|
safecopy(prices->base,base,sizeof(prices->base)), touppercase(prices->base);
|
|
safecopy(prices->lbase,base,sizeof(prices->lbase)), tolowercase(prices->lbase);
|
|
if ( rel[0] == 0 && prices777_ispair(basebuf,relbuf,base) >= 0 )
|
|
{
|
|
strcpy(base,basebuf), strcpy(rel,relbuf);
|
|
//printf("(%s) is a pair (%s)+(%s)\n",base,basebuf,relbuf);
|
|
}
|
|
if ( rel[0] != 0 )
|
|
{
|
|
rellen = (int32_t)(strlen(rel) + 1);
|
|
safecopy(prices->rel,rel,sizeof(prices->rel)), touppercase(prices->rel);
|
|
safecopy(prices->lrel,rel,sizeof(prices->lrel)), tolowercase(prices->lrel);
|
|
if ( prices->contract[0] == 0 )
|
|
{
|
|
strcpy(prices->contract,prices->base);
|
|
if ( strcmp(prices->rel,&prices->contract[strlen(prices->contract)-3]) != 0 )
|
|
strcat(prices->contract,"/"), strcat(prices->contract,prices->rel);
|
|
}
|
|
//printf("create base.(%s) rel.(%s)\n",prices->base,prices->rel);
|
|
}
|
|
else
|
|
{
|
|
if ( prices->contract[0] == 0 )
|
|
strcpy(prices->contract,base);
|
|
}
|
|
}
|
|
char str[65]; printf("%s init_pair.(%s) (%s)(%s).%llu -> (%s) keysize.%d crc.%u (baseid.%llu relid.%llu)\n",mbstr(str,allocated),exchange,base,rel,(long long)prices->contractnum,prices->contract,prices->keysize,calc_crc32(0,(void *)prices->key,prices->keysize),(long long)prices->baseid,(long long)prices->relid);
|
|
prices->decay = decay, prices->oppodecay = (1. - decay);
|
|
prices->RTflag = 1;
|
|
if ( (exchangeptr= find_exchange(0,exchange)) != 0 )
|
|
{
|
|
if ( prices->commission == 0. )
|
|
prices->commission = exchangeptr->commission;
|
|
prices->exchangeid = exchangeptr->exchangeid;
|
|
if ( exchangeptr->issue.update == 0 )
|
|
{
|
|
for (i=0; i<sizeof(funcs)/sizeof(*funcs); i++)
|
|
{
|
|
if ( strcmp(exchange,funcs[i].exchange) == 0 )
|
|
{
|
|
exchangeptr->issue = funcs[i];
|
|
//printf("return prices.%p\n",prices);
|
|
}
|
|
}
|
|
}
|
|
if ( exchangeptr->refcount == 0 )
|
|
{
|
|
printf("incr refcount.%s from %d\n",exchangeptr->name,exchangeptr->refcount);
|
|
exchangeptr->refcount++;
|
|
}
|
|
return(prices);
|
|
}
|
|
//printf("initialized.(%s).%lld\n",prices->contract,(long long)prices->contractnum);
|
|
return(prices);
|
|
}
|
|
|
|
int32_t is_pair(char *base,char *rel,char *refbase,char *refrel)
|
|
{
|
|
if ( strcmp(base,refbase) == 0 && strcmp(rel,refrel) == 0 )
|
|
return(1);
|
|
else if ( strcmp(rel,refbase) == 0 && strcmp(base,refrel) == 0 )
|
|
return(-1);
|
|
return(0);
|
|
}
|
|
|
|
struct prices777 *prices777_poll(char *_exchangestr,char *_name,char *_base,uint64_t refbaseid,char *_rel,uint64_t refrelid)
|
|
{
|
|
char exchangestr[64],base[64],rel[64],name[64],key[1024]; uint64_t baseid,relid;
|
|
int32_t keysize,exchangeid,valid; struct exchange_info *exchange; struct prices777 *prices;
|
|
baseid = refbaseid, relid = refrelid;
|
|
strcpy(exchangestr,_exchangestr), strcpy(base,_base), strcpy(rel,_rel), strcpy(name,_name);
|
|
if ( (strcmp(exchangestr,"huobi") == 0 && is_pair(base,rel,"BTC","CNY") == 0 && is_pair(base,rel,"LTC","CNY") == 0) ||
|
|
((strcmp(exchangestr,"bityes") == 0 || strcmp(exchangestr,"okcoin") == 0) && is_pair(base,rel,"BTC","USD") == 0 && is_pair(base,rel,"LTC","USD") == 0) ||
|
|
((strcmp(exchangestr,"bitstamp") == 0 || strcmp(exchangestr,"coinbase") == 0) && is_pair(base,rel,"BTC","USD") == 0) ||
|
|
(strcmp(exchangestr,"lakebtc") == 0 && is_pair(base,rel,"BTC","CNY") == 0 && is_pair(base,rel,"BTC","USD") == 0) ||
|
|
(strcmp(exchangestr,"quadriga") == 0 && is_pair(base,rel,"BTC","CAD") == 0 && is_pair(base,rel,"BTC","USD") == 0) ||
|
|
0 )
|
|
{
|
|
printf("%s (%s/%s) is not a supported trading pair\n",exchangestr,base,rel);
|
|
return(0);
|
|
}
|
|
InstantDEX_name(key,&keysize,exchangestr,name,base,&baseid,rel,&relid);
|
|
//printf("call addbundle\n");
|
|
if ( (prices= prices777_addbundle(&valid,0,0,exchangestr,baseid,relid)) != 0 )
|
|
{
|
|
printf("found (%s/%s).%s %llu %llu in slot-> %p\n",base,rel,exchangestr,(long long)baseid,(long long)relid,prices);
|
|
return(prices);
|
|
}
|
|
//printf("call find_exchange\n");
|
|
if ( (exchange= find_exchange(&exchangeid,exchangestr)) == 0 )
|
|
{
|
|
printf("cant add exchange.(%s)\n",exchangestr);
|
|
return(0);
|
|
}
|
|
if ( strcmp(exchangestr,"nxtae") == 0 || strcmp(exchangestr,"unconf") == 0 )
|
|
{
|
|
if ( strcmp(base,"NXT") != 0 && strcmp(rel,"NXT") != 0 )
|
|
{
|
|
printf("nxtae/unconf needs to be relative to NXT (%s/%s) %llu/%llu\n",base,rel,(long long)baseid,(long long)relid);
|
|
return(0);
|
|
}
|
|
}
|
|
if ( (prices= prices777_initpair(1,exchangestr,base,rel,0.,name,baseid,relid,0)) != 0 )
|
|
{
|
|
//printf("call addbundle after initpair\n");
|
|
prices777_addbundle(&valid,1,prices,0,0,0);
|
|
}
|
|
return(prices);
|
|
}
|
|
|
|
int32_t prices777_propagate(struct prices777 *prices)
|
|
{
|
|
int32_t i,n = 0;
|
|
for (i=0; i<prices->numdependents; i++)
|
|
{
|
|
n++;
|
|
if ( (*prices->dependents[i]) < 0xff )
|
|
(*prices->dependents[i])++;
|
|
if ( Debuglevel > 2 )
|
|
printf("numdependents.%d of %d %p %d\n",i,prices->numdependents,prices->dependents[i],*prices->dependents[i]);
|
|
}
|
|
return(n);
|
|
}
|
|
|
|
int32_t prices777_updated;
|
|
void prices777_basketsloop(void *ptr)
|
|
{
|
|
extern int32_t prices777_NXTBLOCK;
|
|
int32_t i,n; uint32_t updated; struct prices777 *prices;
|
|
while ( 1 )
|
|
{
|
|
for (i=n=0; i<BUNDLE.num; i++)
|
|
{
|
|
updated = (uint32_t)time(NULL);
|
|
if ( (prices= BUNDLE.ptrs[i]) != 0 && prices->disabled == 0 && prices->basketsize != 0 )
|
|
{
|
|
if ( prices->changed != 0 )
|
|
{
|
|
if ( Debuglevel > 2 )
|
|
printf("%s updating basket(%s) lastprice %.8f changed.%p %d\n",prices->exchange,prices->contract,prices->lastprice,&prices->changed,prices->changed);
|
|
prices->pollnxtblock = prices777_NXTBLOCK;
|
|
n++;
|
|
prices->lastupdate = updated;
|
|
if ( (prices->lastprice= prices777_basket(prices,MAX_DEPTH)) != 0. )
|
|
{
|
|
if ( prices->O.numbids > 0 || prices->O.numasks > 0 )
|
|
{
|
|
prices777_jsonstrs(prices,&prices->O);
|
|
prices777_updated += prices777_propagate(prices);
|
|
}
|
|
}
|
|
prices->changed = 0;
|
|
}
|
|
}
|
|
}
|
|
if ( n == 0 )
|
|
usleep(250000);
|
|
else usleep(10000);
|
|
}
|
|
}
|
|
|
|
void prices777_exchangeloop(void *ptr)
|
|
{
|
|
extern int32_t prices777_NXTBLOCK;
|
|
struct prices777 *prices; int32_t i,n,pollflag,isnxtae = 0; double updated = 0.; struct exchange_info *exchange = ptr;
|
|
if ( strcmp(exchange->name,"nxtae") == 0 || strcmp(exchange->name,"unconf") == 0 )
|
|
isnxtae = 1;
|
|
printf("POLL.(%s)\n",exchange->name);
|
|
while ( 1 )
|
|
{
|
|
for (i=n=0; i<BUNDLE.num; i++)
|
|
{
|
|
if ( (prices= BUNDLE.ptrs[i]) != 0 && prices->disabled == 0 && prices->basketsize == 0 && prices->exchangeid == exchange->exchangeid )
|
|
{
|
|
if ( prices->exchangeid == INSTANTDEX_EXCHANGEID && prices->dirty != 0 )
|
|
pollflag = 1;
|
|
else if ( isnxtae == 0 )
|
|
pollflag = milliseconds() > (exchange->lastupdate + exchange->pollgap*1000) && milliseconds() > (prices->lastupdate + 1000*IGUANA_EXCHANGEIDLE);
|
|
else if ( (strcmp(exchange->name,"unconf") == 0 && milliseconds() > prices->lastupdate + 5000) || prices->pollnxtblock < prices777_NXTBLOCK || milliseconds() > prices->lastupdate + 1000*IGUANA_EXCHANGEIDLE )
|
|
pollflag = 1;
|
|
else continue;
|
|
//printf("(%s) pollflag.%d %p\n",exchange->name,pollflag,exchange->issue.update);
|
|
if ( pollflag != 0 && exchange->issue.update != 0 )
|
|
{
|
|
portable_mutex_lock(&exchange->mutex);
|
|
prices->lastprice = (*exchange->issue.update)(prices,MAX_DEPTH);
|
|
portable_mutex_unlock(&exchange->mutex);
|
|
updated = exchange->lastupdate = milliseconds(), prices->lastupdate = milliseconds();
|
|
if ( prices->lastprice != 0. )
|
|
{
|
|
if ( Debuglevel > 2 && strcmp(exchange->name,"unconf") != 0 )
|
|
printf("%-8s %8s (%8s %8s) %llu %llu isnxtae.%d poll %u -> %u %.8f hbla %.8f %.8f\n",prices->exchange,prices->contract,prices->base,prices->rel,(long long)prices->baseid,(long long)prices->relid,isnxtae,prices->pollnxtblock,prices777_NXTBLOCK,prices->lastprice,prices->lastbid,prices->lastask);
|
|
prices777_propagate(prices);
|
|
}
|
|
prices->pollnxtblock = prices777_NXTBLOCK;
|
|
prices->dirty = 0;
|
|
n++;
|
|
}
|
|
/*if ( 0 && exchange->issue.trade != 0 && exchange->apikey[0] != 0 && exchange->exchangeid >= FIRST_EXTERNAL && time(NULL) > exchange->lastbalancetime+300 )
|
|
{
|
|
if ( (json= (*exchange->issue.balances)(exchange)) != 0 )
|
|
{
|
|
if ( exchange->balancejson != 0 )
|
|
free_json(exchange->balancejson);
|
|
exchange->balancejson = json;
|
|
}
|
|
exchange->lastbalancetime = (uint32_t)time(NULL);
|
|
}*/
|
|
}
|
|
}
|
|
if ( n == 0 )
|
|
sleep(3);
|
|
else sleep(1);
|
|
}
|
|
}
|
|
|
|
int32_t prices777_init(char *jsonstr,int32_t peggyflag)
|
|
{
|
|
static int32_t didinit;
|
|
char *btcdexchanges[] = { "poloniex", "bittrex" };//, "bter" };
|
|
char *btcusdexchanges[] = { "bityes", "bitfinex", "bitstamp", "okcoin", "coinbase", "btce", "lakebtc", "kraken" };
|
|
cJSON *json=0,*item,*exchanges; int32_t i,n; char *exchange,*base,*rel,*contract; struct exchange_info *exchangeptr=0; struct destbuf tmp;
|
|
if ( didinit != 0 )
|
|
return(0);
|
|
didinit = 1;
|
|
if ( (BUNDLE.ptrs[BUNDLE.num]= prices777_initpair(1,"unconf","BTC","NXT",0,"BTC/NXT",calc_nxt64bits("12659653638116877017"),NXT_ASSETID,0)) != 0 )
|
|
BUNDLE.num++;
|
|
if ( peggyflag != 0 )
|
|
{
|
|
if ( (BUNDLE.ptrs[BUNDLE.num]= prices777_initpair(1,"huobi","BTC","USD",0.,0,0,0,0)) != 0 )
|
|
BUNDLE.num++;
|
|
if ( (BUNDLE.ptrs[BUNDLE.num]= prices777_initpair(1,"btc38","CNY","NXT",0.,0,0,0,0)) != 0 )
|
|
BUNDLE.num++;
|
|
if ( (BUNDLE.ptrs[BUNDLE.num]= prices777_initpair(1,"okcoin","LTC","BTC",0.,0,0,0,0)) != 0 )
|
|
BUNDLE.num++;
|
|
if ( (BUNDLE.ptrs[BUNDLE.num]= prices777_initpair(1,"poloniex","LTC","BTC",0.,0,0,0,0)) != 0 )
|
|
BUNDLE.num++;
|
|
if ( (BUNDLE.ptrs[BUNDLE.num]= prices777_initpair(1,"poloniex","XMR","BTC",0.,0,0,0,0)) != 0 )
|
|
BUNDLE.num++;
|
|
if ( (BUNDLE.ptrs[BUNDLE.num]= prices777_initpair(1,"poloniex","BTS","BTC",0.,0,0,0,0)) != 0 )
|
|
BUNDLE.num++;
|
|
if ( (BUNDLE.ptrs[BUNDLE.num]= prices777_initpair(1,"poloniex","XCP","BTC",0.,0,0,0,0)) != 0 )
|
|
BUNDLE.num++;
|
|
for (i=0; i<sizeof(btcdexchanges)/sizeof(*btcdexchanges); i++)
|
|
if ( (BUNDLE.ptrs[BUNDLE.num]= prices777_initpair(1,btcusdexchanges[i],"BTC","USD",0.,0,0,0,0)) != 0 )
|
|
BUNDLE.num++;
|
|
for (i=0; i<sizeof(btcdexchanges)/sizeof(*btcdexchanges); i++)
|
|
if ( (BUNDLE.ptrs[BUNDLE.num]= prices777_initpair(1,btcdexchanges[i],"BTCD","BTC",0.,0,0,0,0)) != 0 )
|
|
BUNDLE.num++;
|
|
}
|
|
if ( (json= cJSON_Parse(jsonstr)) != 0 && (exchanges= jarray(&n,json,"prices")) != 0 )
|
|
{
|
|
printf("prices has %d items\n",n);
|
|
for (i=0; i<n; i++)
|
|
{
|
|
item = jitem(exchanges,i);
|
|
exchange = jstr(item,"exchange"), base = jstr(item,"base"), rel = jstr(item,"rel");
|
|
if ( (base == 0 || rel == 0) && (contract= jstr(item,"contract")) != 0 )
|
|
rel = 0, base = contract;
|
|
else contract = 0;
|
|
//printf("PRICES[%d] %p %p %p\n",i,exchange,base,rel);
|
|
if ( exchange != 0 && (strcmp(exchange,"bter") == 0 || strcmp(exchange,"exmo") == 0) )
|
|
continue;
|
|
if ( exchange != 0 && (exchangeptr= find_exchange(0,exchange)) != 0 )
|
|
{
|
|
exchangeptr->pollgap = get_API_int(cJSON_GetObjectItem(item,"pollgap"),IGUANA_EXCHANGEIDLE);
|
|
extract_cJSON_str(exchangeptr->apikey,sizeof(exchangeptr->apikey),item,"key");
|
|
if ( exchangeptr->apikey[0] == 0 )
|
|
extract_cJSON_str(exchangeptr->apikey,sizeof(exchangeptr->apikey),item,"apikey");
|
|
extract_cJSON_str(exchangeptr->userid,sizeof(exchangeptr->userid),item,"userid");
|
|
extract_cJSON_str(exchangeptr->apisecret,sizeof(exchangeptr->apisecret),item,"secret");
|
|
if ( exchangeptr->apisecret[0] == 0 )
|
|
extract_cJSON_str(exchangeptr->apisecret,sizeof(exchangeptr->apisecret),item,"apisecret");
|
|
if ( exchangeptr->commission == 0. )
|
|
exchangeptr->commission = jdouble(item,"commission");
|
|
printf("%p ADDEXCHANGE.(%s) [%s, %s, %s] commission %.3f%%\n",exchangeptr,exchange,exchangeptr->apikey,exchangeptr->userid,exchangeptr->apisecret,exchangeptr->commission * 100);
|
|
} else printf(" exchangeptr.%p for (%p)\n",exchangeptr,exchange);
|
|
if ( exchange != 0 && strcmp(exchange,"truefx") == 0 )
|
|
{
|
|
copy_cJSON(&tmp,jobj(item,"truefxuser")), safecopy(BUNDLE.truefxuser,tmp.buf,sizeof(BUNDLE.truefxuser));
|
|
copy_cJSON(&tmp,jobj(item,"truefxpass")), safecopy(BUNDLE.truefxpass,tmp.buf,sizeof(BUNDLE.truefxpass));;
|
|
printf("truefx.(%s %s)\n",BUNDLE.truefxuser,BUNDLE.truefxpass);
|
|
}
|
|
else if ( base != 0 && rel != 0 && base[0] != 0 && rel[0] != 0 && (BUNDLE.ptrs[BUNDLE.num]= prices777_initpair(1,exchange,base,rel,jdouble(item,"decay"),contract,stringbits(base),stringbits(rel),0)) != 0 )
|
|
{
|
|
if ( exchangeptr != 0 && (BUNDLE.ptrs[BUNDLE.num]->commission= jdouble(item,"commission")) == 0. )
|
|
BUNDLE.ptrs[BUNDLE.num]->commission = exchangeptr->commission;
|
|
printf("SET COMMISSION.%s %f for %s/%s\n",exchange,exchangeptr!=0?exchangeptr->commission:0,base,rel);
|
|
BUNDLE.num++;
|
|
}
|
|
}
|
|
} else printf("(%s) has no prices[]\n",jsonstr);
|
|
if ( json != 0 )
|
|
free_json(json);
|
|
for (i=0; i<MAX_EXCHANGES; i++)
|
|
{
|
|
exchangeptr = &Exchanges[i];
|
|
if ( (exchangeptr->refcount > 0 || strcmp(exchangeptr->name,"unconf") == 0) )//&& strcmp(exchangeptr->name,"pangea") != 0 && strcmp(exchangeptr->name,"jumblr") != 0 )
|
|
iguana_launch(iguana_coinadd("BTCD"),"exchangeloop",(void *)prices777_exchangeloop,exchangeptr,IGUANA_EXCHANGETHREAD);
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
double prices777_yahoo(char *metal)
|
|
{
|
|
// http://finance.yahoo.com/webservice/v1/symbols/allcurrencies/quote?format=json
|
|
// http://finance.yahoo.com/webservice/v1/symbols/XAU=X/quote?format=json
|
|
// http://finance.yahoo.com/webservice/v1/symbols/XAG=X/quote?format=json
|
|
// http://finance.yahoo.com/webservice/v1/symbols/XPT=X/quote?format=json
|
|
// http://finance.yahoo.com/webservice/v1/symbols/XPD=X/quote?format=json
|
|
char url[1024],*jsonstr; cJSON *json,*obj,*robj,*item,*field; double price = 0.;
|
|
sprintf(url,"http://finance.yahoo.com/webservice/v1/symbols/%s=X/quote?format=json",metal);
|
|
if ( (jsonstr= issue_curl(url)) != 0 )
|
|
{
|
|
//printf("(%s)\n",jsonstr);
|
|
if ( (json= cJSON_Parse(jsonstr)) != 0 )
|
|
{
|
|
if ( (obj= jobj(json,"list")) != 0 && (robj= jobj(obj,"resources")) != 0 && (item= jitem(robj,0)) != 0 )
|
|
{
|
|
if ( (robj= jobj(item,"resource")) != 0 && (field= jobj(robj,"fields")) != 0 && (price= jdouble(field,"price")) != 0 )
|
|
price = 1. / price;
|
|
}
|
|
free_json(json);
|
|
}
|
|
free(jsonstr);
|
|
}
|
|
if ( Debuglevel > 2 )
|
|
printf("(%s %f) ",metal,price);
|
|
return(price);
|
|
}
|
|
|
|
cJSON *url_json(char *url)
|
|
{
|
|
char *jsonstr; cJSON *json = 0;
|
|
if ( (jsonstr= issue_curl(url)) != 0 )
|
|
{
|
|
//printf("(%s) -> (%s)\n",url,jsonstr);
|
|
json = cJSON_Parse(jsonstr);
|
|
free(jsonstr);
|
|
}
|
|
return(json);
|
|
}
|
|
|
|
cJSON *url_json2(char *url)
|
|
{
|
|
char *jsonstr; cJSON *json = 0;
|
|
if ( (jsonstr= issue_curl(url)) != 0 )
|
|
{
|
|
//printf("(%s) -> (%s)\n",url,jsonstr);
|
|
json = cJSON_Parse(jsonstr);
|
|
free(jsonstr);
|
|
}
|
|
return(json);
|
|
}
|
|
|
|
void prices777_btcprices(int32_t enddatenum,int32_t numdates)
|
|
{
|
|
int32_t i,n,year,month,day,seconds,datenum; char url[1024],date[64],*dstr,*str; uint32_t timestamp,utc32[MAX_SPLINES];
|
|
cJSON *coindesk,*quandl,*btcdhist,*bpi,*array,*item;
|
|
double btcddaily[MAX_SPLINES],cdaily[MAX_SPLINES],qdaily[MAX_SPLINES],ask,high,low,bid,close,vol,quotevol,open,price = 0.;
|
|
coindesk = url_json("http://api.coindesk.com/v1/bpi/historical/close.json");
|
|
sprintf(url,"https://poloniex.com/public?command=returnChartData¤cyPair=BTC_BTCD&start=%ld&end=9999999999&period=86400",(long)(time(NULL)-numdates*3600*24));
|
|
if ( (bpi= jobj(coindesk,"bpi")) != 0 )
|
|
{
|
|
datenum = enddatenum;
|
|
memset(utc32,0,sizeof(utc32));
|
|
memset(cdaily,0,sizeof(cdaily));
|
|
if ( datenum == 0 )
|
|
{
|
|
datenum = OS_conv_unixtime(&seconds,(uint32_t)time(NULL));
|
|
printf("got datenum.%d %d %d %d\n",datenum,seconds/3600,(seconds/60)%24,seconds%60);
|
|
}
|
|
for (i=0; i<numdates; i++)
|
|
{
|
|
expand_datenum(date,datenum);
|
|
if ( (price= jdouble(bpi,date)) != 0 )
|
|
{
|
|
utc32[numdates - 1 - i] = OS_conv_datenum(datenum,12,0,0);
|
|
cdaily[numdates - 1 - i] = price * .001;
|
|
//printf("(%s %u %f) ",date,utc32[numdates - 1 - i],price);
|
|
}
|
|
datenum = ecb_decrdate(&year,&month,&day,date,datenum);
|
|
}
|
|
prices777_genspline(&BUNDLE.splines[MAX_CURRENCIES],MAX_CURRENCIES,"coindesk",utc32,cdaily,numdates,cdaily);
|
|
|
|
} else printf("no bpi\n");
|
|
quandl = url_json("https://www.quandl.com/api/v1/datasets/BAVERAGE/USD.json?rows=64");
|
|
if ( (str= jstr(quandl,"updated_at")) != 0 && (datenum= conv_date(&seconds,str)) > 0 && (array= jarray(&n,quandl,"data")) != 0 )
|
|
{
|
|
printf("datenum.%d data.%d %d\n",datenum,n,cJSON_GetArraySize(array));
|
|
memset(utc32,0,sizeof(utc32)), memset(qdaily,0,sizeof(qdaily));
|
|
for (i=0; i<n&&i<MAX_SPLINES; i++)
|
|
{
|
|
// ["Date","24h Average","Ask","Bid","Last","Total Volume"]
|
|
// ["2015-07-25",289.27,288.84,288.68,288.87,44978.61]
|
|
item = jitem(array,i);
|
|
if ( Debuglevel > 2 )
|
|
printf("(%s) ",cJSON_Print(item));
|
|
if ( (dstr= jstr(jitem(item,0),0)) != 0 && (datenum= conv_date(&seconds,dstr)) > 0 )
|
|
{
|
|
price = jdouble(jitem(item,1),0), ask = jdouble(jitem(item,2),0), bid = jdouble(jitem(item,3),0);
|
|
close = jdouble(jitem(item,4),0), vol = jdouble(jitem(item,5),0);
|
|
if ( Debuglevel > 2 )
|
|
fprintf(stderr,"%d.[%d %f %f %f %f %f].%d ",i,datenum,price,ask,bid,close,vol,n);
|
|
utc32[numdates - 1 - i] = OS_conv_datenum(datenum,12,0,0), qdaily[numdates - 1 - i] = price * .001;
|
|
}
|
|
}
|
|
prices777_genspline(&BUNDLE.splines[MAX_CURRENCIES+1],MAX_CURRENCIES+1,"quandl",utc32,qdaily,n<MAX_SPLINES?n:MAX_SPLINES,qdaily);
|
|
}
|
|
btcdhist = url_json(url);
|
|
//{"date":1406160000,"high":0.01,"low":0.00125,"open":0.01,"close":0.001375,"volume":1.50179994,"quoteVolume":903.58818412,"weightedAverage":0.00166204},
|
|
if ( (array= jarray(&n,btcdhist,0)) != 0 )
|
|
{
|
|
memset(utc32,0,sizeof(utc32)), memset(btcddaily,0,sizeof(btcddaily));
|
|
//printf("GOT.(%s)\n",cJSON_Print(array));
|
|
for (i=0; i<n; i++)
|
|
{
|
|
item = jitem(array,i);
|
|
timestamp = juint(item,"date"), high = jdouble(item,"high"), low = jdouble(item,"low"), open = jdouble(item,"open");
|
|
close = jdouble(item,"close"), vol = jdouble(item,"volume"), quotevol = jdouble(item,"quoteVolume"), price = jdouble(item,"weightedAverage");
|
|
//printf("[%u %f %f %f %f %f %f %f]",timestamp,high,low,open,close,vol,quotevol,price);
|
|
if ( Debuglevel > 2 )
|
|
printf("[%u %d %f]",timestamp,OS_conv_unixtime(&seconds,timestamp),price);
|
|
utc32[i] = timestamp - 12*3600, btcddaily[i] = price * 100.;
|
|
}
|
|
if ( Debuglevel > 2 )
|
|
printf("poloniex.%d\n",n);
|
|
prices777_genspline(&BUNDLE.splines[MAX_CURRENCIES+2],MAX_CURRENCIES+2,"btcdhist",utc32,btcddaily,n<MAX_SPLINES?n:MAX_SPLINES,btcddaily);
|
|
}
|
|
// https://poloniex.com/public?command=returnChartData¤cyPair=BTC_BTCD&start=1405699200&end=9999999999&period=86400
|
|
}
|
|
|
|
int32_t prices777_calcmatrix(double matrix[32][32])
|
|
{
|
|
int32_t basenum,relnum,nonz,vnum,iter,numbase,numerrs = 0; double sum,vsum,price,price2,basevals[32],errsum=0;
|
|
memset(basevals,0,sizeof(basevals));
|
|
for (iter=0; iter<2; iter++)
|
|
{
|
|
numbase = 32;
|
|
for (basenum=0; basenum<numbase; basenum++)
|
|
{
|
|
for (vsum=sum=vnum=nonz=relnum=0; relnum<numbase; relnum++)
|
|
{
|
|
if ( basenum != relnum )
|
|
{
|
|
if ( (price= matrix[basenum][relnum]) != 0. )
|
|
{
|
|
price /= (MINDENOMS[relnum] * .001);
|
|
price *= (MINDENOMS[basenum] * .001);
|
|
if ( iter == 0 )
|
|
sum += (price), nonz++;//, printf("%.8f ",price);
|
|
else sum += fabs((price) - (basevals[basenum] / basevals[relnum])), nonz++;
|
|
}
|
|
if ( (price2= matrix[relnum][basenum]) != 0. )
|
|
{
|
|
price2 *= (MINDENOMS[relnum] * .001);
|
|
price2 /= (MINDENOMS[basenum] * .001);
|
|
if ( iter == 0 )
|
|
vsum += (price2), vnum++;
|
|
else vsum += fabs(price2 - (basevals[relnum] / basevals[basenum])), vnum++;
|
|
}
|
|
//if ( iter == 0 && 1/price2 > price )
|
|
// printf("base.%d rel.%d price2 %f vs %f\n",basenum,relnum,1/price2,price);
|
|
}
|
|
}
|
|
if ( iter == 0 )
|
|
sum += 1., vsum += 1.;
|
|
if ( nonz != 0 )
|
|
sum /= nonz;
|
|
if ( vnum != 0 )
|
|
vsum /= vnum;
|
|
if ( iter == 0 )
|
|
basevals[basenum] = (sum + 1./vsum) / 2.;
|
|
else errsum += (sum + vsum)/2, numerrs++;//, printf("(%.8f %.8f) ",sum,vsum);
|
|
//printf("date.%d (%.8f/%d %.8f/%d).%02d -> %.8f\n",i,sum,nonz,vsum,vnum,basenum,basevals[basenum]);
|
|
}
|
|
if ( iter == 0 )
|
|
{
|
|
for (sum=relnum=0; relnum<numbase; relnum++)
|
|
sum += (basevals[relnum]);//, printf("%.8f ",(basevals[relnum]));
|
|
//printf("date.%d sums %.8f and vsums iter.%d\n",i,sum/7,iter);
|
|
sum /= (numbase - 1);
|
|
for (relnum=0; relnum<numbase; relnum++)
|
|
basevals[relnum] /= sum;//, printf("%.8f ",basevals[relnum]);
|
|
//printf("date.%d sums %.8f and vsums iter.%d\n",i,sum,iter);
|
|
}
|
|
else
|
|
{
|
|
for (basenum=0; basenum<numbase; basenum++)
|
|
matrix[basenum][basenum] = basevals[basenum];
|
|
}
|
|
}
|
|
if ( numerrs != 0 )
|
|
errsum /= numerrs;
|
|
return(errsum);
|
|
}
|
|
|
|
int32_t ecb_matrix(double matrix[32][32],char *date)
|
|
{
|
|
FILE *fp=0; int32_t n=0,datenum,year=0,seconds,month=0,day=0,loaded = 0; char fname[64],_date[64];
|
|
if ( date == 0 )
|
|
date = _date, memset(_date,0,sizeof(_date));
|
|
sprintf(fname,"ECB/%s",date), iguana_compatible_path(fname);
|
|
if ( date[0] != 0 && (fp= fopen(fname,"rb")) != 0 )
|
|
{
|
|
if ( fread(matrix,1,sizeof(matrix[0][0])*32*32,fp) == sizeof(matrix[0][0])*32*32 )
|
|
loaded = 1;
|
|
else printf("fread error\n");
|
|
fclose(fp);
|
|
} else printf("ecb_matrix.(%s) load error fp.%p\n",fname,fp);
|
|
if ( loaded == 0 )
|
|
{
|
|
datenum = conv_date(&seconds,date);
|
|
year = datenum / 10000, month = (datenum / 100) % 100, day = (datenum % 100);
|
|
if ( (n= prices777_ecb(date,&matrix[0][0],year,month,day)) > 0 )
|
|
{
|
|
sprintf(fname,"ECB/%s",date), iguana_compatible_path(fname);
|
|
if ( (fp= fopen(fname,"wb")) != 0 )
|
|
{
|
|
if ( fwrite(matrix,1,sizeof(matrix[0][0])*32*32,fp) == sizeof(matrix[0][0])*32*32 )
|
|
loaded = 1;
|
|
fclose(fp);
|
|
}
|
|
} else printf("peggy_matrix error loading %d.%d.%d\n",year,month,day);
|
|
}
|
|
if ( loaded == 0 && n == 0 )
|
|
{
|
|
printf("peggy_matrix couldnt process loaded.%d n.%d\n",loaded,n);
|
|
return(-1);
|
|
}
|
|
//"2000-01-03"
|
|
if ( (datenum= conv_date(&seconds,date)) < 0 )
|
|
return(-1);
|
|
printf("loaded.(%s) nonz.%d (%d %d %d) datenum.%d\n",date,n,year,month,day,datenum);
|
|
return(datenum);
|
|
}
|
|
|
|
void price777_update(double *btcusdp,double *btcdbtcp)
|
|
{
|
|
int32_t i,n,seconds,datenum; uint32_t timestamp; char url[1024],*dstr,*str;
|
|
double btcddaily=0.,btcusd=0.,ask,high,low,bid,close,vol,quotevol,open,price = 0.;
|
|
//cJSON *btcdtrades,*btcdtrades2,*,*bitcoincharts,;
|
|
cJSON *quandl,*btcdhist,*array,*item,*bitcoinave,*blockchaininfo,*coindesk=0;
|
|
//btcdtrades = url_json("https://poloniex.com/public?command=returnTradeHistory¤cyPair=BTC_BTCD");
|
|
//btcdtrades2 = url_json("https://bittrex.com/api/v1.1/public/getmarkethistory?market=BTC-BTCD&count=50");
|
|
bitcoinave = url_json("https://api.bitcoinaverage.com/ticker/USD/");
|
|
//bitcoincharts = url_json("http://api.bitcoincharts.com/v1/weighted_prices.json");
|
|
blockchaininfo = url_json("https://blockchain.info/ticker");
|
|
coindesk = url_json("http://api.coindesk.com/v1/bpi/historical/close.json");
|
|
sprintf(url,"https://poloniex.com/public?command=returnChartData¤cyPair=BTC_BTCD&start=%ld&end=9999999999&period=86400",(long)(time(NULL)-2*3600*24));
|
|
quandl = url_json("https://www.quandl.com/api/v1/datasets/BAVERAGE/USD.json?rows=1");
|
|
if ( quandl != 0 && (str= jstr(quandl,"updated_at")) != 0 && (datenum= conv_date(&seconds,str)) > 0 && (array= jarray(&n,quandl,"data")) != 0 )
|
|
{
|
|
//printf("datenum.%d data.%d %d\n",datenum,n,cJSON_GetArraySize(array));
|
|
for (i=0; i<1; i++)
|
|
{
|
|
// ["Date","24h Average","Ask","Bid","Last","Total Volume"]
|
|
// ["2015-07-25",289.27,288.84,288.68,288.87,44978.61]
|
|
item = jitem(array,i);
|
|
if ( (dstr= jstr(jitem(item,0),0)) != 0 && (datenum= conv_date(&seconds,dstr)) > 0 )
|
|
{
|
|
btcusd = price = jdouble(jitem(item,1),0), ask = jdouble(jitem(item,2),0), bid = jdouble(jitem(item,3),0);
|
|
close = jdouble(jitem(item,4),0), vol = jdouble(jitem(item,5),0);
|
|
//fprintf(stderr,"%d.[%d %f %f %f %f %f].%d ",i,datenum,price,ask,bid,close,vol,n);
|
|
}
|
|
}
|
|
}
|
|
price = 0.;
|
|
for (i=n=0; i<BUNDLE.num; i++)
|
|
{
|
|
if ( strcmp(BUNDLE.ptrs[i]->lbase,"btcd") == 0 && strcmp(BUNDLE.ptrs[i]->lrel,"btc") == 0 && BUNDLE.ptrs[i]->lastprice != 0. )
|
|
{
|
|
price += BUNDLE.ptrs[i]->lastprice;
|
|
n++;
|
|
}
|
|
}
|
|
if ( n != 0 )
|
|
{
|
|
price /= n;
|
|
*btcdbtcp = price;
|
|
//printf("set BTCD price %f\n",price);
|
|
BUNDLE.btcdbtc = price;
|
|
}
|
|
else
|
|
{
|
|
btcdhist = url_json(url);
|
|
//{"date":1406160000,"high":0.01,"low":0.00125,"open":0.01,"close":0.001375,"volume":1.50179994,"quoteVolume":903.58818412,"weightedAverage":0.00166204},
|
|
if ( btcdhist != 0 && (array= jarray(&n,btcdhist,0)) != 0 )
|
|
{
|
|
//printf("GOT.(%s)\n",cJSON_Print(array));
|
|
for (i=0; i<1; i++)
|
|
{
|
|
item = jitem(array,i);
|
|
timestamp = juint(item,"date"), high = jdouble(item,"high"), low = jdouble(item,"low"), open = jdouble(item,"open");
|
|
close = jdouble(item,"close"), vol = jdouble(item,"volume"), quotevol = jdouble(item,"quoteVolume"), price = jdouble(item,"weightedAverage");
|
|
//printf("[%u %f %f %f %f %f %f %f]",timestamp,high,low,open,close,vol,quotevol,price);
|
|
//printf("[%u %d %f]",timestamp,OS_conv_unixtime(&seconds,timestamp),price);
|
|
btcddaily = price;
|
|
if ( btcddaily != 0 )
|
|
BUNDLE.btcdbtc = *btcdbtcp = btcddaily;
|
|
}
|
|
//printf("poloniex.%d\n",n);
|
|
}
|
|
if ( btcdhist != 0 )
|
|
free_json(btcdhist);
|
|
}
|
|
// https://blockchain.info/ticker
|
|
/*
|
|
{
|
|
"USD" : {"15m" : 288.22, "last" : 288.22, "buy" : 288.54, "sell" : 288.57, "symbol" : "$"},
|
|
"ISK" : {"15m" : 38765.88, "last" : 38765.88, "buy" : 38808.92, "sell" : 38812.95, "symbol" : "kr"},
|
|
"HKD" : {"15m" : 2234, "last" : 2234, "buy" : 2236.48, "sell" : 2236.71, "symbol" : "$"},
|
|
"TWD" : {"15m" : 9034.19, "last" : 9034.19, "buy" : 9044.22, "sell" : 9045.16, "symbol" : "NT$"},
|
|
"CHF" : {"15m" : 276.39, "last" : 276.39, "buy" : 276.69, "sell" : 276.72, "symbol" : "CHF"},
|
|
"EUR" : {"15m" : 262.46, "last" : 262.46, "buy" : 262.75, "sell" : 262.78, "symbol" : "€"},
|
|
"DKK" : {"15m" : 1958.92, "last" : 1958.92, "buy" : 1961.1, "sell" : 1961.3, "symbol" : "kr"},
|
|
"CLP" : {"15m" : 189160.6, "last" : 189160.6, "buy" : 189370.62, "sell" : 189390.31, "symbol" : "$"},
|
|
"CAD" : {"15m" : 375.45, "last" : 375.45, "buy" : 375.87, "sell" : 375.91, "symbol" : "$"},
|
|
"CNY" : {"15m" : 1783.67, "last" : 1783.67, "buy" : 1785.65, "sell" : 1785.83, "symbol" : "¥"},
|
|
"THB" : {"15m" : 10046.98, "last" : 10046.98, "buy" : 10058.14, "sell" : 10059.18, "symbol" : "฿"},
|
|
"AUD" : {"15m" : 394.77, "last" : 394.77, "buy" : 395.2, "sell" : 395.25, "symbol" : "$"},
|
|
"SGD" : {"15m" : 395.08, "last" : 395.08, "buy" : 395.52, "sell" : 395.56, "symbol" : "$"},
|
|
"KRW" : {"15m" : 335991.51, "last" : 335991.51, "buy" : 336364.55, "sell" : 336399.52, "symbol" : "₩"},
|
|
"JPY" : {"15m" : 35711.99, "last" : 35711.99, "buy" : 35751.64, "sell" : 35755.35, "symbol" : "¥"},
|
|
"PLN" : {"15m" : 1082.74, "last" : 1082.74, "buy" : 1083.94, "sell" : 1084.06, "symbol" : "zł"},
|
|
"GBP" : {"15m" : 185.84, "last" : 185.84, "buy" : 186.04, "sell" : 186.06, "symbol" : "£"},
|
|
"SEK" : {"15m" : 2471.02, "last" : 2471.02, "buy" : 2473.76, "sell" : 2474.02, "symbol" : "kr"},
|
|
"NZD" : {"15m" : 436.89, "last" : 436.89, "buy" : 437.37, "sell" : 437.42, "symbol" : "$"},
|
|
"BRL" : {"15m" : 944.91, "last" : 944.91, "buy" : 945.95, "sell" : 946.05, "symbol" : "R$"},
|
|
"RUB" : {"15m" : 16695.05, "last" : 16695.05, "buy" : 16713.58, "sell" : 16715.32, "symbol" : "RUB"}
|
|
}*/
|
|
/*{
|
|
"24h_avg": 281.22,
|
|
"ask": 280.12,
|
|
"bid": 279.33,
|
|
"last": 279.58,
|
|
"timestamp": "Sun, 02 Aug 2015 09:36:34 -0000",
|
|
"total_vol": 39625.8
|
|
}*/
|
|
|
|
if ( bitcoinave != 0 )
|
|
{
|
|
if ( (price= jdouble(bitcoinave,"24h_avg")) > SMALLVAL )
|
|
{
|
|
//printf("bitcoinave %f %f\n",btcusd,price);
|
|
dxblend(&btcusd,price,0.5);
|
|
}
|
|
free_json(bitcoinave);
|
|
}
|
|
if ( quandl != 0 )
|
|
free_json(quandl);
|
|
if ( coindesk != 0 )
|
|
free_json(coindesk);
|
|
if ( blockchaininfo != 0 )
|
|
{
|
|
if ( (item= jobj(blockchaininfo,"USD")) != 0 && item != 0 && (price= jdouble(item,"15m")) > SMALLVAL )
|
|
{
|
|
//printf("blockchaininfo %f %f\n",btcusd,price);
|
|
dxblend(&btcusd,price,0.5);
|
|
}
|
|
free_json(blockchaininfo);
|
|
}
|
|
if ( btcusd != 0 )
|
|
BUNDLE.btcusd = *btcusdp = btcusd;
|
|
|
|
|
|
// https://poloniex.com/public?command=returnChartData¤cyPair=BTC_BTCD&start=1405699200&end=9999999999&period=86400
|
|
|
|
// https://poloniex.com/public?command=returnTradeHistory¤cyPair=BTC_BTCD
|
|
//https://bittrex.com/api/v1.1/public/getmarkethistory?market=BTC-BTCD&count=50
|
|
/*{"success":true,"message":"","result":[{"Id":8551089,"TimeStamp":"2015-07-25T16:00:41.597","Quantity":59.60917089,"Price":0.00642371,"Total":0.38291202,"FillType":"FILL","OrderType":"BUY"},{"Id":8551088,"TimeStamp":"2015-07-25T16:00:41.597","Quantity":7.00000000,"Price":0.00639680,"Total":0.04477760,"FillType":"PARTIAL_FILL","OrderType":"BUY"},{"Id":8551087,"TimeStamp":"2015-07-25T16:00:41.597","Quantity":6.51000000,"Price":0.00639679,"Total":0.04164310,"FillType":"PARTIAL_FILL","OrderType":"BUY"},{"Id":8551086,"TimeStamp":"2015-07-25T16:00:41.597","Quantity":6.00000000,"Price":0.00633300,"Total":0.03799800,"FillType":"PARTIAL_FILL","OrderType":"BUY"},{"Id":8551085,"TimeStamp":"2015-07-25T16:00:41.593","Quantity":4.76833955,"Price":0.00623300,"Total":0.02972106,"FillType":"PARTIAL_FILL","OrderType":"BUY"},{"Id":8551084,"TimeStamp":"2015-07-25T16:00:41.593","Quantity":5.00000000,"Price":0.00620860,"Total":0.03104300,"FillType":"PARTIAL_FILL","OrderType":"BUY"},{"Id":8551083,"TimeStamp":"2015-07-25T16:00:41.593","Quantity":4.91803279,"Price":0.00620134,"Total":0.03049839,"FillType":"PARTIAL_FILL","OrderType":"BUY"},{"Id":8551082,"TimeStamp":"2015-07-25T16:00:41.593","Quantity":4.45166432,"Price":0.00619316,"Total":0.02756986,"FillType":"PARTIAL_FILL","OrderType":"BUY"},{"Id":8551081,"TimeStamp":"2015-07-25T16:00:41.59","Quantity":2.00000000,"Price":0.00619315,"Total":0.01238630,"FillType":"PARTIAL_FILL","OrderType":"BUY"},{"Id":8547525,"TimeStamp":"2015-07-25T06:20:43.69","Quantity":1.23166045,"Price":0.00623300,"Total":0.00767693,"FillType":"FILL","OrderType":"BUY"},{"Id":8547524,"TimeStamp":"2015-07-25T06:20:43.69","Quantity":5.00000000,"Price":0.00613300,"Total":0.03066500,"FillType":"PARTIAL_FILL","OrderType":"BUY"},{"Id":8547523,"TimeStamp":"2015-07-25T06:20:43.687","Quantity":10.00000000,"Price":0.00609990,"Total":0.06099900,"FillType":"PARTIAL_FILL","OrderType":"BUY"},{"Id":8547522,"TimeStamp":"2015-07-25T06:20:43.687","Quantity":0.12326502,"Price":0.00609989,"Total":0.00075190,"FillType":"PARTIAL_FILL","OrderType":"BUY"},{"Id":8547521,"TimeStamp":"2015-07-25T06:20:43.687","Quantity":3.29000000,"Price":0.00609989,"Total":0.02006863,"FillType":"PARTIAL_FILL","OrderType":"BUY"},{"Id":8547520,"TimeStamp":"2015-07-25T06:20:43.687","Quantity":5.00000000,"Price":0.00604400,"Total":0.03022000,"FillType":"PARTIAL_FILL","OrderType":"BUY"},{"Id":8547519,"TimeStamp":"2015-07-25T06:20:43.683","Quantity":12.80164947,"Price":0.00603915,"Total":0.07731108,"FillType":"PARTIAL_FILL","OrderType":"BUY"},{"Id":8547518,"TimeStamp":"2015-07-25T06:20:43.683","Quantity":10.00000000,"Price":0.00602715,"Total":0.06027150,"FillType":"PARTIAL_FILL","OrderType":"BUY"},{"Id":8547517,"TimeStamp":"2015-07-25T06:20:43.683","Quantity":4.29037397,"Price":0.00600000,"Total":0.02574224,"FillType":"PARTIAL_FILL","OrderType":"BUY"},{"Id":8547516,"TimeStamp":"2015-07-25T06:20:43.683","Quantity":77.55994092,"Price":0.00598921,"Total":0.46452277,"FillType":"PARTIAL_FILL","OrderType":"BUY"},{"Id":8547515,"TimeStamp":"2015-07-25T06:20:43.68","Quantity":0.08645064,"Price":0.00598492,"Total":0.00051740,"FillType":"PARTIAL_FILL","OrderType":"BUY"}]}
|
|
*/
|
|
|
|
// https://api.bitcoinaverage.com/ticker/global/all
|
|
/* {
|
|
"AED": {
|
|
"ask": 1063.28,
|
|
"bid": 1062.1,
|
|
"last": 1062.29,
|
|
"timestamp": "Sat, 25 Jul 2015 17:13:14 -0000",
|
|
"volume_btc": 0.0,
|
|
"volume_percent": 0.0
|
|
},*/
|
|
|
|
// http://api.bitcoincharts.com/v1/weighted_prices.json
|
|
// {"USD": {"7d": "279.79", "30d": "276.05", "24h": "288.55"}, "IDR": {"7d": "3750799.88", "30d": "3636926.02", "24h": "3860769.92"}, "ILS": {"7d": "1033.34", "30d": "1031.58", "24h": "1092.36"}, "GBP": {"7d": "179.51", "30d": "175.30", "24h": "185.74"}, "DKK": {"30d": "1758.61"}, "CAD": {"7d": "364.04", "30d": "351.27", "24h": "376.12"}, "MXN": {"30d": "4369.33"}, "XRP": {"7d": "35491.70", "30d": "29257.39", "24h": "36979.02"}, "SEK": {"7d": "2484.50", "30d": "2270.94"}, "SGD": {"7d": "381.93", "30d": "373.69", "24h": "393.94"}, "HKD": {"7d": "2167.99", "30d": "2115.77", "24h": "2232.12"}, "AUD": {"7d": "379.42", "30d": "365.85", "24h": "394.93"}, "CHF": {"30d": "250.61"}, "timestamp": 1437844509, "CNY": {"7d": "1724.99", "30d": "1702.32", "24h": "1779.48"}, "LTC": {"7d": "67.46", "30d": "51.97", "24h": "61.61"}, "NZD": {"7d": "425.01", "30d": "409.33", "24h": "437.86"}, "THB": {"30d": "8632.82"}, "EUR": {"7d": "257.32", "30d": "249.88", "24h": "263.42"}, "ARS": {"30d": "3271.98"}, "NOK": {"30d": "2227.54"}, "RUB": {"7d": "16032.32", "30d": "15600.38", "24h": "16443.39"}, "INR": {"30d": "16601.17"}, "JPY": {"7d": "34685.73", "30d": "33617.77", "24h": "35652.79"}, "CZK": {"30d": "6442.13"}, "BRL": {"7d": "946.76", "30d": "900.77", "24h": "964.09"}, "NMC": {"7d": "454.06", "30d": "370.39", "24h": "436.71"}, "PLN": {"7d": "1041.81", "30d": "1024.96", "24h": "1072.49"}, "ZAR": {"30d": "3805.55"}}
|
|
}
|
|
|
|
double blend_price(double *volp,double wtA,cJSON *jsonA,double wtB,cJSON *jsonB)
|
|
{
|
|
//A.{"ticker":{"base":"BTS","target":"CNY","price":"0.02958291","volume":"3128008.39295500","change":"0.00019513","markets":[{"market":"BTC38","price":"0.02960000","volume":3051650.682955},{"market":"Bter","price":"0.02890000","volume":76357.71}]},"timestamp":1438490881,"success":true,"error":""}
|
|
// B.{"id":"bts\/cny","price":"0.02940000","price_before_24h":"0.02990000","volume_first":"3048457.6857147217","volume_second":"90629.45859575272","volume_btc":"52.74","best_market":"btc38","latest_trade":"2015-08-02 03:57:38","coin1":"BitShares","coin2":"CNY","markets":[{"market":"btc38","price":"0.02940000","volume":"3048457.6857147217","volume_btc":"52.738317962865"},{"market":"bter","price":"0.04350000","volume":"0","volume_btc":"0"}]}
|
|
double priceA,priceB,priceB24,price,volA,volB; cJSON *obj;
|
|
priceA = priceB = priceB24= price = volA = volB = 0.;
|
|
if ( jsonA != 0 && (obj= jobj(jsonA,"ticker")) != 0 )
|
|
{
|
|
priceA = jdouble(obj,"price");
|
|
volA = jdouble(obj,"volume");
|
|
}
|
|
if ( jsonB != 0 )
|
|
{
|
|
priceB = jdouble(jsonB,"price");
|
|
priceB24 = jdouble(jsonB,"price_before_24h");
|
|
volB = jdouble(jsonB,"volume_first");
|
|
}
|
|
//printf("priceA %f volA %f, priceB %f %f volB %f\n",priceA,volA,priceB,priceB24,volB);
|
|
if ( priceB > SMALLVAL && priceB24 > SMALLVAL )
|
|
priceB = (priceB * .1) + (priceB24 * .9);
|
|
else if ( priceB < SMALLVAL )
|
|
priceB = priceB24;
|
|
if ( priceA*volA < SMALLVAL )
|
|
price = priceB;
|
|
else if ( priceB*volB < SMALLVAL )
|
|
price = priceA;
|
|
else price = (wtA * priceA) + (wtB * priceB);
|
|
*volp = (volA + volB);
|
|
return(price);
|
|
}
|
|
|
|
void _crypto_update(double cryptovols[2][8][2],struct prices777_data *dp,int32_t selector,int32_t peggyflag)
|
|
{
|
|
char *cryptonatorA = "https://www.cryptonator.com/api/full/%s-%s"; //unity-btc
|
|
char *cryptocoinchartsB = "http://api.cryptocoincharts.info/tradingPair/%s_%s"; //bts_btc
|
|
char *cryptostrs[9] = { "btc", "nxt", "unity", "eth", "ltc", "xmr", "bts", "xcp", "etc" };
|
|
int32_t iter,i,j; double btcusd,btcdbtc,cnyusd,prices[8][2],volumes[8][2];
|
|
char base[16],rel[16],url[512],*str; cJSON *jsonA,*jsonB;
|
|
if ( peggyflag != 0 )
|
|
{
|
|
cnyusd = BUNDLE.cnyusd;
|
|
btcusd = BUNDLE.btcusd;
|
|
btcdbtc = BUNDLE.btcdbtc;
|
|
//printf("update with btcusd %f btcd %f cnyusd %f cnybtc %f\n",btcusd,btcdbtc,cnyusd,cnyusd/btcusd);
|
|
if ( btcusd < SMALLVAL || btcdbtc < SMALLVAL )
|
|
{
|
|
price777_update(&btcusd,&btcdbtc);
|
|
printf("price777_update with btcusd %f btcd %f\n",btcusd,btcdbtc);
|
|
}
|
|
memset(prices,0,sizeof(prices));
|
|
memset(volumes,0,sizeof(volumes));
|
|
for (j=0; j<sizeof(cryptostrs)/sizeof(*cryptostrs); j++)
|
|
{
|
|
str = cryptostrs[j];
|
|
if ( strcmp(str,"etc") == 0 )
|
|
{
|
|
if ( prices[3][0] > SMALLVAL )
|
|
break;
|
|
i = 3;
|
|
} else i = j;
|
|
for (iter=0; iter<1; iter++)
|
|
{
|
|
if ( i == 0 && iter == 0 )
|
|
strcpy(base,"btcd"), strcpy(rel,"btc");
|
|
else strcpy(base,str), strcpy(rel,iter==0?"btc":"cny");
|
|
//if ( selector == 0 )
|
|
{
|
|
sprintf(url,cryptonatorA,base,rel);
|
|
jsonA = url_json(url);
|
|
}
|
|
//else
|
|
{
|
|
sprintf(url,cryptocoinchartsB,base,rel);
|
|
jsonB = url_json(url);
|
|
}
|
|
prices[i][iter] = blend_price(&volumes[i][iter],0.4,jsonA,0.6,jsonB);
|
|
if ( iter == 1 )
|
|
{
|
|
if ( btcusd > SMALLVAL )
|
|
{
|
|
prices[i][iter] *= cnyusd / btcusd;
|
|
volumes[i][iter] *= cnyusd / btcusd;
|
|
} else prices[i][iter] = volumes[i][iter] = 0.;
|
|
}
|
|
cryptovols[0][i][iter] = _pairaved(cryptovols[0][i][iter],prices[i][iter]);
|
|
cryptovols[1][i][iter] = _pairaved(cryptovols[1][i][iter],volumes[i][iter]);
|
|
if ( Debuglevel > 2 )
|
|
printf("(%f %f).%d:%d ",cryptovols[0][i][iter],cryptovols[1][i][iter],i,iter);
|
|
//if ( cnyusd < SMALLVAL || btcusd < SMALLVAL )
|
|
// break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void crypto_update(int32_t peggyflag)
|
|
{
|
|
_crypto_update(BUNDLE.cryptovols,&BUNDLE.data,1,peggyflag);
|
|
while ( 1 )
|
|
{
|
|
_crypto_update(BUNDLE.cryptovols,&BUNDLE.data,1,peggyflag);
|
|
sleep(100);
|
|
}
|
|
}
|
|
|
|
void prices777_RTupdate(double cryptovols[2][8][2],double RTmetals[4],double *RTprices,struct prices777_data *dp)
|
|
{
|
|
char *cryptostrs[8] = { "btc", "nxt", "unity", "eth", "ltc", "xmr", "bts", "xcp" };
|
|
int32_t iter,i,c,baserel,basenum,relnum; double cnyusd,btcusd,btcdbtc,bid,ask,price,vol,prices[8][2],volumes[8][2];
|
|
char base[16],rel[16];
|
|
price777_update(&btcusd,&btcdbtc);
|
|
memset(prices,0,sizeof(prices));
|
|
memset(volumes,0,sizeof(volumes));
|
|
for (i=0; i<sizeof(cryptostrs)/sizeof(*cryptostrs); i++)
|
|
for (iter=0; iter<2; iter++)
|
|
prices[i][iter] = cryptovols[0][i][iter], volumes[i][iter] = cryptovols[1][i][iter];
|
|
if ( prices[0][0] > SMALLVAL )
|
|
dxblend(&btcdbtc,prices[0][0],.9);
|
|
dxblend(&dp->btcdbtc,btcdbtc,.995);
|
|
if ( BUNDLE.btcdbtc < SMALLVAL )
|
|
BUNDLE.btcdbtc = dp->btcdbtc;
|
|
if ( (cnyusd= BUNDLE.cnyusd) > SMALLVAL )
|
|
{
|
|
if ( prices[0][1] > SMALLVAL )
|
|
{
|
|
//printf("cnyusd %f, btccny %f -> btcusd %f %f\n",cnyusd,prices[0][1],prices[0][1]*cnyusd,btcusd);
|
|
btcusd = prices[0][1] * cnyusd;
|
|
if ( dp->btcusd < SMALLVAL )
|
|
dp->btcusd = btcusd;
|
|
else dxblend(&dp->btcusd,btcusd,.995);
|
|
if ( BUNDLE.btcusd < SMALLVAL )
|
|
BUNDLE.btcusd = dp->btcusd;
|
|
if ( BUNDLE.data.btcusd < SMALLVAL )
|
|
BUNDLE.data.btcusd = dp->btcusd;
|
|
printf("cnyusd %f, btccny %f -> btcusd %f %f -> %f %f %f\n",cnyusd,prices[0][1],prices[0][1]*cnyusd,btcusd,dp->btcusd,BUNDLE.btcusd,BUNDLE.data.btcusd);
|
|
}
|
|
}
|
|
for (i=1; i<sizeof(cryptostrs)/sizeof(*cryptostrs); i++)
|
|
{
|
|
if ( (vol= volumes[i][0]+volumes[i][1]) > SMALLVAL )
|
|
{
|
|
price = ((prices[i][0] * volumes[i][0]) + (prices[i][1] * volumes[i][1])) / vol;
|
|
if ( Debuglevel > 2 )
|
|
printf("%s %f v%f + %f v%f -> %f %f\n",cryptostrs[i],prices[i][0],volumes[i][0],prices[i][1],volumes[i][1],price,dp->cryptos[i]);
|
|
dxblend(&dp->cryptos[i],price,.995);
|
|
}
|
|
}
|
|
btcusd = BUNDLE.btcusd;
|
|
btcdbtc = BUNDLE.btcdbtc;
|
|
if ( Debuglevel > 2 )
|
|
printf(" update with btcusd %f btcd %f\n",btcusd,btcdbtc);
|
|
if ( btcusd < SMALLVAL || btcdbtc < SMALLVAL )
|
|
{
|
|
price777_update(&btcusd,&btcdbtc);
|
|
if ( Debuglevel > 2 )
|
|
printf(" price777_update with btcusd %f btcd %f\n",btcusd,btcdbtc);
|
|
} else BUNDLE.btcusd = btcusd, BUNDLE.btcdbtc = btcdbtc;
|
|
for (c=0; c<sizeof(CONTRACTS)/sizeof(*CONTRACTS); c++)
|
|
{
|
|
for (iter=0; iter<3; iter++)
|
|
{
|
|
switch ( iter )
|
|
{
|
|
case 0: bid = dp->tbids[c], ask = dp->tasks[c]; break;
|
|
case 1: bid = dp->fbids[c], ask = dp->fasks[c]; break;
|
|
case 2: bid = dp->ibids[c], ask = dp->iasks[c]; break;
|
|
}
|
|
if ( (price= _pairaved(bid,ask)) > SMALLVAL )
|
|
{
|
|
if ( Debuglevel > 2 )
|
|
printf("%.6f ",price);
|
|
dxblend(&RTprices[c],price,.995);
|
|
if ( 0 && (baserel= prices777_ispair(base,rel,CONTRACTS[c])) >= 0 )
|
|
{
|
|
basenum = (baserel >> 8) & 0xff, relnum = baserel & 0xff;
|
|
if ( basenum < 32 && relnum < 32 )
|
|
{
|
|
//printf("%s.%d %f <- %f\n",CONTRACTS[c],c,RTmatrix[basenum][relnum],RTprices[c]);
|
|
//dxblend(&RTmatrix[basenum][relnum],RTprices[c],.999);
|
|
}
|
|
}
|
|
if ( strcmp(CONTRACTS[c],"XAUUSD") == 0 )
|
|
dxblend(&RTmetals[0],price,.995);
|
|
}
|
|
}
|
|
}
|
|
for (i=0; i<sizeof(Yahoo_metals)/sizeof(*Yahoo_metals); i++)
|
|
if ( BUNDLE.data.metals[i] != 0 )
|
|
dxblend(&RTmetals[i],BUNDLE.data.metals[i],.995);
|
|
}
|
|
|
|
int32_t prices777_getmatrix(double *basevals,double *btcusdp,double *btcdbtcp,double Hmatrix[32][32],double *RTprices,char *contracts[],int32_t num,uint32_t timestamp)
|
|
{
|
|
int32_t i,j,c; char name[16]; double btcusd,btcdbtc;
|
|
memcpy(Hmatrix,BUNDLE.data.ecbmatrix,sizeof(BUNDLE.data.ecbmatrix));
|
|
prices777_calcmatrix(Hmatrix);
|
|
/*for (i=0; i<32; i++)
|
|
{
|
|
for (j=0; j<32; j++)
|
|
printf("%.6f ",Hmatrix[i][j]);
|
|
printf("%s\n",CURRENCIES[i]);
|
|
}*/
|
|
btcusd = BUNDLE.btcusd;
|
|
btcdbtc = BUNDLE.btcdbtc;
|
|
if ( btcusd > SMALLVAL )
|
|
dxblend(btcusdp,btcusd,.9);
|
|
if ( btcdbtc > SMALLVAL )
|
|
dxblend(btcdbtcp,btcdbtc,.9);
|
|
// char *cryptostrs[8] = { "btc", "nxt", "unity", "eth", "ltc", "xmr", "bts", "xcp" };
|
|
// "BTCUSD", "NXTBTC", "SuperNET", "ETHBTC", "LTCBTC", "XMRBTC", "BTSBTC", "XCPBTC", // BTC priced
|
|
for (i=0; i<num; i++)
|
|
{
|
|
if ( contracts[i] == 0 )
|
|
continue;
|
|
if ( i == num-1 && strcmp(contracts[i],"BTCUSD") == 0 )
|
|
{
|
|
RTprices[i] = *btcusdp;
|
|
continue;
|
|
}
|
|
else if ( i == num-2 && strcmp(contracts[i],"BTCCNY") == 0 )
|
|
{
|
|
continue;
|
|
}
|
|
else if ( i == num-3 && strcmp(contracts[i],"BTCRUB") == 0 )
|
|
{
|
|
continue;
|
|
}
|
|
else if ( i == num-4 && strcmp(contracts[i],"XAUUSD") == 0 )
|
|
{
|
|
continue;
|
|
}
|
|
if ( strcmp(contracts[i],"NXTBTC") == 0 )
|
|
RTprices[i] = BUNDLE.data.cryptos[1];
|
|
else if ( strcmp(contracts[i],"SuperNET") == 0 )
|
|
RTprices[i] = BUNDLE.data.cryptos[2];
|
|
else if ( strcmp(contracts[i],"ETHBTC") == 0 )
|
|
RTprices[i] = BUNDLE.data.cryptos[3];
|
|
else if ( strcmp(contracts[i],"LTCBTC") == 0 )
|
|
RTprices[i] = BUNDLE.data.cryptos[4];
|
|
else if ( strcmp(contracts[i],"XMRBTC") == 0 )
|
|
RTprices[i] = BUNDLE.data.cryptos[5];
|
|
else if ( strcmp(contracts[i],"BTSBTC") == 0 )
|
|
RTprices[i] = BUNDLE.data.cryptos[6];
|
|
else if ( strcmp(contracts[i],"XCPBTC") == 0 )
|
|
RTprices[i] = BUNDLE.data.cryptos[7];
|
|
else if ( i < 32 )
|
|
{
|
|
basevals[i] = Hmatrix[i][i];
|
|
if ( Debuglevel > 2 )
|
|
printf("(%s %f).%d ",CURRENCIES[i],basevals[i],i);
|
|
}
|
|
else if ( (c= prices777_contractnum(contracts[i],0)) >= 0 )
|
|
{
|
|
RTprices[i] = BUNDLE.data.RTprices[c];
|
|
//if ( is_decimalstr(contracts[i]+strlen(contracts[i])-2) != 0 )
|
|
// cprices[i] *= .0001;
|
|
}
|
|
else
|
|
{
|
|
for (j=0; j<sizeof(Yahoo_metals)/sizeof(*Yahoo_metals); j++)
|
|
{
|
|
sprintf(name,"%sUSD",Yahoo_metals[j]);
|
|
if ( contracts[i] != 0 && strcmp(name,contracts[i]) == 0 )
|
|
{
|
|
RTprices[i] = BUNDLE.data.RTmetals[j];
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if ( Debuglevel > 2 )
|
|
printf("(%f %f) i.%d num.%d %s %f\n",*btcusdp,*btcdbtcp,i,num,contracts[i],RTprices[i]);
|
|
//printf("RT.(%s %f) ",contracts[i],RTprices[i]);
|
|
}
|
|
return(BUNDLE.data.ecbdatenum);
|
|
}
|
|
|
|
int32_t prices_idle(int32_t peggyflag,int32_t idlegap)
|
|
{
|
|
static double lastupdate,lastdayupdate; static int32_t didinit; static portable_mutex_t mutex;
|
|
int32_t i,datenum; struct prices777_data *dp = &BUNDLE.tmp;
|
|
*dp = BUNDLE.data;
|
|
if ( didinit == 0 )
|
|
{
|
|
portable_mutex_init(&mutex);
|
|
prices777_init(BUNDLE.jsonstr,peggyflag);
|
|
didinit = 1;
|
|
if ( peggyflag != 0 )
|
|
{
|
|
int32_t opreturns_init(uint32_t blocknum,uint32_t blocktimestamp,char *path);
|
|
opreturns_init(0,(uint32_t)time(NULL),"peggy");
|
|
}
|
|
}
|
|
if ( peggyflag != 0 && milliseconds() > lastupdate + (1000*idlegap) )
|
|
{
|
|
lastupdate = milliseconds();
|
|
if ( milliseconds() > lastdayupdate + 60000*60 )
|
|
{
|
|
lastdayupdate = milliseconds();
|
|
printf("call ecb_matrix.(%s)\n",dp->edate);
|
|
if ( (datenum= ecb_matrix(dp->ecbmatrix,dp->edate)) > 0 )
|
|
{
|
|
dp->ecbdatenum = datenum;
|
|
dp->ecbyear = dp->ecbdatenum / 10000, dp->ecbmonth = (dp->ecbdatenum / 100) % 100, dp->ecbday = (dp->ecbdatenum % 100);
|
|
expand_datenum(dp->edate,datenum);
|
|
memcpy(dp->RTmatrix,dp->ecbmatrix,sizeof(dp->RTmatrix));
|
|
}
|
|
}
|
|
for (i=0; i<sizeof(Yahoo_metals)/sizeof(*Yahoo_metals); i++)
|
|
BUNDLE.data.metals[i] = prices777_yahoo(Yahoo_metals[i]);
|
|
BUNDLE.truefxidnum = prices777_truefx(dp->tmillistamps,dp->tbids,dp->tasks,dp->topens,dp->thighs,dp->tlows,BUNDLE.truefxuser,BUNDLE.truefxpass,(uint32_t)BUNDLE.truefxidnum);
|
|
prices777_fxcm(dp->flhlogmatrix,dp->flogmatrix,dp->fbids,dp->fasks,dp->fhighs,dp->flows);
|
|
prices777_instaforex(dp->ilogmatrix,dp->itimestamps,dp->ibids,dp->iasks);
|
|
double btcdbtc,btcusd;
|
|
price777_update(&btcusd,&btcdbtc);
|
|
if ( btcusd > SMALLVAL )
|
|
dxblend(&dp->btcusd,btcusd,0.99);
|
|
if ( btcdbtc > SMALLVAL )
|
|
dxblend(&dp->btcdbtc,btcdbtc,0.99);
|
|
if ( BUNDLE.data.btcusd == 0 )
|
|
BUNDLE.data.btcusd = dp->btcusd;
|
|
if ( BUNDLE.data.btcdbtc == 0 )
|
|
BUNDLE.data.btcdbtc = dp->btcdbtc;
|
|
if ( dp->ecbmatrix[USD][USD] > SMALLVAL && dp->ecbmatrix[CNY][CNY] > SMALLVAL )
|
|
BUNDLE.cnyusd = (dp->ecbmatrix[CNY][CNY] / dp->ecbmatrix[USD][USD]);
|
|
portable_mutex_lock(&mutex);
|
|
BUNDLE.data = *dp;
|
|
portable_mutex_unlock(&mutex);
|
|
//kv777_write(BUNDLE.kv,"data",5,&BUNDLE.data,sizeof(BUNDLE.data));
|
|
prices777_RTupdate(BUNDLE.cryptovols,BUNDLE.data.RTmetals,BUNDLE.data.RTprices,&BUNDLE.data);
|
|
//printf("update finished\n");
|
|
void peggy();
|
|
peggy();
|
|
didinit = 1;
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
void prices777_sim(uint32_t now,int32_t numiters)
|
|
{
|
|
double btca,btcb,btcd,btc,btcdusd,basevals[MAX_CURRENCIES],btcdprices[MAX_CURRENCIES+1];
|
|
int32_t i,j,datenum,seconds; uint32_t timestamp,starttime = (uint32_t)time(NULL);
|
|
for (i=0; i<numiters; i++)
|
|
{
|
|
timestamp = now - (rand() % (3600*24*64));
|
|
btca = 1000. * prices777_splineval(&BUNDLE.splines[MAX_CURRENCIES+0],timestamp,0);
|
|
btcb = 1000. * prices777_splineval(&BUNDLE.splines[MAX_CURRENCIES+1],timestamp,0);
|
|
btc = _pairaved(btca,btcb);
|
|
btcd = .01 * prices777_splineval(&BUNDLE.splines[MAX_CURRENCIES+2],timestamp,0);
|
|
btcdusd = (btc * btcd);
|
|
datenum = OS_conv_unixtime(&seconds,timestamp);
|
|
for (j=0; j<MAX_CURRENCIES; j++)
|
|
{
|
|
basevals[j] = prices777_splineval(&BUNDLE.splines[j],timestamp,0);
|
|
btcdprices[j] = basevals[j] / (btcdusd * basevals[USD]);
|
|
}
|
|
if ( (i % 100000) == 0 )
|
|
{
|
|
printf("%d:%02d:%02d %.8f %.8f -> USD %.8f (EURUSD %.8f %.8f) ",datenum,seconds/3600,(seconds%3600)/60,btc,btcd,btcdusd,btcdprices[EUR]/btcdprices[USD],basevals[EUR]/basevals[USD]);
|
|
for (j=0; j<MAX_CURRENCIES; j++)
|
|
printf("%.8f ",btcdprices[j]);
|
|
printf("\n");
|
|
}
|
|
}
|
|
printf("sim took %ld seconds\n",(long)(time(NULL) - starttime));
|
|
}
|
|
|
|
void prices777_getlist(char *retbuf)
|
|
{
|
|
int32_t i,j; struct prices777 *prices; char pair[16],*jsonstr; cJSON *json,*array,*item;
|
|
json = cJSON_CreateObject();
|
|
array = cJSON_CreateArray();
|
|
for (i=0; i<sizeof(CURRENCIES)/sizeof(*CURRENCIES); i++)
|
|
cJSON_AddItemToArray(array,cJSON_CreateString(CURRENCIES[i]));
|
|
cJSON_AddItemToObject(json,"currency",array);
|
|
array = cJSON_CreateArray();
|
|
for (i=0; i<32; i++)
|
|
for (j=0; j<32; j++)
|
|
{
|
|
if ( i != j )
|
|
{
|
|
sprintf(pair,"%s%s",CURRENCIES[i],CURRENCIES[j]);
|
|
cJSON_AddItemToArray(array,cJSON_CreateString(pair));
|
|
}
|
|
}
|
|
cJSON_AddItemToObject(json,"pairs",array);
|
|
array = cJSON_CreateArray();
|
|
for (i=0; i<sizeof(CONTRACTS)/sizeof(*CONTRACTS); i++)
|
|
cJSON_AddItemToArray(array,cJSON_CreateString(CONTRACTS[i]));
|
|
cJSON_AddItemToObject(json,"contract",array);
|
|
array = cJSON_CreateArray();
|
|
for (i=0; i<BUNDLE.num; i++)
|
|
{
|
|
if ( (prices= BUNDLE.ptrs[i]) != 0 )
|
|
{
|
|
item = cJSON_CreateObject();
|
|
cJSON_AddItemToObject(item,prices->exchange,cJSON_CreateString(prices->contract));
|
|
cJSON_AddItemToObject(item,"base",cJSON_CreateString(prices->base));
|
|
if ( prices->rel[0] != 0 )
|
|
cJSON_AddItemToObject(item,"rel",cJSON_CreateString(prices->rel));
|
|
//printf("(%s) (%s) (%s)\n",prices->contract,prices->base,prices->rel);
|
|
cJSON_AddItemToArray(array,item);
|
|
}
|
|
}
|
|
cJSON_AddItemToObject(json,"result",cJSON_CreateString("success"));
|
|
cJSON_AddItemToObject(json,"list",array);
|
|
jsonstr = cJSON_Print(json), _stripwhite(jsonstr,' '), free_json(json);
|
|
strcpy(retbuf,jsonstr), free(jsonstr);
|
|
printf("list -> (%s)\n",retbuf);
|
|
}
|
|
|
|
|
|
#endif
|
|
|