|
@ -878,58 +878,30 @@ void tradebot_arbcandidate(struct supernet_info *myinfo,char *exchange,int32_t t |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
void _default_swap_balancingtrade(struct supernet_info *myinfo,struct basilisk_swap *swap,int32_t iambob) |
|
|
cJSON *linfo_json(struct liquidity_info *li) |
|
|
{ |
|
|
{ |
|
|
// update balance, compare to target balance, issue balancing trade via central exchanges, if needed
|
|
|
cJSON *item = cJSON_CreateObject(); |
|
|
double price,volume,srcamount,destamount,profitmargin,dir=0.,dotrade=1.; char base[64],rel[64]; |
|
|
jaddstr(item,"base",li->base); |
|
|
srcamount = swap->I.req.srcamount; |
|
|
jaddstr(item,"rel",li->rel); |
|
|
destamount = swap->I.req.destamount; |
|
|
if ( li->exchange[0] != 0 ) |
|
|
profitmargin = (double)swap->I.req.profitmargin / 1000000.; |
|
|
jaddstr(item,"exchange",li->exchange); |
|
|
if ( srcamount <= SMALLVAL || destamount <= SMALLVAL ) |
|
|
if ( li->assetid != 0 ) |
|
|
{ |
|
|
jadd64bits(item,"assetid",li->assetid); |
|
|
printf("illegal amount for balancing %f %f\n",srcamount,destamount); |
|
|
if ( li->profit != 0. ) |
|
|
return; |
|
|
jaddnum(item,"profitmargin",li->profit); |
|
|
} |
|
|
if ( li->refprice != 0. ) |
|
|
strcpy(rel,"BTC"); |
|
|
jaddnum(item,"refprice",li->refprice); |
|
|
if ( strcmp(swap->I.req.src,"BTC") == 0 ) |
|
|
if ( li->bid != 0. ) |
|
|
{ |
|
|
jaddnum(item,"bid",li->bid); |
|
|
strcpy(base,swap->I.req.dest); |
|
|
if ( li->ask != 0. ) |
|
|
price = (srcamount / destamount); |
|
|
jaddnum(item,"ask",li->ask); |
|
|
volume = destamount / SATOSHIDEN; |
|
|
if ( li->minvol != 0. ) |
|
|
dir = -1.; |
|
|
jaddnum(item,"minvol",li->minvol); |
|
|
} |
|
|
if ( li->maxvol != 0. ) |
|
|
else if ( strcmp(swap->I.req.dest,"BTC") == 0 ) |
|
|
jaddnum(item,"maxvol",li->maxvol); |
|
|
{ |
|
|
if ( li->totalvol != 0. ) |
|
|
strcpy(base,swap->I.req.src); |
|
|
jaddnum(item,"totalvol",li->totalvol); |
|
|
price = (destamount / srcamount); |
|
|
return(item); |
|
|
volume = srcamount / SATOSHIDEN; |
|
|
|
|
|
dir = 1.; |
|
|
|
|
|
} |
|
|
|
|
|
else |
|
|
|
|
|
{ |
|
|
|
|
|
printf("only BTC trades can be balanced, not (%s/%s)\n",swap->I.req.src,swap->I.req.dest); |
|
|
|
|
|
return; |
|
|
|
|
|
} |
|
|
|
|
|
if ( iambob != 0 ) |
|
|
|
|
|
{ |
|
|
|
|
|
if ( myinfo->IAMLP != 0 ) |
|
|
|
|
|
{ |
|
|
|
|
|
printf("BOB: price %f * vol %f -> %s newprice %f margin %.2f%%\n",price,volume,dir < 0. ? "buy" : "sell",price + dir * price * profitmargin,100*profitmargin); |
|
|
|
|
|
if ( dir < 0. ) |
|
|
|
|
|
InstantDEX_buy(myinfo,0,0,0,"poloniex",base,rel,price,volume,dotrade); |
|
|
|
|
|
else InstantDEX_sell(myinfo,0,0,0,"poloniex",base,rel,price,volume,dotrade); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
else |
|
|
|
|
|
{ |
|
|
|
|
|
if ( myinfo->IAMLP != 0 ) |
|
|
|
|
|
{ |
|
|
|
|
|
printf("ALICE: price %f * vol %f -> %s newprice %f margin %.2f%%\n",price,volume,dir > 0. ? "buy" : "sell",price - dir * price * profitmargin,100*profitmargin); |
|
|
|
|
|
if ( dir > 0. ) |
|
|
|
|
|
InstantDEX_buy(myinfo,0,0,0,"poloniex",base,rel,price,volume,dotrade); |
|
|
|
|
|
else InstantDEX_sell(myinfo,0,0,0,"poloniex",base,rel,price,volume,dotrade); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
void _default_liquidity_command(struct supernet_info *myinfo,char *base,bits256 hash,cJSON *vals) |
|
|
void _default_liquidity_command(struct supernet_info *myinfo,char *base,bits256 hash,cJSON *vals) |
|
@ -953,18 +925,17 @@ void _default_liquidity_command(struct supernet_info *myinfo,char *base,bits256 |
|
|
memset(&li,0,sizeof(li)); |
|
|
memset(&li,0,sizeof(li)); |
|
|
safecopy(li.base,base,sizeof(li.base)); |
|
|
safecopy(li.base,base,sizeof(li.base)); |
|
|
safecopy(li.rel,relstr,sizeof(li.rel)); |
|
|
safecopy(li.rel,relstr,sizeof(li.rel)); |
|
|
safecopy(li.exchange,exchange,sizeof(li.exchange)); |
|
|
strncpy(li.exchange,exchange,sizeof(li.exchange)); |
|
|
li.profit = jdouble(vals,"profit"); |
|
|
li.profit = jdouble(vals,"profit"); |
|
|
li.refprice = jdouble(vals,"refprice"); |
|
|
li.refprice = jdouble(vals,"refprice"); |
|
|
li.bid = jdouble(vals,"bid"); |
|
|
li.bid = jdouble(vals,"bid"); |
|
|
li.ask = jdouble(vals,"ask"); |
|
|
li.ask = jdouble(vals,"ask"); |
|
|
li.maxvol = jdouble(vals,"maxvol"); |
|
|
if ( (li.minvol= jdouble(vals,"minvol")) <= 0. ) |
|
|
li.dir = jint(vals,"dir"); // positive -> buy, negative -> sell, 0 or missing -> both
|
|
|
li.minvol = (strcmp("BTC",base) == 0) ? 0.0001 : 0.01; |
|
|
li.onetime = jint(vals,"onetime"); |
|
|
if ( (li.maxvol= jdouble(vals,"maxvol")) < li.minvol ) |
|
|
// li.theoretical = ... dotproduct
|
|
|
li.maxvol = li.minvol; |
|
|
// li.filter = ...
|
|
|
if ( (li.totalvol= jdouble(vals,"total")) < li.maxvol ) |
|
|
// li.trigger = ...
|
|
|
li.totalvol = li.maxvol; |
|
|
// PAX response
|
|
|
|
|
|
if ( strcmp("NXT",li.rel) == 0 ) |
|
|
if ( strcmp("NXT",li.rel) == 0 ) |
|
|
li.assetid = NXT_assetidfind(base); |
|
|
li.assetid = NXT_assetidfind(base); |
|
|
else if ( strcmp("UNITY",base) == 0 ) |
|
|
else if ( strcmp("UNITY",base) == 0 ) |
|
@ -986,20 +957,20 @@ void _default_liquidity_command(struct supernet_info *myinfo,char *base,bits256 |
|
|
for (i=0; i<sizeof(myinfo->linfos)/sizeof(*myinfo->linfos); i++) |
|
|
for (i=0; i<sizeof(myinfo->linfos)/sizeof(*myinfo->linfos); i++) |
|
|
{ |
|
|
{ |
|
|
refli = myinfo->linfos[i]; |
|
|
refli = myinfo->linfos[i]; |
|
|
/*if ( strcmp(li.rel,refli.base) == 0 && strcmp(li.base,refli.rel) == 0 )
|
|
|
if ( strcmp(li.rel,refli.base) == 0 && strcmp(li.base,refli.rel) == 0 ) |
|
|
{ |
|
|
{ |
|
|
li = refli; |
|
|
/*li = refli;
|
|
|
strcpy(li.base,refli.base); |
|
|
strcpy(li.base,refli.base); |
|
|
strcpy(li.rel,refli.rel); |
|
|
strcpy(li.rel,refli.rel); |
|
|
if ( fabs(li.refprice) > SMALLVAL ) |
|
|
if ( fabs(li.refprice) > SMALLVAL ) |
|
|
li.refprice = (1. / li.refprice); |
|
|
li.refprice = (1. / li.refprice); |
|
|
else li.refprice = 0.; |
|
|
else li.refprice = 0.; |
|
|
li.dir = -li.dir; |
|
|
li.dir = -li.dir; |
|
|
printf("Set rev linfo[%d] (%s/%s) %.6f %.8f\n",i,li.base,li.rel,li.profit,li.refprice); |
|
|
myinfo->linfos[i] = li;*/ |
|
|
myinfo->linfos[i] = li; |
|
|
printf("cant Set rev linfo[%d] (%s/%s) %.6f %.8f already have (%s/%s)\n",i,li.rel,li.base,li.profit,li.refprice,refli.base,refli.rel); |
|
|
return; |
|
|
return; |
|
|
} |
|
|
} |
|
|
else*/ if ( refli.base[0] == 0 || (strcmp(li.base,refli.base) == 0 && strcmp(li.rel,refli.rel) == 0 && strcmp(li.exchange,refli.exchange) == 0) ) |
|
|
else if ( refli.base[0] == 0 || (strcmp(li.base,refli.base) == 0 && strcmp(li.rel,refli.rel) == 0 && strcmp(li.exchange,refli.exchange) == 0) ) |
|
|
{ |
|
|
{ |
|
|
if ( refli.base[0] == 0 && li.exchange[0] != 0 && strcmp(li.exchange,"DEX") != 0 ) |
|
|
if ( refli.base[0] == 0 && li.exchange[0] != 0 && strcmp(li.exchange,"DEX") != 0 ) |
|
|
{ |
|
|
{ |
|
@ -1020,9 +991,9 @@ void _default_liquidity_command(struct supernet_info *myinfo,char *base,bits256 |
|
|
|
|
|
|
|
|
int32_t _default_volume_ok(struct supernet_info *myinfo,struct liquidity_info *li,int32_t dir,double volume) |
|
|
int32_t _default_volume_ok(struct supernet_info *myinfo,struct liquidity_info *li,int32_t dir,double volume) |
|
|
{ |
|
|
{ |
|
|
// check order exposure
|
|
|
if ( (li->minvol == 0 || volume >= li->minvol) && (li->maxvol == 0 || volume <= li->maxvol) ) |
|
|
// check cumulative exposure
|
|
|
return(0); |
|
|
return(0); |
|
|
else return(-1); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
double _default_liquidity_active(struct supernet_info *myinfo,double *refpricep,char *exchange,char *base,char *rel,double volume) |
|
|
double _default_liquidity_active(struct supernet_info *myinfo,double *refpricep,char *exchange,char *base,char *rel,double volume) |
|
@ -1030,7 +1001,7 @@ double _default_liquidity_active(struct supernet_info *myinfo,double *refpricep, |
|
|
int32_t i,dir; struct liquidity_info refli; |
|
|
int32_t i,dir; struct liquidity_info refli; |
|
|
*refpricep = 0.; |
|
|
*refpricep = 0.; |
|
|
//printf("%s %s/%s\n",exchange,base,rel);
|
|
|
//printf("%s %s/%s\n",exchange,base,rel);
|
|
|
for (i=sizeof(myinfo->linfos)/sizeof(*myinfo->linfos)-1; i>=0; i--) |
|
|
for (i=0; i<sizeof(myinfo->linfos)/sizeof(*myinfo->linfos); i++) |
|
|
{ |
|
|
{ |
|
|
refli = myinfo->linfos[i]; |
|
|
refli = myinfo->linfos[i]; |
|
|
if ( refli.base[0] == 0 ) |
|
|
if ( refli.base[0] == 0 ) |
|
@ -1046,25 +1017,106 @@ double _default_liquidity_active(struct supernet_info *myinfo,double *refpricep, |
|
|
continue; |
|
|
continue; |
|
|
} |
|
|
} |
|
|
//printf(">>>>>>>> %s %s/%s [%d] dir.%d refli.dir %d vs %s/%s\n",exchange,base,rel,i,dir,refli.dir,refli.base,refli.rel);
|
|
|
//printf(">>>>>>>> %s %s/%s [%d] dir.%d refli.dir %d vs %s/%s\n",exchange,base,rel,i,dir,refli.dir,refli.base,refli.rel);
|
|
|
if ( dir != 0 && dir * refli.dir <= 0 ) |
|
|
if ( _default_volume_ok(myinfo,&refli,dir,volume) == 0 ) |
|
|
{ |
|
|
{ |
|
|
if ( refli.profit != 0. ) |
|
|
if ( refli.profit != 0. ) |
|
|
{ |
|
|
*refpricep = refli.refprice; |
|
|
if ( _default_volume_ok(myinfo,&refli,dir,volume) == 0 ) |
|
|
else if ( dir > 0 ) |
|
|
{ |
|
|
*refpricep = refli.bid; |
|
|
*refpricep = refli.refprice; |
|
|
else if ( dir < 0 ) |
|
|
return(refli.profit); |
|
|
*refpricep = refli.ask; |
|
|
} else break; |
|
|
return(refli.profit); |
|
|
} |
|
|
|
|
|
else |
|
|
|
|
|
{ |
|
|
|
|
|
//bid, ask, track pending, recover expired, onetime
|
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
break; |
|
|
} |
|
|
} |
|
|
return(0.); |
|
|
return(0.); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
struct liquidity_info *_default_lifind(struct supernet_info *myinfo,int32_t *dirp,char *base,char *rel) |
|
|
|
|
|
{ |
|
|
|
|
|
struct liquidity_info *li; int32_t i; |
|
|
|
|
|
*dirp = 0; |
|
|
|
|
|
for (i=0; i<sizeof(myinfo->linfos)/sizeof(*myinfo->linfos); i++) |
|
|
|
|
|
{ |
|
|
|
|
|
li = &myinfo->linfos[i]; |
|
|
|
|
|
if ( strcmp(li->base,base) == 0 && strcmp(li->rel,rel) == 0 ) |
|
|
|
|
|
{ |
|
|
|
|
|
*dirp = 1; |
|
|
|
|
|
return(li); |
|
|
|
|
|
} |
|
|
|
|
|
else if ( strcmp(li->base,rel) == 0 && strcmp(li->rel,base) == 0 ) |
|
|
|
|
|
{ |
|
|
|
|
|
*dirp = -1; |
|
|
|
|
|
return(li); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
return(0); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void _default_swap_balancingtrade(struct supernet_info *myinfo,struct basilisk_swap *swap,int32_t iambob) |
|
|
|
|
|
{ |
|
|
|
|
|
// update balance, compare to target balance, issue balancing trade via central exchanges, if needed
|
|
|
|
|
|
struct liquidity_info *li; double vol,price,volume,srcamount,destamount,profitmargin,dir=0.,dotrade=1.; char base[64],rel[64]; int32_t idir; |
|
|
|
|
|
srcamount = swap->I.req.srcamount; |
|
|
|
|
|
destamount = swap->I.req.destamount; |
|
|
|
|
|
profitmargin = (double)swap->I.req.profitmargin / 1000000.; |
|
|
|
|
|
if ( srcamount <= SMALLVAL || destamount <= SMALLVAL ) |
|
|
|
|
|
{ |
|
|
|
|
|
printf("illegal amount for balancing %f %f\n",srcamount,destamount); |
|
|
|
|
|
return; |
|
|
|
|
|
} |
|
|
|
|
|
if ( (li= _default_lifind(myinfo,&idir,swap->I.req.src,swap->I.req.dest)) != 0 ) |
|
|
|
|
|
{ |
|
|
|
|
|
if ( idir < 0 ) |
|
|
|
|
|
vol = 1. / ((double)destamount / SATOSHIDEN); |
|
|
|
|
|
else vol = ((double)srcamount / SATOSHIDEN); |
|
|
|
|
|
li->totalvol -= vol; |
|
|
|
|
|
if ( li->totalvol <= 0. || (li->minvol != 0. && li->totalvol < li->minvol) ) |
|
|
|
|
|
li->minvol = li->maxvol = li->totalvol = 0.; |
|
|
|
|
|
printf("li.(%s/%s) totalvol %f after -= %f minmax.(%f %f)\n",li->base,li->rel,li->totalvol,vol,li->minvol,li->maxvol); |
|
|
|
|
|
} |
|
|
|
|
|
strcpy(rel,"BTC"); |
|
|
|
|
|
if ( strcmp(swap->I.req.src,"BTC") == 0 ) |
|
|
|
|
|
{ |
|
|
|
|
|
strcpy(base,swap->I.req.dest); |
|
|
|
|
|
price = (srcamount / destamount); |
|
|
|
|
|
volume = destamount / SATOSHIDEN; |
|
|
|
|
|
dir = -1.; |
|
|
|
|
|
} |
|
|
|
|
|
else if ( strcmp(swap->I.req.dest,"BTC") == 0 ) |
|
|
|
|
|
{ |
|
|
|
|
|
strcpy(base,swap->I.req.src); |
|
|
|
|
|
price = (destamount / srcamount); |
|
|
|
|
|
volume = srcamount / SATOSHIDEN; |
|
|
|
|
|
dir = 1.; |
|
|
|
|
|
} |
|
|
|
|
|
else |
|
|
|
|
|
{ |
|
|
|
|
|
printf("only BTC trades can be balanced, not (%s/%s)\n",swap->I.req.src,swap->I.req.dest); |
|
|
|
|
|
return; |
|
|
|
|
|
} |
|
|
|
|
|
if ( iambob != 0 ) |
|
|
|
|
|
{ |
|
|
|
|
|
if ( myinfo->IAMLP != 0 ) |
|
|
|
|
|
{ |
|
|
|
|
|
printf("BOB: price %f * vol %f -> %s newprice %f margin %.2f%%\n",price,volume,dir < 0. ? "buy" : "sell",price + dir * price * profitmargin,100*profitmargin); |
|
|
|
|
|
if ( dir < 0. ) |
|
|
|
|
|
InstantDEX_buy(myinfo,0,0,0,"poloniex",base,rel,price,volume,dotrade); |
|
|
|
|
|
else InstantDEX_sell(myinfo,0,0,0,"poloniex",base,rel,price,volume,dotrade); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
else |
|
|
|
|
|
{ |
|
|
|
|
|
if ( myinfo->IAMLP != 0 ) |
|
|
|
|
|
{ |
|
|
|
|
|
printf("ALICE: price %f * vol %f -> %s newprice %f margin %.2f%%\n",price,volume,dir > 0. ? "buy" : "sell",price - dir * price * profitmargin,100*profitmargin); |
|
|
|
|
|
if ( dir > 0. ) |
|
|
|
|
|
InstantDEX_buy(myinfo,0,0,0,"poloniex",base,rel,price,volume,dotrade); |
|
|
|
|
|
else InstantDEX_sell(myinfo,0,0,0,"poloniex",base,rel,price,volume,dotrade); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
void tradebot_swap_balancingtrade(struct supernet_info *myinfo,struct basilisk_swap *swap,int32_t iambob) |
|
|
void tradebot_swap_balancingtrade(struct supernet_info *myinfo,struct basilisk_swap *swap,int32_t iambob) |
|
|
{ |
|
|
{ |
|
|
if ( swap->balancingtrade == 0 ) |
|
|
if ( swap->balancingtrade == 0 ) |
|
@ -1145,7 +1197,7 @@ void tradebots_processprices(struct supernet_info *myinfo,struct exchange_info * |
|
|
#include "../includes/iguana_apidefs.h" |
|
|
#include "../includes/iguana_apidefs.h" |
|
|
#include "../includes/iguana_apideclares.h" |
|
|
#include "../includes/iguana_apideclares.h" |
|
|
|
|
|
|
|
|
TWO_STRINGS(tradebots,gensvm,base,rel) |
|
|
TWO_STRINGS(tradebot,gensvm,base,rel) |
|
|
{ |
|
|
{ |
|
|
#ifdef _WIN |
|
|
#ifdef _WIN |
|
|
return(clonestr("{\"error\":\"windows doesnt support SVM\"}")); |
|
|
return(clonestr("{\"error\":\"windows doesnt support SVM\"}")); |
|
@ -1161,4 +1213,15 @@ TWO_STRINGS(tradebots,gensvm,base,rel) |
|
|
#endif |
|
|
#endif |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
ZERO_ARGS(tradebot,openliquidity) |
|
|
|
|
|
{ |
|
|
|
|
|
int32_t i; cJSON *array = cJSON_CreateArray(); |
|
|
|
|
|
for (i=0; i<sizeof(myinfo->linfos)/sizeof(*myinfo->linfos); i++) |
|
|
|
|
|
{ |
|
|
|
|
|
if ( myinfo->linfos[i].base[0] != 0 ) |
|
|
|
|
|
jaddi(array,linfo_json(&myinfo->linfos[i])); |
|
|
|
|
|
} |
|
|
|
|
|
return(jprint(array,1)); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
#include "../includes/iguana_apiundefs.h" |
|
|
#include "../includes/iguana_apiundefs.h" |
|
|