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.

898 lines
41 KiB

8 years ago
/******************************************************************************
* Copyright © 2014-2017 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. *
* *
******************************************************************************/
//
// LP_portfolio.c
// marketmaker
//
7 years ago
struct LP_portfoliotrade { double metric; char buycoin[65],sellcoin[65]; };
7 years ago
struct LP_autoprice_ref
{
7 years ago
char refbase[65],refrel[65],base[65],rel[65],fundbid[16],fundask[16];
7 years ago
double buymargin,sellmargin,factor,offset,lastbid,lastask;
cJSON *fundvalue;
7 years ago
uint32_t count;
} LP_autorefs[1024];
7 years ago
int32_t LP_autoprices,num_LP_autorefs;
7 years ago
char LP_portfolio_base[128],LP_portfolio_rel[128];
8 years ago
double LP_portfolio_relvolume;
void LP_portfolio_reset()
{
struct iguana_info *coin,*tmp; cJSON *fundjson; int32_t i; struct LP_autoprice_ref *ptr;
for (i=0; i<num_LP_autorefs; i++)
{
ptr = &LP_autorefs[i];
if ( (fundjson= ptr->fundvalue) != 0 )
{
ptr->fundvalue = 0;
free_json(fundjson);
}
}
memset(LP_autorefs,0,sizeof(LP_autorefs));
LP_autoprices = 0;
num_LP_autorefs = 0;
strcpy(LP_portfolio_base,"");
strcpy(LP_portfolio_rel,"");
LP_portfolio_relvolume = 0.;
HASH_ITER(hh,LP_coins,coin,tmp)
{
coin->maxamount = 0;
coin->perc = 0;
coin->goal = 0;
coin->goalperc = 0;
coin->relvolume = 0;
coin->force = 0;
coin->balanceA = 0;
coin->valuesumA = 0;
coin->balanceB = 0;
coin->valuesumB = 0;
}
}
8 years ago
cJSON *LP_portfolio_entry(struct iguana_info *coin)
8 years ago
{
cJSON *item = cJSON_CreateObject();
jaddstr(item,"coin",coin->symbol);
8 years ago
jaddstr(item,"address",coin->smartaddr);
8 years ago
jaddnum(item,"amount",dstr(coin->maxamount));
7 years ago
jaddnum(item,"price",coin->price_kmd);
8 years ago
jaddnum(item,"kmd_equiv",dstr(coin->kmd_equiv));
8 years ago
jaddnum(item,"perc",coin->perc);
8 years ago
jaddnum(item,"goal",coin->goal);
jaddnum(item,"goalperc",coin->goalperc);
8 years ago
jaddnum(item,"relvolume",coin->relvolume);
8 years ago
jaddnum(item,"force",coin->force);
8 years ago
jaddnum(item,"balanceA",dstr(coin->balanceA));
jaddnum(item,"valuesumA",dstr(coin->valuesumA));
8 years ago
if ( coin->valuesumA != 0 )
jaddnum(item,"aliceutil",100. * (double)coin->balanceA/coin->valuesumA);
8 years ago
jaddnum(item,"balanceB",dstr(coin->balanceB));
jaddnum(item,"valuesumB",dstr(coin->valuesumB));
8 years ago
jaddnum(item,"balance",dstr(coin->maxamount));
8 years ago
if ( coin->valuesumB != 0 )
jaddnum(item,"bobutil",100. * (double)coin->balanceB/coin->valuesumB);
8 years ago
return(item);
}
uint64_t LP_balance(uint64_t *valuep,int32_t iambob,char *symbol,char *coinaddr)
{
7 years ago
cJSON *array,*item; bits256 zero; int32_t i,n; uint64_t valuesum,satoshisum,value;
8 years ago
valuesum = satoshisum = 0;
7 years ago
memset(zero.bytes,0,sizeof(zero));
if ( (array= LP_listunspent(symbol,coinaddr,zero,zero)) != 0 )
8 years ago
{
if ( is_cJSON_Array(array) != 0 && (n= cJSON_GetArraySize(array)) > 0 )
{
for (i=0; i<n; i++)
{
item = jitem(array,i);
7 years ago
value = LP_value_extract(item,1);
8 years ago
valuesum += value;
}
}
free_json(array);
}
7 years ago
/*if ( (array= LP_inventory(symbol)) != 0 )
8 years ago
{
if ( (n= cJSON_GetArraySize(array)) > 0 && is_cJSON_Array(array) != 0 )
{
for (i=0; i<n; i++)
{
item = jitem(array,i);
8 years ago
//valuesum += j64bits(item,"value") + j64bits(item,"value2");
8 years ago
satoshisum += j64bits(item,"satoshis");
}
}
free_json(array);
7 years ago
}*/
8 years ago
*valuep = valuesum;
7 years ago
satoshisum = valuesum;
8 years ago
return(satoshisum);
}
char *LP_portfolio()
{
8 years ago
double maxval = 0.,minval = 0.,goalsum = 0.; uint64_t kmdsum = 0; int32_t iter; cJSON *retjson,*array; struct iguana_info *coin,*tmp,*sellcoin = 0,*buycoin = 0;
8 years ago
array = cJSON_CreateArray();
retjson = cJSON_CreateObject();
for (iter=0; iter<2; iter++)
{
HASH_ITER(hh,LP_coins,coin,tmp)
{
7 years ago
if ( coin->inactive != 0 )//|| (coin->electrum != 0 && coin->obooktime == 0) )
8 years ago
continue;
8 years ago
if ( iter == 0 )
{
7 years ago
//printf("from portfolio\n");
7 years ago
//LP_privkey_init(-1,coin,G.LP_privkey,G.LP_mypub25519);
8 years ago
coin->balanceA = LP_balance(&coin->valuesumA,0,coin->symbol,coin->smartaddr);
coin->balanceB = LP_balance(&coin->valuesumB,1,coin->symbol,coin->smartaddr);
if ( strcmp(coin->symbol,"KMD") != 0 )
coin->price_kmd = LP_price(coin->symbol,"KMD");
else coin->price_kmd = 1.;
coin->maxamount = coin->valuesumA;
if ( coin->valuesumB > coin->maxamount )
coin->maxamount = coin->valuesumB;
coin->kmd_equiv = coin->maxamount * coin->price_kmd;
kmdsum += coin->kmd_equiv;
8 years ago
goalsum += coin->goal;
8 years ago
}
8 years ago
else
8 years ago
{
8 years ago
coin->relvolume = 0.;
8 years ago
if ( kmdsum > SMALLVAL )
coin->perc = 100. * coin->kmd_equiv / kmdsum;
8 years ago
if ( goalsum > SMALLVAL && coin->goal > SMALLVAL )
{
8 years ago
coin->goalperc = 100. * coin->goal / goalsum;
8 years ago
if ( (coin->force= (coin->goalperc - coin->perc)) < 0. )
8 years ago
{
8 years ago
coin->force *= -coin->force;
8 years ago
if ( coin->price_kmd > SMALLVAL )
8 years ago
coin->relvolume = (dstr(coin->maxamount) * (coin->perc - coin->goalperc)) / 100.;
8 years ago
} else coin->force *= coin->force;
8 years ago
if ( coin->force > maxval )
8 years ago
{
8 years ago
maxval = coin->force;
buycoin = coin;
}
if ( coin->force < minval )
{
minval = coin->force;
sellcoin = coin;
8 years ago
}
8 years ago
} else coin->goalperc = coin->force = 0.;
8 years ago
jaddi(array,LP_portfolio_entry(coin));
8 years ago
}
8 years ago
}
}
jaddstr(retjson,"result","success");
8 years ago
jaddnum(retjson,"kmd_equiv",dstr(kmdsum));
8 years ago
if ( buycoin != 0 )
{
jaddstr(retjson,"buycoin",buycoin->symbol);
jaddnum(retjson,"buyforce",maxval);
}
if ( sellcoin != 0 )
8 years ago
{
8 years ago
jaddstr(retjson,"sellcoin",sellcoin->symbol);
jaddnum(retjson,"sellforce",minval);
8 years ago
}
8 years ago
if ( LP_portfolio_relvolume > SMALLVAL )
{
jaddstr(retjson,"base",LP_portfolio_base);
jaddstr(retjson,"rel",LP_portfolio_rel);
jaddnum(retjson,"relvolume",LP_portfolio_relvolume);
}
8 years ago
jadd(retjson,"portfolio",array);
return(jprint(retjson,1));
}
8 years ago
char *LP_portfolio_goal(char *symbol,double goal)
{
8 years ago
struct iguana_info *coin,*tmp; int32_t iter,n = 0; double kmdbtc = 50.;
if ( strcmp(symbol,"*") == 0 )
{
for (iter=0; iter<2; iter++)
{
HASH_ITER(hh,LP_coins,coin,tmp)
{
8 years ago
if ( coin->inactive != 0 )
continue;
8 years ago
if ( iter == 0 )
coin->goal = 0;
if ( coin->inactive == 0 && strcmp(coin->symbol,"KMD") != 0 && strcmp(coin->symbol,"BTC") != 0 )
{
if ( iter == 0 )
n++;
else coin->goal = (100. - kmdbtc) / n;
}
}
if ( n == 0 )
break;
}
8 years ago
if ( (coin= LP_coinfind("KMD")) != 0 && coin->inactive == 0 )
8 years ago
coin->goal = kmdbtc * 0.5;
8 years ago
if ( (coin= LP_coinfind("BTC")) != 0 && coin->inactive == 0 )
8 years ago
coin->goal = kmdbtc * 0.5;
7 years ago
if ( coin->goal != 0 )
coin->obooktime = (uint32_t)time(NULL);
8 years ago
return(LP_portfolio());
}
else if ( (coin= LP_coinfind(symbol)) != 0 && coin->inactive == 0 )
8 years ago
{
coin->goal = goal;
8 years ago
printf("set %s goal %f\n",coin->symbol,goal);
7 years ago
if ( coin->goal != 0 )
coin->obooktime = (uint32_t)time(NULL);
8 years ago
return(LP_portfolio());
8 years ago
} else return(clonestr("{\"error\":\"cant set goal for inactive coin\"}"));
8 years ago
}
8 years ago
/*int32_t LP_autofill(char *base,char *rel,double maxprice,double totalrelvolume)
8 years ago
{
struct LP_priceinfo *basepp,*relpp;
if ( (basepp= LP_priceinfofind(base)) != 0 && (relpp= LP_priceinfofind(rel)) != 0 )
{
basepp->maxprices[relpp->ind] = maxprice;
basepp->relvols[relpp->ind] = totalrelvolume;
8 years ago
LP_autofills++;
8 years ago
return(0);
}
return(-1);
8 years ago
}*/
8 years ago
7 years ago
void LP_autopriceset(int32_t ind,void *ctx,int32_t dir,struct LP_priceinfo *basepp,struct LP_priceinfo *relpp,double price,char *refbase,char *refrel)
8 years ago
{
7 years ago
static uint32_t lasttime;
7 years ago
double margin,minprice,newprice,oppomargin,fixedprice,factor,offset; double bid,ask; int32_t changed;
7 years ago
margin = basepp->sellmargins[relpp->ind];
oppomargin = basepp->buymargins[relpp->ind];
7 years ago
if ( (fixedprice= basepp->fixedprices[relpp->ind]) > SMALLVAL )
7 years ago
{
LP_mypriceset(&changed,relpp->symbol,basepp->symbol,fixedprice);
7 years ago
//printf("autoprice FIXED %s/%s <- %.8f\n",basepp->symbol,relpp->symbol,fixedprice);
7 years ago
LP_pricepings(ctx,LP_myipaddr,LP_mypubsock,relpp->symbol,basepp->symbol,fixedprice);
return;
}
8 years ago
if ( margin != 0. || oppomargin != 0. )
8 years ago
{
7 years ago
offset = basepp->offsets[relpp->ind];
factor = basepp->factors[relpp->ind];
7 years ago
if ( fabs(price) < SMALLVAL && refbase != 0 && refrel != 0 )
{
price = LP_myprice(&bid,&ask,refbase,refrel);
7 years ago
//printf("%s/%s USE ref %s/%s %.8f factor %.8f offset %.8f margin %.8f/%.8f\n",basepp->symbol,relpp->symbol,refbase,refrel,price,factor,offset,oppomargin,margin);
7 years ago
}
7 years ago
if ( LP_pricevalid(price) > 0 )
7 years ago
{
7 years ago
if ( factor > SMALLVAL )
7 years ago
{
7 years ago
//double tmp = (price * factor) + offset;
//printf("price %.8f -> %.8f factor %.8f offset %.8f margin %.8f [%.8f %.8f] [%.8f %.8f]\n",price,tmp,factor,offset,margin,(tmp * (1. + margin)),1./(tmp * (1. - margin)),(tmp * (1. - margin)),1./(tmp * (1. + margin)));
7 years ago
price = (price * factor) + offset;
}
if ( margin == 0. )
margin = oppomargin;
7 years ago
//printf("min %.8f %s/%s %.8f dir.%d margin %.8f (%.8f %.8f)\n",basepp->minprices[relpp->ind],relpp->symbol,basepp->symbol,price,dir,margin,1. / (price * (1. - margin)),(price * (1. + margin)));
7 years ago
if ( dir > 0 )
7 years ago
newprice = (1. / price) * (1. + margin);
else newprice = (price * (1. + margin));
7 years ago
if ( (minprice= basepp->minprices[relpp->ind]) == 0. || price >= minprice )
{
7 years ago
if ( ind >= 0 )
{
if ( LP_autorefs[ind].lastask < SMALLVAL )
LP_autorefs[ind].lastask = newprice;
7 years ago
else LP_autorefs[ind].lastask = (LP_autorefs[ind].lastask * 0.99) + (0.01 *newprice);
7 years ago
newprice = LP_autorefs[ind].lastask;
7 years ago
//printf("autopriceset %s/%s <- %.8f %.8f (%.8f %.8f)\n",basepp->symbol,relpp->symbol,price,newprice,LP_autorefs[ind].lastbid,LP_autorefs[ind].lastask);
7 years ago
}
7 years ago
LP_mypriceset(&changed,relpp->symbol,basepp->symbol,newprice);
7 years ago
if ( changed != 0 || time(NULL) > lasttime+LP_ORDERBOOK_DURATION*.777)
{
lasttime = (uint32_t)time(NULL);
7 years ago
LP_pricepings(ctx,LP_myipaddr,LP_mypubsock,relpp->symbol,basepp->symbol,newprice);
7 years ago
}
7 years ago
}
8 years ago
}
}
}
double LP_pricesparse(void *ctx,int32_t trexflag,char *retstr,struct LP_priceinfo *btcpp)
{
//{"success":true,"message":"","result":[{"MarketName":"BTC-KMD","High":0.00040840,"Low":0.00034900,"Volume":328042.46061669,"Last":0.00037236,"BaseVolume":123.36439511,"TimeStamp":"2017-07-15T13:50:21.87","Bid":0.00035721,"Ask":0.00037069,"OpenBuyOrders":343,"OpenSellOrders":1690,"PrevDay":0.00040875,"Created":"2017-02-11T23:04:01.853"},
//{"TradePairId":4762,"Label":"WAVES/BTC","AskPrice":0.00099989,"BidPrice":0.00097350,"Low":0.00095000,"High":0.00108838,"Volume":6501.24403100,"LastPrice":0.00098028,"BuyVolume":1058994.86554882,"SellVolume":2067.87377158,"Change":-7.46,"Open":0.00105926,"Close":0.00098028,"BaseVolume":6.52057452,"BuyBaseVolume":2.33098660,"SellBaseVolume":1167.77655709},
7 years ago
int32_t i,j,n,iter; double price,kmdbtc,bid,ask,nxtkmd=0.; struct LP_priceinfo *coinpp,*refpp; char symbol[65],*name,*refcoin; cJSON *retjson,*array,*item;
8 years ago
if ( (retjson= cJSON_Parse(retstr)) != 0 )
{
//printf("got.(%s)\n",retstr);
kmdbtc = 0.;
refcoin = "BTC";
refpp = btcpp;
if ( (array= jarray(&n,retjson,trexflag != 0 ? "result" : "Data")) != 0 )
{
for (iter=0; iter<2; iter++)
{
for (i=0; i<n; i++)
{
item = jitem(array,i);
if ( (name= jstr(item,trexflag != 0 ? "MarketName" : "Label")) != 0 )
{
symbol[0] = 0;
if ( trexflag != 0 )
{
if ( strncmp("BTC-",name,4) == 0 )
{
name += 4;
strcpy(symbol,name);
}
}
else
{
for (j=0; j<sizeof(symbol)-1; j++)
if ( (symbol[j]= name[j]) == '/' )
break;
symbol[j] = 0;
if ( strcmp(name+j+1,"BTC") != 0 )
continue;
}
if ( symbol[0] != 0 )
{
//printf("%s\n",jprint(item,0));
bid = jdouble(item,trexflag != 0 ? "Bid" : "BidPrice");
ask = jdouble(item,trexflag != 0 ? "Ask" : "AskPrice");
if ( iter == 1 && kmdbtc > SMALLVAL && strcmp(symbol,"NXT") == 0 )
nxtkmd = 0.5 * (bid + ask) / kmdbtc;
if ( (coinpp= LP_priceinfofind(symbol)) != 0 )
{
coinpp->high[trexflag] = jdouble(item,"High");
coinpp->low[trexflag] = jdouble(item,"Low");
//coinpp->volume = jdouble(item,"Volume");
//coinpp->btcvolume = jdouble(item,"BaseVolume");
coinpp->last[trexflag] = jdouble(item,trexflag != 0 ? "Last" : "LastPrice");
coinpp->bid[trexflag] = bid;
coinpp->ask[trexflag] = ask;
//coinpp->prevday = jdouble(item,"PrevDay");
//printf("iter.%d trexflag.%d %s high %.8f, low %.8f, last %.8f hbla.(%.8f %.8f)\n",iter,trexflag,symbol,coinpp->high[trexflag],coinpp->low[trexflag],coinpp->last[trexflag],coinpp->bid[trexflag],coinpp->ask[trexflag]);
if ( coinpp->bid[trexflag] > SMALLVAL && coinpp->ask[trexflag] > SMALLVAL )
{
price = 0.5 * (coinpp->bid[trexflag] + coinpp->ask[trexflag]);
if ( iter == 0 )
{
if ( strcmp(symbol,"KMD") == 0 )
kmdbtc = price;
}
else
{
if ( strcmp(symbol,"KMD") == 0 )
continue;
//printf("(%s/%s) iter.%d trexflag.%d %s %.8f %.8f\n",refpp->symbol,coinpp->symbol,iter,trexflag,symbol,price,price/kmdbtc);
price /= kmdbtc;
}
if ( trexflag == 0 && coinpp->bid[1] > SMALLVAL && coinpp->ask[1] > SMALLVAL )
{
//printf("have trex: iter.%d trexflag.%d %s %.8f %.8f\n",iter,trexflag,symbol,coinpp->bid[1],coinpp->ask[1]);
continue;
}
7 years ago
LP_autopriceset(-1,ctx,1,coinpp,refpp,price,0,0);
LP_autopriceset(-1,ctx,-1,refpp,coinpp,price,0,0);
8 years ago
}
}
}
}
}
refcoin = "KMD";
if ( kmdbtc == 0. || (refpp= LP_priceinfofind("KMD")) == 0 )
break;
}
}
free_json(retjson);
}
return(nxtkmd);
}
7 years ago
double LP_autoprice_newprice(int32_t bidask,double price,double newprice)
{
double gap; int32_t r;
7 years ago
if ( price > SMALLVAL && ((bidask == 0 && newprice < price) || (bidask != 0 && newprice > price)) )
7 years ago
{
gap = fabs(newprice - price) * 2;
r = (rand() % 100);
if ( bidask == 0 )
price -= (gap * r) / 100.;
else price += (gap * r) / 100.;
}
else if ( price > SMALLVAL )
price = (price * 0.95) + (0.05 * newprice);
else price = newprice;
return(price);
}
7 years ago
double LP_tickered_price(int32_t bidask,char *base,char *rel,double price,cJSON *tickerjson)
{
7 years ago
int32_t i,n; cJSON *item; double basevol,relvol,itemprice;
//printf("%s %s/%s %.8f -> ",bidask == 0 ? "bid" : "ask",base,rel,price);
7 years ago
if ( (n= cJSON_GetArraySize(tickerjson)) > 0 )
{
for (i=n-1; i>=0; i--)
{
// {"timestamp":1513235320,"KMD":860.45202538,"SUPERNET":20.00010000,"price":0.02324371}
item = jitem(tickerjson,i);
if ( (basevol= jdouble(item,base)) > SMALLVAL && (relvol= jdouble(item,rel)) > SMALLVAL )
{
itemprice = (relvol / basevol);
7 years ago
//printf("%.8f ",itemprice);
price = LP_autoprice_newprice(bidask,price,itemprice);
7 years ago
}
}
}
7 years ago
//printf("-> %.8f\n",price);
7 years ago
return(price);
}
8 years ago
void LP_autoprice_iter(void *ctx,struct LP_priceinfo *btcpp)
8 years ago
{
7 years ago
static cJSON *tickerjson; static uint32_t lasttime;
7 years ago
char *retstr,*base,*rel; cJSON *retjson,*bid,*ask,*fundjson,*argjson; uint64_t bidsatoshis,asksatoshis; int32_t i,changed; double bidprice,askprice,bch_usd,bch_btc,nxtkmd,price,factor,offset,newprice,buymargin,sellmargin,price_btc,price_usd,kmd_btc,kmd_usd; struct LP_priceinfo *kmdpp,*fiatpp,*nxtpp,*basepp,*relpp;
8 years ago
if ( (retstr= issue_curlt("https://bittrex.com/api/v1.1/public/getmarketsummaries",LP_HTTP_TIMEOUT*10)) == 0 )
8 years ago
{
8 years ago
printf("trex error getting marketsummaries\n");
8 years ago
sleep(60);
return;
}
nxtkmd = LP_pricesparse(ctx,1,retstr,btcpp);
free(retstr);
if ( (retstr= issue_curlt("https://www.cryptopia.co.nz/api/GetMarkets",LP_HTTP_TIMEOUT*10)) == 0 )
{
8 years ago
printf("cryptopia error getting marketsummaries\n");
8 years ago
sleep(60);
return;
}
LP_pricesparse(ctx,0,retstr,btcpp);
free(retstr);
if ( (kmdpp= LP_priceinfofind("KMD")) != 0 )
{
for (i=0; i<32; i++)
7 years ago
{break;
8 years ago
if ( (fiatpp= LP_priceinfofind(CURRENCIES[i])) != 0 )
8 years ago
{
8 years ago
if ( (retjson= LP_paxprice(CURRENCIES[i])) != 0 )
8 years ago
{
8 years ago
//printf("(%s %.8f %.8f) ",CURRENCIES[i],jdouble(retjson,"price"),jdouble(retjson,"invprice"));
price = jdouble(retjson,"price");
7 years ago
LP_autopriceset(-1,ctx,1,fiatpp,kmdpp,price,0,0);
LP_autopriceset(-1,ctx,-1,kmdpp,fiatpp,price,0,0);
8 years ago
free_json(retjson);
8 years ago
}
}
8 years ago
}
}
7 years ago
if ( 0 && nxtkmd > SMALLVAL )
8 years ago
{
for (i=0; i<sizeof(assetids)/sizeof(*assetids); i++)
{
if ( (nxtpp= LP_priceinfofind(assetids[i][1])) != 0 )
8 years ago
{
8 years ago
price = 0.;
bidsatoshis = asksatoshis = 0;
if ( (retjson= LP_assethbla(assetids[i][0])) != 0 )
8 years ago
{
8 years ago
if ( (bid= jobj(retjson,"bid")) != 0 && (ask= jobj(retjson,"ask")) != 0 )
8 years ago
{
8 years ago
bidsatoshis = j64bits(bid,"priceNQT") * atoi(assetids[i][2]);
asksatoshis = j64bits(ask,"priceNQT") * atoi(assetids[i][2]);
if ( bidsatoshis != 0 && asksatoshis != 0 )
price = 0.5 * dstr(bidsatoshis + asksatoshis) * nxtkmd;
8 years ago
}
7 years ago
LP_autopriceset(-1,ctx,1,nxtpp,kmdpp,price,0,0);
LP_autopriceset(-1,ctx,-1,kmdpp,nxtpp,price,0,0);
8 years ago
//printf("%s %s -> (%s) nxtkmd %.8f %.8f %.8f\n",assetids[i][1],assetids[i][0],jprint(retjson,0),nxtkmd,0.5*dstr(bidsatoshis + asksatoshis),price);
free_json(retjson);
8 years ago
}
}
}
8 years ago
}
7 years ago
if ( time(NULL) > lasttime+60 )
{
if ( tickerjson != 0 )
free_json(tickerjson);
if ( (retstr= LP_ticker("","")) != 0 )
{
tickerjson = cJSON_Parse(retstr);
free(retstr);
}
}
7 years ago
kmd_btc = LP_CMCbtcprice(&kmd_usd,"komodo");
bch_btc = LP_CMCbtcprice(&bch_usd,"bitcoin-cash");
7 years ago
for (i=0; i<num_LP_autorefs; i++)
{
7 years ago
rel = LP_autorefs[i].rel;
base = LP_autorefs[i].base;
7 years ago
buymargin = LP_autorefs[i].buymargin;
sellmargin = LP_autorefs[i].sellmargin;
7 years ago
offset = LP_autorefs[i].offset;
factor = LP_autorefs[i].factor;
if ( (argjson= LP_autorefs[i].fundvalue) != 0 )
{
if ( (fundjson= LP_fundvalue(argjson)) != 0 )
{
7 years ago
//printf("%s\n",jprint(fundjson,0));
7 years ago
if ( jint(fundjson,"missing") == 0 )
{
7 years ago
if ( LP_autorefs[i].fundbid[0] != 0 && (bidprice= jdouble(fundjson,LP_autorefs[i].fundbid)) > SMALLVAL && LP_autorefs[i].fundask[0] != 0 && (askprice= jdouble(fundjson,LP_autorefs[i].fundask)) > SMALLVAL )
{
price = (bidprice + askprice) * 0.5;
7 years ago
bidprice = (1. / price * (1. + buymargin));
if ( LP_autorefs[i].lastbid < SMALLVAL )
LP_autorefs[i].lastbid = bidprice;
7 years ago
else LP_autorefs[i].lastbid = (LP_autorefs[i].lastbid * 0.9) + (0.1 * bidprice);
bidprice = LP_autorefs[i].lastbid;
7 years ago
askprice = price * (1. + sellmargin);
if ( LP_autorefs[i].lastask < SMALLVAL )
LP_autorefs[i].lastask = askprice;
7 years ago
else LP_autorefs[i].lastask = (LP_autorefs[i].lastask * 0.9) + (0.1 * askprice);
askprice = LP_autorefs[i].lastask;
7 years ago
LP_mypriceset(&changed,rel,base,bidprice);
LP_pricepings(ctx,LP_myipaddr,LP_mypubsock,rel,base,bidprice);
LP_mypriceset(&changed,base,rel,askprice);
LP_pricepings(ctx,LP_myipaddr,LP_mypubsock,base,rel,askprice);
7 years ago
//printf("price %.8f -> %.8f %.8f\n",price,bidprice,askprice);
7 years ago
}
7 years ago
LP_autorefs[i].count++;
7 years ago
}
free_json(fundjson);
}
}
else if ( strcmp(LP_autorefs[i].refrel,"coinmarketcap") == 0 )
7 years ago
{
7 years ago
//printf("%s/%s for %s/%s margin %.8f/%.8f\n",base,rel,LP_autorefs[i].refbase,LP_autorefs[i].refrel,buymargin,sellmargin);
7 years ago
if ( (price_btc= LP_CMCbtcprice(&price_usd,LP_autorefs[i].refbase)) > SMALLVAL )
{
if ( strcmp(rel,"KMD") == 0 && kmd_btc > SMALLVAL )
7 years ago
price = kmd_btc / price_btc;
else if ( strcmp(rel,"BCH") == 0 && bch_btc > SMALLVAL )
price = bch_btc / price_btc;
7 years ago
else if ( strcmp(rel,"BTC") == 0 )
7 years ago
price = 1. / price_btc;
7 years ago
else continue;
7 years ago
if ( factor > 0. )
price = (price * factor) + offset;
7 years ago
newprice = (price * (1. + buymargin));
7 years ago
if ( LP_autorefs[i].lastbid < SMALLVAL )
LP_autorefs[i].lastbid = newprice;
7 years ago
else LP_autorefs[i].lastbid = (LP_autorefs[i].lastbid * 0.99) + (0.01 * newprice);
7 years ago
newprice = LP_autorefs[i].lastbid;
7 years ago
LP_mypriceset(&changed,rel,base,newprice);
7 years ago
LP_pricepings(ctx,LP_myipaddr,LP_mypubsock,rel,base,newprice);
7 years ago
//printf("%s/%s price %.8f margin %.8f/%.8f newprice %.8f %.8f\n",base,rel,price,buymargin,sellmargin,newprice,(1. / newprice) * (1. + sellmargin));
newprice = (1. / price) * (1. + sellmargin);
7 years ago
if ( LP_autorefs[i].lastask < SMALLVAL )
LP_autorefs[i].lastask = newprice;
7 years ago
else LP_autorefs[i].lastask = (LP_autorefs[i].lastask * 0.99) + (0.01 * newprice);
7 years ago
newprice = LP_autorefs[i].lastask;
7 years ago
LP_mypriceset(&changed,base,rel,newprice);
7 years ago
LP_pricepings(ctx,LP_myipaddr,LP_mypubsock,base,rel,newprice);
7 years ago
}
7 years ago
}
7 years ago
else
{
7 years ago
basepp = LP_priceinfofind(base);
relpp = LP_priceinfofind(rel);
7 years ago
if ( basepp != 0 && relpp != 0 )
{
7 years ago
//printf("check ref-autoprice %s/%s %f %f (%.8f %.8f)\n",LP_autorefs[i].refbase,LP_autorefs[i].refrel,relpp->fixedprices[basepp->ind],basepp->fixedprices[relpp->ind],LP_autorefs[i].lastbid,LP_autorefs[i].lastask);
7 years ago
LP_autopriceset(i,ctx,1,basepp,relpp,0.,LP_autorefs[i].refbase,LP_autorefs[i].refrel);
7 years ago
}
}
}
}
7 years ago
void LP_autoprices_update(char *method,char *base,double basevol,char *rel,double relvol)
7 years ago
{
7 years ago
int32_t i; double price,newprice;
if ( basevol > 0. && relvol > 0. )
7 years ago
{
price = relvol/basevol;
7 years ago
for (i=0; i<num_LP_autorefs; i++)
{
7 years ago
if ( strcmp(LP_autorefs[i].rel,rel) == 0 && strcmp(base,LP_autorefs[i].base) == 0 )
7 years ago
{
7 years ago
newprice = (LP_autorefs[i].lastask * 0.9) + (0.1 * price);
7 years ago
if ( LP_autorefs[i].lastask > 0 )
7 years ago
{
7 years ago
//printf("%s: autoprice ask update %s/%s %.8f vs myprice %.8f/%.8f -> %.8f\n",method,base,rel,price,LP_autorefs[i].lastbid,LP_autorefs[i].lastask,newprice);
7 years ago
LP_autorefs[i].lastask = newprice;
7 years ago
} // else printf("%s: autoprice ask skip update %s/%s %.8f vs myprice %.8f/%.8f -> %.8f\n",method,base,rel,price,LP_autorefs[i].lastbid,LP_autorefs[i].lastask,newprice);
7 years ago
}
7 years ago
else if ( strcmp(LP_autorefs[i].rel,base) == 0 && strcmp(rel,LP_autorefs[i].base) == 0 )
7 years ago
{
7 years ago
newprice = (LP_autorefs[i].lastbid * 0.9) + (0.1 * price);
7 years ago
if ( LP_autorefs[i].lastbid > 0 )
7 years ago
{
7 years ago
//printf("%s: autoprice bid update %s/%s %.8f vs myprice %.8f/%.8f -> %.8f\n",method,base,rel,price,LP_autorefs[i].lastbid,LP_autorefs[i].lastask,newprice);
7 years ago
LP_autorefs[i].lastbid = newprice;
7 years ago
} // else printf("%s: autoprice bid skip update %s/%s %.8f vs myprice %.8f/%.8f -> %.8f\n",method,base,rel,price,LP_autorefs[i].lastbid,LP_autorefs[i].lastask,newprice);
7 years ago
}
}
7 years ago
}
7 years ago
}
7 years ago
int32_t LP_autoprice(void *ctx,char *base,char *rel,cJSON *argjson)
{
//curl --url "http://127.0.0.1:7783" --data "{\"userpass\":\"$userpass\",\"method\":\"autoprice\",\"base\":\"MNZ\",\"rel\":\"KMD\",\"offset\":0.1,\"refbase\":\"KMD\",\refrel\":\"BTC\",\"factor\":15000,\"margin\":0.01}"
7 years ago
struct LP_priceinfo *basepp,*relpp; int32_t i,retval = -1; char *fundvalue_bid,*fundvalue_ask,*refbase="",*refrel=""; double margin,minprice,buymargin,sellmargin,offset,factor,fixedprice; cJSON *fundvalue;
7 years ago
//printf("autoprice.(%s %s) %s\n",base,rel,jprint(argjson,0));
if ( (basepp= LP_priceinfofind(base)) != 0 && (relpp= LP_priceinfofind(rel)) != 0 )
{
if ( jobj(argjson,"minprice") != 0 )
minprice = jdouble(argjson,"minprice");
else minprice = 0.;
7 years ago
if ( (margin= jdouble(argjson,"margin")) == 0. )
{
buymargin = jdouble(argjson,"buymargin");
sellmargin = jdouble(argjson,"sellmargin");
}
else
{
buymargin = margin;
sellmargin = margin;
}
7 years ago
offset = jdouble(argjson,"offset");
factor = jdouble(argjson,"factor");
fixedprice = jdouble(argjson,"fixed");
basepp->fixedprices[relpp->ind] = fixedprice;
basepp->minprices[relpp->ind] = minprice;
7 years ago
if ( jobj(argjson,"maxprice") != 0 )
relpp->minprices[basepp->ind] = 1. / jdouble(argjson,"maxprice");
7 years ago
basepp->buymargins[relpp->ind] = buymargin;
basepp->sellmargins[relpp->ind] = sellmargin;
7 years ago
basepp->offsets[relpp->ind] = offset;
basepp->factors[relpp->ind] = factor;
refbase = jstr(argjson,"refbase");
refrel = jstr(argjson,"refrel");
7 years ago
fundvalue_bid = jstr(argjson,"fundvalue_bid");
fundvalue_ask = jstr(argjson,"fundvalue_ask");
if ( fundvalue_bid != 0 || fundvalue_ask != 0 || fixedprice > SMALLVAL || (refbase != 0 && refrel != 0) )
7 years ago
{
if ( fixedprice > SMALLVAL )
{
refbase = base;
refrel = rel;
}
for (i=0; i<num_LP_autorefs; i++)
{
if ( strcmp(base,LP_autorefs[i].base) == 0 && strcmp(rel,LP_autorefs[i].rel) == 0 )
{
7 years ago
if ( fundvalue_bid != 0 || fundvalue_ask != 0 )
{
fundvalue = jduplicate(argjson);
jdelete(fundvalue,"method");
jaddstr(fundvalue,"method","fundvalue");
LP_autorefs[i].fundvalue = fundvalue;
safecopy(LP_autorefs[i].fundbid,fundvalue_bid,sizeof(LP_autorefs[i].fundbid));
safecopy(LP_autorefs[i].fundask,fundvalue_ask,sizeof(LP_autorefs[i].fundask));
}
7 years ago
LP_autorefs[i].buymargin = buymargin;
LP_autorefs[i].sellmargin = sellmargin;
7 years ago
LP_autorefs[i].factor = factor;
LP_autorefs[i].offset = offset;
7 years ago
safecopy(LP_autorefs[i].refbase,refbase,sizeof(LP_autorefs[i].refbase));
safecopy(LP_autorefs[i].refrel,refrel,sizeof(LP_autorefs[i].refrel));
printf("%d Update ref %s/%s for %s/%s factor %.8f offset %.8f\n",i,refbase,refrel,base,rel,factor,offset);
break;
}
}
if ( i == num_LP_autorefs && num_LP_autorefs < sizeof(LP_autorefs)/sizeof(*LP_autorefs) )
{
7 years ago
if ( fundvalue_bid != 0 || fundvalue_ask != 0 )
{
fundvalue = jduplicate(argjson);
jdelete(fundvalue,"method");
jaddstr(fundvalue,"method","fundvalue");
LP_autorefs[num_LP_autorefs].fundvalue = fundvalue;
safecopy(LP_autorefs[num_LP_autorefs].fundbid,fundvalue_bid,sizeof(LP_autorefs[num_LP_autorefs].fundbid));
safecopy(LP_autorefs[num_LP_autorefs].fundask,fundvalue_ask,sizeof(LP_autorefs[num_LP_autorefs].fundask));
}
7 years ago
LP_autorefs[i].buymargin = buymargin;
LP_autorefs[i].sellmargin = sellmargin;
7 years ago
LP_autorefs[num_LP_autorefs].factor = factor;
LP_autorefs[num_LP_autorefs].offset = offset;
7 years ago
safecopy(LP_autorefs[num_LP_autorefs].refbase,refbase,sizeof(LP_autorefs[num_LP_autorefs].refbase));
safecopy(LP_autorefs[num_LP_autorefs].refrel,refrel,sizeof(LP_autorefs[num_LP_autorefs].refrel));
safecopy(LP_autorefs[num_LP_autorefs].base,base,sizeof(LP_autorefs[num_LP_autorefs].base));
safecopy(LP_autorefs[num_LP_autorefs].rel,rel,sizeof(LP_autorefs[num_LP_autorefs].rel));
7 years ago
printf("%d Using ref %s/%s for %s/%s factor %.8f, offset %.8f, margin %.8f/%.8f fixed %.8f\n",num_LP_autorefs,refbase,refrel,base,rel,factor,offset,buymargin,sellmargin,fixedprice);
7 years ago
num_LP_autorefs++;
}
}
LP_autoprices++;
retval = 0;
7 years ago
}
7 years ago
//LP_autoprice_iter(ctx,LP_priceinfofind("BTC"));
7 years ago
return(retval);
8 years ago
}
7 years ago
int32_t LP_portfolio_trade(void *ctx,uint32_t *requestidp,uint32_t *quoteidp,struct iguana_info *buy,struct iguana_info *sell,double relvolume,int32_t setbaserel,char *gui)
8 years ago
{
7 years ago
char *retstr2; uint64_t txfee,desttxfee; double bid,ask,maxprice; bits256 zero; uint32_t requestid,quoteid,iter,i; cJSON *retjson2; struct LP_utxoinfo A; struct LP_address_utxo *utxos[1000]; int32_t max=(int32_t)(sizeof(utxos)/sizeof(*utxos));
LP_txfees(&txfee,&desttxfee,buy->symbol,sell->symbol);
8 years ago
requestid = quoteid = 0;
LP_myprice(&bid,&ask,buy->symbol,sell->symbol);
maxprice = ask;
if ( setbaserel != 0 )
{
strcpy(LP_portfolio_base,"");
strcpy(LP_portfolio_rel,"");
LP_portfolio_relvolume = 0.;
}
7 years ago
printf("pending.%d base buy.%s, rel sell.%s relvolume %f maxprice %.8f (%.8f %.8f)\n",G.LP_pendingswaps,buy->symbol,sell->symbol,sell->relvolume,maxprice,bid,ask);
8 years ago
if ( LP_pricevalid(maxprice) > 0 )
{
relvolume = sell->relvolume;
8 years ago
for (iter=0; iter<2; iter++)
8 years ago
{
if ( relvolume < dstr(LP_MIN_TXFEE) )
break;
7 years ago
if ( LP_address_myutxopair(&A,0,utxos,max,sell,sell->symbol,txfee,relvolume,maxprice,desttxfee) == 0 )
//if ( LP_utxo_bestfit(sell->symbol,SATOSHIDEN * relvolume) != 0 )
8 years ago
{
7 years ago
memset(zero.bytes,0,sizeof(zero));
7 years ago
if ( (retstr2= LP_autobuy(ctx,"127.0.0.1",-1,buy->symbol,sell->symbol,maxprice,relvolume,60,24*3600,gui,LP_lastnonce+1,zero,1)) != 0 )
8 years ago
{
if ( (retjson2= cJSON_Parse(retstr2)) != 0 )
{
if ( (requestid= juint(retjson2,"requestid")) != 0 && (quoteid= juint(retjson2,"quoteid")) != 0 )
{
}
free_json(retjson2);
}
printf("%s relvolume %.8f LP_autotrade.(%s)\n",sell->symbol,relvolume,retstr2);
free(retstr2);
}
if ( requestid != 0 && quoteid != 0 )
break;
} else printf("cant find alice %.8f %s\n",relvolume,sell->symbol);
8 years ago
if ( iter == 0 )
8 years ago
{
8 years ago
for (i=0; i<100; i++)
8 years ago
{
8 years ago
relvolume *= .99;
7 years ago
if ( LP_address_myutxopair(&A,0,utxos,max,sell,sell->symbol,txfee,relvolume,maxprice,desttxfee) == 0 )
//if ( LP_utxo_bestfit(sell->symbol,SATOSHIDEN * relvolume) != 0 )
8 years ago
{
printf("i.%d relvolume %.8f from %.8f\n",i,relvolume,sell->relvolume);
break;
}
8 years ago
}
}
8 years ago
}
}
else if ( setbaserel != 0 )
{
strcpy(LP_portfolio_base,buy->symbol);
strcpy(LP_portfolio_rel,sell->symbol);
LP_portfolio_relvolume = sell->relvolume;
}
*requestidp = requestid;
*quoteidp = quoteid;
if ( requestid != 0 && quoteid != 0 )
return(0);
else return(-1);
}
int32_t LP_portfolio_order(struct LP_portfoliotrade *trades,int32_t max,cJSON *array)
{
int32_t i,j,m,n = 0; cJSON *item; struct LP_portfoliotrade coins[256];
memset(coins,0,sizeof(coins));
if ( (m= cJSON_GetArraySize(array)) > 0 )
{
for (i=j=0; i<m && i<sizeof(coins)/sizeof(*coins); i++)
{
item = jitem(array,i);
safecopy(coins[j].buycoin,jstr(item,"coin"),sizeof(coins[j].buycoin));
coins[j].metric = jdouble(item,"force");
if ( fabs(coins[j].metric) > SMALLVAL && coins[j].buycoin[0] != 0 )
j++;
}
if ( (m= j) > 1 )
{
for (i=n=0; i<m-1; i++)
for (j=i+1; j<m; j++)
if ( coins[i].metric*coins[j].metric < 0. )
{
if ( coins[i].metric > 0. )
{
trades[n].metric = (coins[i].metric - coins[j].metric);
strcpy(trades[n].buycoin,coins[i].buycoin);
strcpy(trades[n].sellcoin,coins[j].buycoin);
printf("buy %s %f, sell %s %f -> %f\n",trades[n].buycoin,coins[i].metric,trades[n].sellcoin,coins[j].metric,trades[n].metric);
}
else
{
trades[n].metric = (coins[j].metric - coins[i].metric);
strcpy(trades[n].buycoin,coins[j].buycoin);
strcpy(trades[n].sellcoin,coins[i].buycoin);
printf("buy %s %f, sell %s %f -> %f\n",trades[n].buycoin,coins[j].metric,trades[n].sellcoin,coins[i].metric,trades[n].metric);
}
n++;
if ( n >= max )
break;
}
revsortds((void *)trades,n,sizeof(*trades));
for (i=0; i<n; i++)
printf("%d: buy %s, sell %s -> %f\n",i,trades[i].buycoin,trades[i].sellcoin,trades[i].metric);
}
}
return(n);
}
7 years ago
void prices_loop(void *ctx)
8 years ago
{
7 years ago
char *retstr; cJSON *retjson,*array; char *buycoin,*sellcoin; struct iguana_info *buy,*sell; uint32_t requestid,quoteid; int32_t i,n,m; struct LP_portfoliotrade trades[256]; struct LP_priceinfo *btcpp;
7 years ago
strcpy(prices_loop_stats.name,"prices_loop");
7 years ago
prices_loop_stats.threshold = 191000.;
while ( LP_STOP_RECEIVED == 0 )
8 years ago
{
7 years ago
//printf("prices loop autoprices.%d autorefs.%d\n",LP_autoprices,num_LP_autorefs);
7 years ago
LP_millistats_update(&prices_loop_stats);
7 years ago
LP_tradebots_timeslice(ctx);
8 years ago
if ( (btcpp= LP_priceinfofind("BTC")) == 0 )
{
7 years ago
printf("prices_loop BTC not in LP_priceinfofind\n");
8 years ago
sleep(60);
continue;
}
if ( LP_autoprices != 0 )
LP_autoprice_iter(ctx,btcpp);
8 years ago
if ( (retstr= LP_portfolio()) != 0 )
8 years ago
{
8 years ago
if ( (retjson= cJSON_Parse(retstr)) != 0 )
8 years ago
{
8 years ago
if ( (buycoin= jstr(retjson,"buycoin")) != 0 && (buy= LP_coinfind(buycoin)) != 0 && (sellcoin= jstr(retjson,"sellcoin")) != 0 && (sell= LP_coinfind(sellcoin)) != 0 && buy->inactive == 0 && sell->inactive == 0 )
8 years ago
{
7 years ago
if ( LP_portfolio_trade(ctx,&requestid,&quoteid,buy,sell,sell->relvolume,1,"portfolio") < 0 )
8 years ago
{
8 years ago
array = jarray(&m,retjson,"portfolio");
if ( array != 0 && (n= LP_portfolio_order(trades,(int32_t)(sizeof(trades)/sizeof(*trades)),array)) > 0 )
8 years ago
{
8 years ago
for (i=0; i<n; i++)
8 years ago
{
8 years ago
if ( strcmp(trades[i].buycoin,buycoin) != 0 || strcmp(trades[i].sellcoin,sellcoin) != 0 )
8 years ago
{
8 years ago
buy = LP_coinfind(trades[i].buycoin);
sell = LP_coinfind(trades[i].sellcoin);
7 years ago
if ( buy != 0 && sell != 0 && LP_portfolio_trade(ctx,&requestid,&quoteid,buy,sell,sell->relvolume,0,"portfolio") == 0 )
8 years ago
break;
8 years ago
}
8 years ago
}
8 years ago
}
}
8 years ago
}
8 years ago
free_json(retjson);
8 years ago
}
8 years ago
free(retstr);
}
7 years ago
sleep(30);
8 years ago
}
}
8 years ago