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.
 
 
 
 
 
 

880 lines
37 KiB

/******************************************************************************
* Copyright © 2014-2015 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_quotes_h
#define xcode_quotes_h
#ifdef oldway
int32_t make_jumpiQ(uint64_t refbaseid,uint64_t refrelid,int32_t flip,struct InstantDEX_quote *iQ,struct InstantDEX_quote *baseiQ,struct InstantDEX_quote *reliQ,char *gui,int32_t duration)
{
uint64_t baseamount,relamount,frombase,fromrel,tobase,torel;
double vol;
char exchange[64];
uint32_t timestamp;
frombase = baseiQ->baseamount, fromrel = baseiQ->relamount;
tobase = reliQ->baseamount, torel = reliQ->relamount;
if ( make_jumpquote(refbaseid,refrelid,&baseamount,&relamount,&frombase,&fromrel,&tobase,&torel) == 0. )
return(0);
if ( (timestamp= reliQ->timestamp) > baseiQ->timestamp )
timestamp = baseiQ->timestamp;
iQ_exchangestr(exchange,iQ);
create_InstantDEX_quote(iQ,timestamp,0,calc_quoteid(baseiQ) ^ calc_quoteid(reliQ),0.,0.,refbaseid,baseamount,refrelid,relamount,exchange,0,gui,baseiQ,reliQ,duration);
if ( Debuglevel > 2 )
printf("jump%s: %f (%llu/%llu) %llu %llu (%f %f) %llu %llu\n",flip==0?"BID":"ASK",calc_price_volume(&vol,iQ->baseamount,iQ->relamount),(long long)baseamount,(long long)relamount,(long long)frombase,(long long)fromrel,calc_price_volume(&vol,frombase,fromrel),calc_price_volume(&vol,tobase,torel),(long long)tobase,(long long)torel);
iQ->isask = flip;
iQ->minperc = baseiQ->minperc;
if ( reliQ->minperc > iQ->minperc )
iQ->minperc = reliQ->minperc;
return(1);
}
#else
struct InstantDEX_quote *AllQuotes;
void clear_InstantDEX_quoteflags(struct InstantDEX_quote *iQ)
{
//duration:14,wallet:1,a:1,isask:1,expired:1,closed:1,swap:1,responded:1,matched:1,feepaid:1,automatch:1,pending:1,minperc:7;
iQ->s.a = iQ->s.expired = iQ->s.swap = iQ->s.feepaid = 0;
iQ->s.closed = iQ->s.pending = iQ->s.responded = iQ->s.matched = 0;
}
void cancel_InstantDEX_quote(struct InstantDEX_quote *iQ) { iQ->s.closed = 1; }
int32_t InstantDEX_uncalcsize() { struct InstantDEX_quote iQ; return(sizeof(iQ.hh) + sizeof(iQ.s.quoteid) + sizeof(iQ.s.price) + sizeof(iQ.s.vol)); }
int32_t iQcmp(struct InstantDEX_quote *iQA,struct InstantDEX_quote *iQB)
{
if ( iQA->s.isask == iQB->s.isask && iQA->s.baseid == iQB->s.baseid && iQA->s.relid == iQB->s.relid && iQA->s.baseamount == iQB->s.baseamount && iQA->s.relamount == iQB->s.relamount )
return(0);
else if ( iQA->s.isask != iQB->s.isask && iQA->s.baseid == iQB->s.relid && iQA->s.relid == iQB->s.baseid && iQA->s.baseamount == iQB->s.relamount && iQA->s.relamount == iQB->s.baseamount )
return(0);
return(-1);
}
uint64_t calc_txid(unsigned char *buf,int32_t len)
{
bits256 hash;
vcalc_sha256(0,hash.bytes,buf,len);
return(hash.txid);
}
uint64_t calc_quoteid(struct InstantDEX_quote *iQ)
{
struct InstantDEX_quote Q;
if ( iQ == 0 )
return(0);
if ( iQ->s.duration == 0 || iQ->s.duration > ORDERBOOK_EXPIRATION )
iQ->s.duration = ORDERBOOK_EXPIRATION;
if ( iQ->s.quoteid == 0 )
{
Q = *iQ;
clear_InstantDEX_quoteflags(&Q);
if ( Q.s.isask != 0 )
{
Q.s.baseid = iQ->s.relid, Q.s.baseamount = iQ->s.relamount;
Q.s.relid = iQ->s.baseid, Q.s.relamount = iQ->s.baseamount;
Q.s.isask = Q.s.minperc = 0;
}
return(calc_txid((uint8_t *)((long)&Q + InstantDEX_uncalcsize()),sizeof(Q) - InstantDEX_uncalcsize()));
} return(iQ->s.quoteid);
}
struct InstantDEX_quote *find_iQ(uint64_t quoteid)
{
struct InstantDEX_quote *iQ;
HASH_FIND(hh,AllQuotes,&quoteid,sizeof(quoteid),iQ);
return(iQ);
}
struct InstantDEX_quote *delete_iQ(uint64_t quoteid)
{
struct InstantDEX_quote *iQ;
if ( (iQ= find_iQ(quoteid)) != 0 )
{
HASH_DELETE(hh,AllQuotes,iQ);
}
return(iQ);
}
struct InstantDEX_quote *findquoteid(uint64_t quoteid,int32_t evenclosed)
{
struct InstantDEX_quote *iQ;
if ( (iQ= find_iQ(quoteid)) != 0 )
{
if ( evenclosed != 0 || iQ->s.closed == 0 )
{
if ( calc_quoteid(iQ) == quoteid )
return(iQ);
else printf("calc_quoteid %llu vs %llu\n",(long long)calc_quoteid(iQ),(long long)quoteid);
} //else printf("quoteid.%llu closed.%d\n",(long long)quoteid,iQ->closed);
} else printf("couldnt find %llu\n",(long long)quoteid);
return(0);
}
int32_t cancelquote(char *NXTaddr,uint64_t quoteid)
{
struct InstantDEX_quote *iQ;
if ( (iQ= findquoteid(quoteid,0)) != 0 && iQ->s.offerNXT == calc_nxt64bits(NXTaddr) && iQ->exchangeid == INSTANTDEX_EXCHANGEID )
{
cancel_InstantDEX_quote(iQ);
return(1);
}
return(0);
}
struct InstantDEX_quote *create_iQ(struct InstantDEX_quote *iQ,char *walletstr)
{
struct InstantDEX_quote *newiQ,*tmp; struct prices777 *prices; int32_t inverted; long len = 0;
if ( walletstr != 0 && (len= strlen(walletstr)) > 0 )
iQ->s.wallet = 1, len++;
calc_quoteid(iQ);
printf("createiQ %llu/%llu %f %f quoteid.%llu offerNXT.%llu wallet.%d (%s)\n",(long long)iQ->s.baseid,(long long)iQ->s.relid,iQ->s.price,iQ->s.vol,(long long)iQ->s.quoteid,(long long)iQ->s.offerNXT,iQ->s.wallet,walletstr!=0?walletstr:"");
if ( (newiQ= find_iQ(iQ->s.quoteid)) != 0 )
return(newiQ);
newiQ = calloc(1,sizeof(*newiQ) + len);
*newiQ = *iQ;
if ( len != 0 )
memcpy(newiQ->walletstr,walletstr,len);
HASH_ADD(hh,AllQuotes,s.quoteid,sizeof(newiQ->s.quoteid),newiQ);
if ( (prices= prices777_find(&inverted,iQ->s.baseid,iQ->s.relid,INSTANTDEX_NAME)) != 0 )
prices->dirty++;
{
struct InstantDEX_quote *checkiQ;
if ( (checkiQ= find_iQ(iQ->s.quoteid)) == 0 || iQcmp(iQ,checkiQ) != 0 )//memcmp((uint8_t *)((long)checkiQ + sizeof(checkiQ->hh) + sizeof(checkiQ->quoteid)),(uint8_t *)((long)iQ + sizeof(iQ->hh) + sizeof(iQ->quoteid)),sizeof(*iQ) - sizeof(iQ->hh) - sizeof(iQ->quoteid)) != 0 )
{
int32_t i;
for (i=(sizeof(iQ->hh) - sizeof(iQ->s.quoteid)); i<sizeof(*iQ) - sizeof(iQ->hh) - sizeof(iQ->s.quoteid); i++)
printf("%02x ",((uint8_t *)iQ)[i]);
printf("iQ\n");
for (i=(sizeof(checkiQ->hh) + sizeof(checkiQ->s.quoteid)); i<sizeof(*checkiQ) - sizeof(checkiQ->hh) - sizeof(checkiQ->s.quoteid); i++)
printf("%02x ",((uint8_t *)checkiQ)[i]);
printf("checkiQ\n");
printf("error finding iQ after adding %llu vs %llu\n",(long long)checkiQ->s.quoteid,(long long)iQ->s.quoteid);
}
}
HASH_ITER(hh,AllQuotes,iQ,tmp)
{
if ( iQ->s.expired != 0 )
{
printf("quoteid.%llu expired, purging\n",(long long)iQ->s.expired);
delete_iQ(iQ->s.quoteid);
}
}
return(newiQ);
}
#ifdef later
cJSON *pangea_walletitem(cJSON *walletitem,struct coin777 *coin,int32_t rakemillis,int64_t bigblind,int64_t ante,int32_t minbuyin,int32_t maxbuyin)
{
char *addr; struct destbuf pubkey;
if ( walletitem == 0 )
walletitem = cJSON_CreateObject();
//printf("call get_acct_coinaddr.%s (%s) (%s)\n",coin->name,coin->serverport,coin->userpass);
if ( coin->pangeapubkey[0] == 0 || coin->pangeacoinaddr[0] == 0 )
{
if ( strcmp("NXT",coin->name) == 0 )
{
}
else if ( (addr= get_acct_coinaddr(coin->pangeacoinaddr,coin->name,coin->serverport,coin->userpass,"pangea")) != 0 )
{
//printf("get_pubkey\n");
get_pubkey(&pubkey,coin->name,coin->serverport,coin->userpass,coin->pangeacoinaddr);
strcpy(coin->pangeapubkey,pubkey.buf);
}
}
jaddstr(walletitem,"pubkey",coin->pangeapubkey);
jaddstr(walletitem,"coinaddr",coin->pangeacoinaddr);
jaddnum(walletitem,"rakemillis",rakemillis);
jaddnum(walletitem,"minbuyin",minbuyin);
jaddnum(walletitem,"maxbuyin",maxbuyin);
jadd64bits(walletitem,"bigblind",bigblind);
jadd64bits(walletitem,"ante",ante);
return(walletitem);
}
cJSON *set_walletstr(cJSON *walletitem,char *walletstr,struct InstantDEX_quote *iQ)
{
char pubkeystr[128],pkhash[128],base[64],rel[64],fieldA[64],fieldB[64],fieldpkhash[64],*pubA,*pubB,*pkhashstr,*str,*exchangestr;
struct coin777 *coin; int32_t flip = 0;
if ( walletstr != 0 && walletitem == 0 )
walletitem = cJSON_Parse(walletstr);
if ( walletitem == 0 )
walletitem = cJSON_CreateObject();
unstringbits(base,iQ->s.basebits), unstringbits(rel,iQ->s.relbits);
flip = (iQ->s.offerNXT != IGUANA_MY64BITS);
if ( strcmp(base,"NXT") != 0 )
coin = coin777_find(base,1);
else if ( strcmp(rel,"NXT") != 0 )
coin = coin777_find(rel,1), flip ^= 1;
else coin = 0;
if ( coin != 0 )
{
if ( (exchangestr= exchange_str(iQ->exchangeid)) != 0 && strcmp(exchangestr,"pangea") == 0 )
pangea_walletitem(walletitem,coin,iQ->s.minperc,iQ->s.baseamount,iQ->s.relamount,iQ->s.minbuyin,iQ->s.maxbuyin);
else
{
//printf("START.(%s)\n",jprint(walletitem,0));
if ( (iQ->s.isask ^ flip) == 0 )
{
sprintf(fieldA,"%spubA",coin->name);
if ( (pubA= jstr(walletitem,fieldA)) != 0 )
cJSON_DeleteItemFromObject(walletitem,fieldA);
jaddstr(walletitem,fieldA,coin->atomicsendpubkey);
//printf("replaceA\n");
}
else
{
sprintf(fieldB,"%spubB",coin->name);
if ( (pubB= jstr(walletitem,fieldB)) != 0 )
cJSON_DeleteItemFromObject(walletitem,fieldB);
jaddstr(walletitem,fieldB,coin->atomicrecvpubkey);
sprintf(fieldpkhash,"%spkhash",coin->name);
if ( (pkhashstr= jstr(walletitem,fieldpkhash)) != 0 )
cJSON_DeleteItemFromObject(walletitem,fieldpkhash);
subatomic_pubkeyhash(pubkeystr,pkhash,coin,iQ->s.quoteid);
jaddstr(walletitem,fieldpkhash,pkhash);
//printf("replaceB\n");
}
}
str = jprint(walletitem,0);
strcpy(walletstr,str);
free(str);
return(walletitem);
}
return(0);
}
#endif
char *InstantDEX_str(char *walletstr,char *buf,int32_t extraflag,struct InstantDEX_quote *iQ)
{
cJSON *json; char _buf[4096],base[64],rel[64],*str;
unstringbits(base,iQ->s.basebits), unstringbits(rel,iQ->s.relbits);
if ( buf == 0 )
buf = _buf;
sprintf(buf,"{\"quoteid\":\"%llu\",\"base\":\"%s\",\"baseid\":\"%llu\",\"baseamount\":\"%llu\",\"rel\":\"%s\",\"relid\":\"%llu\",\"relamount\":\"%llu\",\"price\":%.8f,\"volume\":%.8f,\"offerNXT\":\"%llu\",\"timestamp\":\"%u\",\"isask\":\"%u\",\"exchange\":\"%s\",\"gui\":\"%s\"}",(long long)iQ->s.quoteid,base,(long long)iQ->s.baseid,(long long)iQ->s.baseamount,rel,(long long)iQ->s.relid,(long long)iQ->s.relamount,iQ->s.price,iQ->s.vol,(long long)iQ->s.offerNXT,iQ->s.timestamp,iQ->s.isask,exchange_str(iQ->exchangeid),iQ->gui);
if ( extraflag != 0 )
{
sprintf(buf + strlen(buf) - 1,",\"plugin\":\"relay\",\"destplugin\":\"InstantDEX\",\"method\":\"busdata\",\"submethod\":\"%s\"}",(iQ->s.isask != 0) ? "ask" : "bid");
}
//printf("InstantDEX_str.(%s)\n",buf);
if ( (json= cJSON_Parse(buf)) != 0 )
{
#ifdef later
char _buf[4096],_walletstr[256],base[64],rel[64],*exchange,*str; cJSON *walletitem,*json; struct coin777 *coin;
if ( walletstr == 0 )
{
walletstr = _walletstr;
walletstr[0] = 0;
}
if ( (exchange= exchange_str(iQ->exchangeid)) != 0 )
{
coin = coin777_find(base,0);
if ( strcmp(exchange,"wallet") == 0 )
walletitem = set_walletstr(0,walletstr,iQ);
else if ( strcmp(exchange,"pangea") == 0 && walletstr[0] == 0 && coin != 0 )
walletitem = pangea_walletitem(0,coin,iQ->s.minperc,iQ->s.baseamount,iQ->s.relamount,iQ->s.minbuyin,iQ->s.maxbuyin);
else walletitem = 0;
if ( walletitem != 0 )
{
jadd(json,"wallet",walletitem);
strcpy(walletstr,jprint(walletitem,0));
}
//printf("exchange.(%s) iswallet.%d (%s) base.(%s) coin.%p (%s)\n",exchange,iQ->s.wallet,walletstr,base,coin,jprint(json,0));
} else printf("InstantDEX_str cant find exchangeid.%d\n",iQ->exchangeid);
#endif
str = jprint(json,1);
strcpy(buf,str);
//printf("str.(%s) %p\n",buf,buf);
free(str);
} else printf("InstantDEX_str cant parse.(%s)\n",buf);
if ( buf == _buf )
return(clonestr(buf));
else return(buf);
}
uint64_t _get_AEquote(char *str,uint64_t orderid)
{
cJSON *json;
uint64_t nxt64bits = 0;
char cmd[256],*jsonstr;
sprintf(cmd,"requestType=get%sOrder&order=%llu",str,(long long)orderid);
if ( (jsonstr= issue_NXTPOST(cmd)) != 0 )
{
//printf("(%s) -> (%s)\n",cmd,jsonstr);
if ( (json= cJSON_Parse(jsonstr)) != 0 )
{
nxt64bits = get_API_nxt64bits(cJSON_GetObjectItem(json,"account"));
free_json(json);
}
free(jsonstr);
}
return(nxt64bits);
}
char *cancel_NXTorderid(char *NXTaddr,char *nxtsecret,uint64_t orderid)
{
uint64_t nxt64bits; char cmd[1025],secret[8192],*str = "Bid",*retstr = 0;
if ( (nxt64bits= _get_AEquote(str,orderid)) == 0 )
str = "Ask", nxt64bits = _get_AEquote(str,orderid);
if ( nxt64bits == calc_nxt64bits(NXTaddr) )
{
escape_code(secret,nxtsecret);
sprintf(cmd,"requestType=cancel%sOrder&secretPhrase=%s&feeNQT=%lld&deadline=%d&order=%llu",str,secret,(long long)MIN_NQTFEE,DEFAULT_NXT_DEADLINE,(long long)orderid);
retstr = issue_NXTPOST(cmd);
//printf("(%s) -> (%s)\n",cmd,retstr);
}
return(retstr);
}
char *InstantDEX_cancelorder(cJSON *argjson,char *activenxt,char *secret,uint64_t orderid,uint64_t quoteid)
{
struct InstantDEX_quote *iQ; cJSON *json,*array,*item; char numstr[64],*retstr,*exchangestr;
uint64_t quoteids[256]; int32_t i,exchangeid,n=0; struct exchange_info *exchange;
if ( (exchangestr= jstr(argjson,"exchange")) != 0 && (exchange= find_exchange(&exchangeid,exchangestr)) != 0 )
{
if ( exchange->issue.cancelorder != 0 )
{
if ( (retstr= (*exchange->issue.cancelorder)(&exchange->cHandle,exchange,argjson,quoteid)) == 0 )
retstr = clonestr("{\"result\":\"nothing returned from exchange\"}");
return(retstr);
}
else return(clonestr("{\"error\":\"no cancelorder function\"}"));
}
memset(quoteids,0,sizeof(quoteids));
json = cJSON_CreateObject(), array = cJSON_CreateArray();
if ( quoteid != 0 )
quoteids[n++] = quoteid;
//n += InstantDEX_quoteids(quoteids+n,orderid);
for (i=0; i<n; i++)
{
quoteid = quoteids[i];
if ( (retstr= cancel_NXTorderid(activenxt,secret,quoteid)) != 0 )
{
if ( (iQ= findquoteid(quoteid,0)) != 0 && iQ->s.offerNXT == calc_nxt64bits(activenxt) )
cancel_InstantDEX_quote(iQ);
if ( (item= cJSON_Parse(retstr)) != 0 )
jaddi(array,item);
free(retstr);
}
cancelquote(activenxt,quoteid);
}
if ( orderid != 0 )
{
if ( cancelquote(activenxt,orderid) != 0 )
sprintf(numstr,"%llu",(long long)orderid), jaddstr(json,"ordercanceled",numstr);
}
return(jprint(json,1));
}
char *InstantDEX_orderstatus(cJSON *argjson,uint64_t orderid,uint64_t quoteid)
{
struct InstantDEX_quote *iQ = 0; char *exchangestr,*str; struct exchange_info *exchange; int32_t exchangeid;
if ( (exchangestr= jstr(argjson,"exchange")) != 0 && (exchange= find_exchange(&exchangeid,exchangestr)) != 0 )
{
if ( exchange->issue.orderstatus != 0 )
{
if ( (str= (*exchange->issue.orderstatus)(&exchange->cHandle,exchange,argjson,quoteid)) == 0 )
str = clonestr("{\"result\":\"nothing returned from exchange\"}");
return(str);
}
else return(clonestr("{\"error\":\"no orderstatus function\"}"));
}
if ( (iQ= find_iQ(orderid)) != 0 || (iQ= find_iQ(quoteid)) != 0 )
return(InstantDEX_str(0,0,0,iQ));
return(clonestr("{\"error\":\"couldnt find orderid\"}"));
}
char *InstantDEX_openorders(cJSON *argjson,char *NXTaddr,int32_t allorders)
{
struct InstantDEX_quote *iQ,*tmp; char buf[4096],*exchangestr,*jsonstr,*str; uint32_t now,duration;
cJSON *json,*array,*item; uint64_t nxt64bits; struct exchange_info *exchange; int32_t exchangeid;
if ( (exchangestr= jstr(argjson,"exchange")) != 0 && (exchange= find_exchange(&exchangeid,exchangestr)) != 0 )
{
if ( exchange->issue.openorders != 0 )
{
if ( (str= (*exchange->issue.openorders)(&exchange->cHandle,exchange,argjson)) == 0 )
str = clonestr("{\"result\":\"nothing returned from exchange\"}");
return(str);
}
else return(clonestr("{\"error\":\"no orderstatus function\"}"));
}
nxt64bits = calc_nxt64bits(NXTaddr);
now = (uint32_t)time(NULL);
json = cJSON_CreateObject(), array = cJSON_CreateArray();
HASH_ITER(hh,AllQuotes,iQ,tmp)
{
if ( (duration= iQ->s.duration) == 0 )
duration = ORDERBOOK_EXPIRATION;
if ( iQ->s.timestamp > (now + duration) )
iQ->s.expired = iQ->s.closed = 1;
if ( iQ->s.offerNXT == nxt64bits && (allorders != 0 || iQ->s.closed == 0) )
{
if ( (jsonstr= InstantDEX_str(0,buf,0,iQ)) != 0 && (item= cJSON_Parse(jsonstr)) != 0 )
jaddi(array,item);
}
}
jadd(json,"openorders",array);
return(jprint(json,1));
}
cJSON *InstantDEX_specialorders(uint64_t *quoteidp,uint64_t nxt64bits,char *base,char *special,uint64_t baseamount,int32_t addrtype)
{
struct InstantDEX_quote *iQ,*tmp; int32_t exchangeid; uint32_t i,n,now,duration,ismine = 0;
uint64_t basebits; cJSON *item=0,*array = 0; char *coinaddr=0,*pubkey,checkaddr[128];
now = (uint32_t)time(NULL);
basebits = stringbits(base);
if ( special == 0 || find_exchange(&exchangeid,special) == 0 )
exchangeid = 0;
n = 0;
*quoteidp = 0;
HASH_ITER(hh,AllQuotes,iQ,tmp)
{
//printf("iter Q.%llu b.%llu\n",(long long)iQ->s.quoteid,(long long)iQ->s.basebits);
if ( (duration= iQ->s.duration) == 0 )
duration = ORDERBOOK_EXPIRATION;
if ( iQ->s.timestamp > (now + duration) )
{
iQ->s.expired = iQ->s.closed = 1;
printf("expire order %llu\n",(long long)iQ->s.quoteid);
continue;
}
if ( iQ->s.basebits == basebits && (exchangeid == 0 || iQ->exchangeid == exchangeid) )
{
//printf("matched basebits\n");
if ( strcmp(special,"pangea") == 0 )
{
checkaddr[0] = 0;
if ( iQ->s.wallet != 0 && (item= cJSON_Parse(iQ->walletstr)) != 0 && (coinaddr= jstr(item,"coinaddr")) != 0 && coinaddr[0] != 0 && (pubkey= jstr(item,"pubkey")) != 0 && pubkey[0] != 0 )
btc_coinaddr(coinaddr,addrtype,pubkey);
if ( item != 0 )
free_json(item);
if ( coinaddr == 0 || strcmp(coinaddr,checkaddr) != 0 )
{
printf("mismatched pangea coinaddr (%s) vs (%s) or baseamount %.8f vs %.8f\n",coinaddr,checkaddr,dstr(baseamount),dstr(iQ->s.baseamount));
continue;
}
}
if ( n > 0 )
{
for (i=0; i<n; i++)
{
if ( iQ->s.offerNXT == j64bits(jitem(array,i),0) )
break;
}
//printf("found duplicate\n");
} else i = 0;
if ( i == n )
{
if ( iQ->s.offerNXT == nxt64bits )
{
ismine = 1;
if ( *quoteidp == 0 )
*quoteidp = iQ->s.quoteid;
}
if ( array == 0 )
array = cJSON_CreateArray();
jaddi64bits(array,iQ->s.offerNXT);
//printf("add %llu\n",(long long)iQ->s.offerNXT);
}
} //else printf("quote.%llu basebits.%llu\n",(long long)iQ->s.quoteid,(long long)iQ->s.basebits);
}
if ( ismine == 0 )
free_json(array), array = 0;
//printf("ismine.%d n.%d array.%d\n",ismine,n,array==0?0:cJSON_GetArraySize(array));
return(array);
}
int _decreasing_quotes(const void *a,const void *b)
{
#define order_a ((struct InstantDEX_quote *)a)
#define order_b ((struct InstantDEX_quote *)b)
if ( order_b->s.price > order_a->s.price )
return(1);
else if ( order_b->s.price < order_a->s.price )
return(-1);
return(0);
#undef order_a
#undef order_b
}
int _increasing_quotes(const void *a,const void *b)
{
#define order_a ((struct InstantDEX_quote *)a)
#define order_b ((struct InstantDEX_quote *)b)
if ( order_b->s.price > order_a->s.price )
return(-1);
else if ( order_b->s.price < order_a->s.price )
return(1);
return(0);
#undef order_a
#undef order_b
}
cJSON *prices777_orderjson(struct InstantDEX_quote *iQ)
{
cJSON *item = cJSON_CreateArray();
jaddinum(item,iQ->s.price);
jaddinum(item,iQ->s.vol);
jaddi64bits(item,iQ->s.quoteid);
return(item);
}
cJSON *InstantDEX_orderbook(struct prices777 *prices)
{
struct InstantDEX_quote *ptr,iQ,*tmp,*askvals=0,*bidvals=0; cJSON *json,*bids,*asks; uint32_t now,duration;
int32_t i,isask,iter,n,m,numbids,numasks,invert;
json = cJSON_CreateObject(), bids = cJSON_CreateArray(), asks = cJSON_CreateArray();
now = (uint32_t)time(NULL);
for (iter=numbids=numasks=n=m=0; iter<2; iter++)
{
HASH_ITER(hh,AllQuotes,ptr,tmp)
{
iQ = *ptr;
if ( (duration= iQ.s.duration) == 0 )
duration = ORDERBOOK_EXPIRATION;
if ( iQ.s.timestamp > (now + duration) )
{
iQ.s.expired = iQ.s.closed = 1;
continue;
}
if ( Debuglevel > 2 )
printf("iterate quote.%llu\n",(long long)iQ.s.quoteid);
if ( prices777_equiv(ptr->s.baseid) == prices777_equiv(prices->baseid) && prices777_equiv(ptr->s.relid) == prices777_equiv(prices->relid) )
invert = 0;
else if ( prices777_equiv(ptr->s.relid) == prices777_equiv(prices->baseid) && prices777_equiv(ptr->s.baseid) == prices777_equiv(prices->relid) )
invert = 1;
else continue;
if ( ptr->s.pending != 0 )
continue;
isask = iQ.s.isask;
if ( invert != 0 )
isask ^= 1;
if ( invert != 0 )
{
if ( iQ.s.price > SMALLVAL )
iQ.s.vol *= iQ.s.price, iQ.s.price = 1. / iQ.s.price;
else iQ.s.price = prices777_price_volume(&iQ.s.vol,iQ.s.relamount,iQ.s.baseamount);
}
else if ( iQ.s.price <= SMALLVAL )
iQ.s.price = prices777_price_volume(&iQ.s.vol,iQ.s.baseamount,iQ.s.relamount);
if ( iter == 0 )
{
if ( isask != 0 )
numasks++;
else numbids++;
}
else
{
if ( isask == 0 && n < numbids )
bidvals[n++] = iQ;
else if ( isask != 0 && m < numasks )
askvals[m++] = iQ;
}
}
if ( iter == 0 )
{
if ( numbids > 0 )
bidvals = calloc(numbids,sizeof(*bidvals));
if ( numasks > 0 )
askvals = calloc(numasks,sizeof(*askvals));
}
}
if ( numbids > 0 )
{
if ( n > 0 )
{
qsort(bidvals,n,sizeof(*bidvals),_decreasing_quotes);
for (i=0; i<n; i++)
jaddi(bids,prices777_orderjson(&bidvals[i]));
}
free(bidvals);
}
if ( numasks > 0 )
{
if ( m > 0 )
{
qsort(askvals,m,sizeof(*askvals),_increasing_quotes);
for (i=0; i<m; i++)
jaddi(asks,prices777_orderjson(&askvals[i]));
}
free(askvals);
}
jadd(json,"bids",bids), jadd(json,"asks",asks);
return(json);
}
double ordermetric(double price,double vol,int32_t dir,double refprice,double refvol)
{
double metric = 0.;
if ( vol > (refvol * INSTANTDEX_MINVOLPERC) )//&& refvol > (vol * iQ->s.minperc * .01) )
{
if ( vol < refvol )
metric = (vol / refvol);
else metric = 1.;
if ( dir > 0 && price < (refprice * (1. + INSTANTDEX_PRICESLIPPAGE) + SMALLVAL) )
metric *= (1. + (refprice - price)/refprice);
else if ( dir < 0 && price > (refprice * (1. - INSTANTDEX_PRICESLIPPAGE) - SMALLVAL) )
metric *= (1. + (price - refprice)/refprice);
else metric = 0.;
if ( metric != 0. )
{
printf("price %.8f vol %.8f | %.8f > %.8f? %.8f > %.8f?\n",price,vol,vol,(refvol * INSTANTDEX_MINVOLPERC),refvol,(vol * INSTANTDEX_MINVOLPERC));
printf("price %f against %f or %f\n",price,(refprice * (1. + INSTANTDEX_PRICESLIPPAGE) + SMALLVAL),(refprice * (1. - INSTANTDEX_PRICESLIPPAGE) - SMALLVAL));
printf("metric %f\n",metric);
}
}
return(metric);
}
char *autofill(char *remoteaddr,struct InstantDEX_quote *refiQ,char *NXTaddr,char *NXTACCTSECRET)
{
double price,volume,revprice,revvol,metric,bestmetric = 0.; int32_t dir,inverted; uint64_t nxt64bits; char *retstr=0;
struct InstantDEX_quote *iQ,*tmp,*bestiQ; struct prices777 *prices; uint32_t duration,now = (uint32_t)time(NULL);
return(0);
nxt64bits = calc_nxt64bits(NXTaddr);
memset(&bestiQ,0,sizeof(bestiQ));
dir = (refiQ->s.isask != 0) ? -1 : 1;
HASH_ITER(hh,AllQuotes,iQ,tmp)
{
if ( (duration= refiQ->s.duration) == 0 )
duration = ORDERBOOK_EXPIRATION;
if ( iQ->s.timestamp > (now + duration) )
iQ->s.expired = iQ->s.closed = 1;
if ( iQ->s.offerNXT == nxt64bits && iQ->s.closed == 0 && iQ->s.pending == 0 )
{
if ( iQ->s.baseid == refiQ->s.baseid && iQ->s.relid == refiQ->s.relid && iQ->s.isask != refiQ->s.isask && (metric= ordermetric(iQ->s.price,iQ->s.vol,dir,refiQ->s.price,refiQ->s.vol)) > bestmetric )
{
bestmetric = metric;
bestiQ = iQ;
}
else if ( iQ->s.baseid == refiQ->s.relid && iQ->s.relid == refiQ->s.baseid && iQ->s.isask == refiQ->s.isask && iQ->s.price > SMALLVAL )
{
revvol = (iQ->s.price * iQ->s.vol), revprice = (1. / iQ->s.price);
if ( (metric= ordermetric(revprice,revvol,dir,refiQ->s.price,refiQ->s.vol)) > bestmetric )
{
bestmetric = metric;
bestiQ = iQ;
}
}
}
}
if ( bestmetric > 0. )
{
if ( (prices= prices777_find(&inverted,bestiQ->s.baseid,bestiQ->s.relid,exchange_str(bestiQ->exchangeid))) != 0 )
{
printf("isask.%d %f %f -> bestmetric %f inverted.%d autofill dir.%d price %f vol %f\n",bestiQ->s.isask,bestiQ->s.price,bestiQ->s.vol,bestmetric,inverted,dir,refiQ->s.price,refiQ->s.vol);
if ( bestiQ->s.isask != 0 )
dir = -1;
else dir = 1;
if ( inverted != 0 )
{
dir *= -1;
volume = (bestiQ->s.price * bestiQ->s.vol);
price = 1. / bestiQ->s.price;
printf("price inverted (%f %f) -> (%f %f)\n",bestiQ->s.price,bestiQ->s.vol,price,volume);
} else price = bestiQ->s.price, volume = bestiQ->s.vol;
retstr = prices777_trade(0,0,0,0,1,0,NXTaddr,NXTACCTSECRET,prices,dir,price,volume,bestiQ,0,bestiQ->s.quoteid,0);
}
}
return(retstr);
}
char *automatch(struct prices777 *prices,int32_t dir,double refprice,double refvol,char *NXTaddr,char *NXTACCTSECRET)
{
int32_t i,n=0; struct prices777_order order,bestorder; char *retstr = 0; double metric,bestmetric = 0.;
return(0);
memset(&bestorder,0,sizeof(bestorder));
if ( dir > 0 )
n = prices->O.numasks;
else if ( dir < 0 )
n = prices->O.numbids;
if ( n > 0 )
{
for (i=0; i<n; i++)
{
order = (dir > 0) ? prices->O.book[MAX_GROUPS][i].ask : prices->O.book[MAX_GROUPS][i].bid;
if ( (metric= ordermetric(order.s.price,order.s.vol,dir,refprice,refvol)) > bestmetric )
{
bestmetric = metric;
bestorder = order;
}
}
}
//printf("n.%d\n",n);
if ( bestorder.source != 0 )
retstr = prices777_trade(0,0,0,0,1,0,NXTaddr,NXTACCTSECRET,bestorder.source,bestorder.s.isask!=0?-1:1,bestorder.s.price,bestorder.s.vol,0,&bestorder,bestorder.s.quoteid,0);
return(retstr);
}
int offer_checkitem(struct pending_trade *pend,cJSON *item)
{
uint64_t quoteid; struct InstantDEX_quote *iQ;
if ( (quoteid= j64bits(item,"quoteid")) != 0 && (iQ= find_iQ(quoteid)) != 0 && iQ->s.closed != 0 )
return(0);
return(-1);
}
void trades_update()
{
#ifdef later
int32_t iter; struct pending_trade *pend;
for (iter=0; iter<2; iter++)
{
while ( (pend= queue_dequeue(&Pending_offersQ.pingpong[iter],0)) != 0 )
{
if ( time(NULL) > pend->expiration )
{
printf("now.%ld vs timestamp.%u vs expiration %u | ",(long)time(NULL),pend->timestamp,pend->expiration);
printf("offer_statemachine %llu/%llu %d %f %f\n",(long long)pend->orderid,(long long)pend->quoteid,pend->dir,pend->price,pend->volume);
//InstantDEX_history(1,pend,retstr);
if ( pend->bot == 0 )
free_pending(pend);
else pend->finishtime = (uint32_t)time(NULL);
}
else
{
printf("InstantDEX_update requeue %llu/%llu %d %f %f\n",(long long)pend->orderid,(long long)pend->quoteid,pend->dir,pend->price,pend->volume);
queue_enqueue("requeue",&Pending_offersQ.pingpong[iter ^ 1],&pend->DL,0);
}
}
}
#endif
}
void InstantDEX_update(char *NXTaddr,char *NXTACCTSECRET)
{
int32_t dir; double price,volume; uint32_t now; char *retstr = 0;
int32_t inverted; struct InstantDEX_quote *iQ,*tmp; struct prices777 *prices; uint64_t nxt64bits = calc_nxt64bits(NXTaddr);
now = (uint32_t)time(NULL);
HASH_ITER(hh,AllQuotes,iQ,tmp)
{
if ( iQ->s.timestamp > (now + ORDERBOOK_EXPIRATION) )
iQ->s.expired = iQ->s.closed = 1;
if ( iQ->s.offerNXT == nxt64bits && iQ->s.closed == 0 && iQ->s.pending == 0 )
{
if ( (prices= prices777_find(&inverted,iQ->s.baseid,iQ->s.relid,exchange_str(iQ->exchangeid))) != 0 )
{
if ( iQ->s.isask != 0 )
dir = -1;
else dir = 1;
if ( inverted != 0 )
{
dir *= -1;
volume = (iQ->s.price * iQ->s.vol);
price = 1. / iQ->s.price;
printf("price inverted (%f %f) -> (%f %f)\n",iQ->s.price,iQ->s.vol,price,volume);
} else price = iQ->s.price, volume = iQ->s.vol;
if ( (retstr= automatch(prices,dir,price,volume,NXTaddr,NXTACCTSECRET)) != 0 )
{
printf("automatched %s isask.%d %f %f (%s)\n",prices->contract,iQ->s.isask,iQ->s.price,iQ->s.vol,retstr);
free(retstr);
}
}
}
}
trades_update();
}
int32_t is_specialexchange(char *exchangestr)
{
if ( strcmp(exchangestr,"InstantDEX") == 0 || strcmp(exchangestr,"jumblr") == 0 || strcmp(exchangestr,"pangea") == 0 || strcmp(exchangestr,"peggy") == 0 || strcmp(exchangestr,"wallet") == 0 || strcmp(exchangestr,"active") == 0 || strncmp(exchangestr,"basket",strlen("basket")) == 0 )
return(1);
return(0);
}
char *InstantDEX_placebidask(char *remoteaddr,uint64_t orderid,char *exchangestr,char *name,char *base,char *rel,struct InstantDEX_quote *iQ,char *extra,char *secret,char *activenxt,cJSON *origjson)
{
struct exchange_info *exchange; cJSON *obj;
char walletstr[256],*str,*retstr = 0; int32_t inverted,dir; struct prices777 *prices; double price,volume;
if ( secret == 0 || activenxt == 0 )
{
secret = IGUANA_NXTACCTSECRET;
activenxt = IGUANA_NXTADDR;
}
//printf("placebidask.(%s)\n",jprint(origjson,0));
if ( (obj= jobj(origjson,"wallet")) != 0 )
{
str = jprint(obj,1);
safecopy(walletstr,str,sizeof(walletstr));
free(str), str = 0;
}
else walletstr[0] = 0;
if ( exchangestr != 0 && (exchange= exchange_find(exchangestr)) != 0 )
iQ->exchangeid = exchange->exchangeid;
if ( iQ->exchangeid < 0 || (exchangestr= exchange_str(iQ->exchangeid)) == 0 )
{
printf("exchangestr.%s id.%d\n",exchangestr,iQ->exchangeid);
return(clonestr("{\"error\":\"exchange not active, check SuperNET.conf exchanges array\"}\n"));
}
//printf("walletstr.(%s)\n",walletstr);
if ( (prices= prices777_find(&inverted,iQ->s.baseid,iQ->s.relid,exchangestr)) == 0 )
prices = prices777_poll(exchangestr,name,base,iQ->s.baseid,rel,iQ->s.relid);
if ( prices != 0 )
{
price = iQ->s.price, volume = iQ->s.vol;
if ( price < SMALLVAL || volume < SMALLVAL )
{
printf("price %f volume %f error\n",price,volume);
return(clonestr("{\"error\":\"prices777_trade invalid price or volume\"}\n"));
}
if ( iQ->s.isask != 0 )
dir = -1;
else dir = 1;
if ( inverted != 0 )
{
dir *= -1;
volume *= price;
price = 1. / price;
printf("price inverted (%f %f) -> (%f %f)\n",iQ->s.price,iQ->s.vol,price,volume);
}
//printf("dir.%d price %f vol %f isask.%d remoteaddr.%p\n",dir,price,volume,iQ->s.isask,remoteaddr);
if ( remoteaddr == 0 )
{
if ( is_specialexchange(exchangestr) == 0 )
return(prices777_trade(0,0,0,0,1,0,activenxt,secret,prices,dir,price,volume,iQ,0,iQ->s.quoteid,extra));
//printf("check automatch\n");
//if ( strcmp(exchangestr,"wallet") != 0 && strcmp(exchangestr,"jumblr") != 0 && strcmp(exchangestr,"pangea") != 0 && iQ->s.automatch != 0 && (SUPERNET.automatch & 1) != 0 && (retstr= automatch(prices,dir,volume,price,activenxt,secret)) != 0 )
// return(retstr);
if ( strcmp(IGUANA_NXTACCTSECRET,secret) != 0 )
return(clonestr("{\"error\":\"cant do queued requests with non-default accounts\"}"));
retstr = InstantDEX_str(walletstr,0,1,iQ);
//printf("create_iQ.(%llu) quoteid.%llu walletstr.(%s) %p\n",(long long)iQ->s.offerNXT,(long long)iQ->s.quoteid,walletstr,walletstr);
iQ = create_iQ(iQ,walletstr);
printf("local got create_iQ.(%llu) quoteid.%llu wallet.(%s) baseamount %llu iswallet.%d\n",(long long)iQ->s.offerNXT,(long long)iQ->s.quoteid,walletstr,(long long)iQ->s.baseamount,iQ->s.wallet);
prices777_InstantDEX(prices,MAX_DEPTH);
queue_enqueue("InstantDEX",&InstantDEXQ,queueitem(retstr),0);
}
else
{
iQ = create_iQ(iQ,walletstr);
if ( (retstr= autofill(remoteaddr,iQ,activenxt,secret)) == 0 )
{
//printf("create_iQ.(%llu) quoteid.%llu\n",(long long)iQ->s.offerNXT,(long long)iQ->s.quoteid);
if ( strcmp(IGUANA_NXTACCTSECRET,secret) != 0 )
return(clonestr("{\"error\":\"cant do queued requests with non-default accounts\"}"));
prices777_InstantDEX(prices,MAX_DEPTH);
printf("remote got create_iQ.(%llu) quoteid.%llu wallet.(%s) baseamount %llu\n",(long long)iQ->s.offerNXT,(long long)iQ->s.quoteid,walletstr,(long long)iQ->s.baseamount);
}
return(retstr);
}
} else printf("cant find prices\n");
if ( retstr == 0 )
retstr = clonestr("{\"error\":\"cant get prices ptr\"}");
return(retstr);
}
#endif
#endif