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.
 
 
 
 
 
 

3456 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&currency=%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&currency=%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&currencyPair=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&currencyPair=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&currencyPair=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&currencyPair=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&currencyPair=BTC_BTCD&start=1405699200&end=9999999999&period=86400
// https://poloniex.com/public?command=returnTradeHistory&currencyPair=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();
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