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.
881 lines
37 KiB
881 lines
37 KiB
9 years ago
|
/******************************************************************************
|
||
|
* 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,"eid,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
|