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.

1899 lines
89 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. *
* *
******************************************************************************/
#include <math.h>
#include "../crypto777/OS_portable.h"
#define _extrapolate_Spline(Splines,gap) ((double)(Splines)[0] + ((gap) * ((double)(Splines)[1] + ((gap) * ((double)(Splines)[2] + ((gap) * (double)(Splines)[3]))))))
#define _extrapolate_Slope(Splines,gap) ((double)(Splines)[1] + ((gap) * ((double)(Splines)[2] + ((gap) * (double)(Splines)[3]))))
#define PRICE_BLEND(oldval,newval,decay,oppodecay) ((oldval == 0.) ? newval : ((oldval * decay) + (oppodecay * newval)))
#define PRICE_BLEND64(oldval,newval,decay,oppodecay) ((oldval == 0) ? newval : ((oldval * decay) + (oppodecay * newval) + 0.499))
#define USD 0
#define EUR 1
#define JPY 2
#define GBP 3
#define AUD 4
#define CAD 5
#define CHF 6
#define NZD 7
#define CNY 8
#define RUB 9
#define NZDUSD 0
#define NZDCHF 1
#define NZDCAD 2
#define NZDJPY 3
#define GBPNZD 4
#define EURNZD 5
#define AUDNZD 6
#define CADJPY 7
#define CADCHF 8
#define USDCAD 9
#define EURCAD 10
#define GBPCAD 11
#define AUDCAD 12
#define USDCHF 13
#define CHFJPY 14
#define EURCHF 15
#define GBPCHF 16
#define AUDCHF 17
#define EURUSD 18
#define EURAUD 19
#define EURJPY 20
#define EURGBP 21
#define GBPUSD 22
#define GBPJPY 23
#define GBPAUD 24
#define USDJPY 25
#define AUDJPY 26
#define AUDUSD 27
#define USDNUM 28
#define EURNUM 29
#define JPYNUM 30
#define GBPNUM 31
#define AUDNUM 32
#define CADNUM 33
#define CHFNUM 34
#define NZDNUM 35
#define NUM_CONTRACTS 28
#define NUM_CURRENCIES 8
#define NUM_COMBINED (NUM_CONTRACTS + NUM_CURRENCIES)
#define MAX_SPLINES 64
#define MAX_LOOKAHEAD 48
#define MAX_EXCHANGES 64
#define MAX_CURRENCIES 32
#define PRICE_DECAY 0.9
#define INSTANTDEX_EXCHANGEID 0
#define INSTANTDEX_UNCONFID 1
#define INSTANTDEX_NXTAEID 2
#define DAYS_FIFO (512)
struct prices777_data
{
uint64_t tmillistamps[128]; double tbids[128],tasks[128],topens[128],thighs[128],tlows[128];
double flhlogmatrix[8][8],flogmatrix[8][8],fbids[128],fasks[128],fhighs[128],flows[128];
uint32_t itimestamps[128]; double ilogmatrix[8][8],ibids[128],iasks[128];
char edate[128]; double ecbmatrix[32][32],dailyprices[MAX_CURRENCIES * MAX_CURRENCIES],metals[4];
int32_t ecbdatenum,ecbyear,ecbmonth,ecbday; double RTmatrix[32][32],RTprices[128],RTmetals[4];
double btcusd,btcdbtc,cryptos[8];
};
struct prices777_spline { char name[64]; int32_t splineid,lasti,basenum,num,firstx,dispincr,spline32[MAX_SPLINES][4]; uint32_t utc32[MAX_SPLINES]; int64_t spline64[MAX_SPLINES][4]; double dSplines[MAX_SPLINES][4],pricevals[MAX_SPLINES+MAX_LOOKAHEAD],lastutc,lastval,aveslopeabs; };
struct prices777_info
{
struct prices777 *ptrs[1024],*truefx[128],*fxcm[128],*instaforex[128],*ecb[128];
struct prices777_spline splines[128]; double cryptovols[2][8][2],btcusd,btcdbtc,cnyusd;
int32_t num,numt,numf,numi,nume; char *jsonstr;
char truefxuser[64],truefxpass[64]; uint64_t truefxidnum;
struct prices777_data data,tmp; struct kv777 *kv;
float ecbdaily[DAYS_FIFO][MAX_CURRENCIES][MAX_CURRENCIES];
} BUNDLE;
uint64_t Currencymasks[NUM_CURRENCIES+1];
char CONTRACTS[][16] = { "NZDUSD", "NZDCHF", "NZDCAD", "NZDJPY", "GBPNZD", "EURNZD", "AUDNZD", "CADJPY", "CADCHF", "USDCAD", "EURCAD", "GBPCAD", "AUDCAD", "USDCHF", "CHFJPY", "EURCHF", "GBPCHF", "AUDCHF", "EURUSD", "EURAUD", "EURJPY", "EURGBP", "GBPUSD", "GBPJPY", "GBPAUD", "USDJPY", "AUDJPY", "AUDUSD", "USDCNY", "USDHKD", "USDMXN", "USDZAR", "USDTRY", "EURTRY", "TRYJPY", "USDSGD", "EURNOK", "USDNOK","USDSEK","USDDKK","EURSEK","EURDKK","NOKJPY","SEKJPY","USDPLN","EURPLN","USDILS", // no more currencies
"XAUUSD", "XAGUSD", "XPTUSD", "XPDUSD", "Copper", "NGAS", "UKOil", "USOil", // commodities
// cryptos
"NAS100", "SPX500", "US30", "Bund", "EUSTX50", "UK100", "JPN225", "GER30", "SUI30", "AUS200", "HKG33", "FRA40", "ESP35", "ITA40", "USDOLLAR", // indices
"SuperNET" // assets
};
char CURRENCIES[][8] = { "USD", "EUR", "JPY", "GBP", "AUD", "CAD", "CHF", "NZD", // major currencies
"CNY", "RUB", "MXN", "BRL", "INR", "HKD", "TRY", "ZAR", "PLN", "NOK", "SEK", "DKK", "CZK", "HUF", "ILS", "KRW", "MYR", "PHP", "RON", "SGD", "THB", "BGN", "IDR", "HRK", // end of currencies
"XAU", "XAG", "XPT", "XPD", // metals, gold must be first
"BTCD", "BTC", "NXT", "LTC", "ETH", "DOGE", "BTS", "MAID", "XCP", "XMR" // cryptos
};
int32_t MINDENOMS[] = { 1000, 1000, 100000, 1000, 1000, 1000, 1000, 1000, // major currencies
10000, 100000, 10000, 1000, 100000, 10000, 1000, 10000, 1000, 10000, 10000, 10000, 10000, 100000, 1000, 1000000, 1000, 10000, 1000, 1000, 10000, 1000, 10000000, 10000, // end of currencies
1, 100, 1, 1, // metals, gold must be first
1, 10, 100000, 100, 100, 10000000, 10000, 1000, 1000, 1000, 100000, 100000, 1000000 // cryptos
};
int32_t prices777_mindenomination(int32_t base)
{
return(MINDENOMS[base]);
}
short Contract_base[NUM_COMBINED+1] = { 7, 7, 7, 7, 3, 1, 4, 5, 5, 0, 1, 3, 4, 0, 6, 1, 3, 4, 1, 1, 1, 1, 3, 3, 3, 0, 4, 4, 0,1,2,3,4,5,6,7, 8 };// Contract_base };
short Contract_rel[NUM_COMBINED+1] = { 0, 6, 5, 2, 7, 7, 7, 2, 6, 5, 5, 5, 5, 6, 2, 6, 6, 6, 0, 4, 2, 3, 0, 2, 4, 2, 2, 0, 0,1,2,3,4,5,6,7,8 };// Contract_rel
short Baserel_contractnum[NUM_CURRENCIES+1][NUM_CURRENCIES+1] =
{
{ 28, 18, 25, 22, 27, 9, 13, 0, 36 },
{ 18, 29, 20, 21, 19, 10, 15, 5, 37 },
{ 25, 20, 30, 23, 26, 7, 14, 3, -1 },
{ 22, 21, 23, 31, 24, 11, 16, 4, 38 },
{ 27, 19, 26, 24, 32, 12, 17, 6, 39 },
{ 9, 10, 7, 11, 12, 33, 8, 2, -1 },
{ 13, 15, 14, 16, 17, 8, 34, 1, 40 },
{ 0, 5, 3, 4, 6, 2, 1, 35, -1 },
{ 36, 37, -1, 38, 39, -1, 40, -1, 74 },
};
short Baserel_contractdir[NUM_CURRENCIES+1][NUM_CURRENCIES+1] =
{
{ 1, -1, 1, -1, -1, 1, 1, -1, -1 },
{ 1, 1, 1, 1, 1, 1, 1, 1, -1 },
{ -1, -1, 1, -1, -1, -1, -1, -1, 0 },
{ 1, -1, 1, 1, 1, 1, 1, 1, -1 },
{ 1, -1, 1, -1, 1, 1, 1, 1, -1 },
{ -1, -1, 1, -1, -1, 1, 1, -1, 0 },
{ -1, -1, 1, -1, -1, -1, 1, -1, -1 },
{ 1, -1, 1, -1, -1, 1, 1, 1, 0 },
{ -1, -1, 0, -1, -1, 0, -1, 0, 1 },
};
short Currency_contracts[NUM_CURRENCIES+1][NUM_CURRENCIES] =
{
{ 0, 9, 13, 18, 22, 25, 27, 28, },
{ 5, 10, 15, 18, 19, 20, 21, 29, },
{ 3, 7, 14, 20, 23, 25, 26, 30, },
{ 4, 11, 16, 21, 22, 23, 24, 31, },
{ 6, 12, 17, 19, 24, 26, 27, 32, },
{ 2, 7, 8, 9, 10, 11, 12, 33, },
{ 1, 8, 13, 14, 15, 16, 17, 34, },
{ 0, 1, 2, 3, 4, 5, 6, 35, },
{ 36, 37, -1, 38, 39, -1, 40, 41, },
};
short Currency_contractothers[NUM_CURRENCIES+1][NUM_CURRENCIES] = // buggy!
{
{ 7, 5, 6, 1, 3, 2, 4, 0, },
{ 7, 5, 6, 0, 4, 2, 3, 1, },
{ 7, 5, 6, 1, 3, 0, 4, 2, },
{ 7, 5, 6, 1, 0, 2, 4, 3, },
{ 7, 5, 6, 1, 3, 2, 0, 4, },
{ 7, 2, 6, 0, 1, 3, 4, 5, },
{ 7, 5, 0, 2, 1, 3, 4, 6, },
{ 0, 6, 5, 2, 1, 3, 4, 7, },
{ 0, 1,-1, 3, 4,-1, 5,-1, },
};
short Currency_contractdirs[NUM_CURRENCIES+1][NUM_CURRENCIES] =
{
{ -1, 1, 1, -1, -1, 1, -1, 1 },
{ 1, 1, 1, 1, 1, 1, 1, 1 },
{ -1, -1, -1, -1, -1, -1, -1, 1 },
{ 1, 1, 1, -1, 1, 1, 1, 1 },
{ 1, 1, 1, -1, -1, 1, 1, 1 },
{ -1, 1, 1, -1, -1, -1, -1, 1 },
{ -1, -1, -1, 1, -1, -1, -1, 1 },
{ 1, 1, 1, 1, -1, -1, -1, 1 },
{ 1, 1, 1, 1, 1, 1, 1, 1 },
};
char *Yahoo_metals[] = { "XAU", "XAG", "XPT", "XPD" };
#define dto64(x) ((int64_t)((x) * (double)SATOSHIDEN * SATOSHIDEN))
#define dto32(x) ((int32_t)((x) * (double)SATOSHIDEN))
#define i64tod(x) ((double)(x) / ((double)SATOSHIDEN * SATOSHIDEN))
#define i32tod(x) ((double)(x) / (double)SATOSHIDEN)
#define _extrapolate_spline64(spline64,gap) ((double)i64tod((spline64)[0]) + ((gap) * ((double)i64tod(.001*.001*(spline64)[1]) + ((gap) * ((double)i64tod(.001*.001*.001*.001*(spline64)[2]) + ((gap) * (double)i64tod(.001*.001*.001*.001*.001*.001*(spline64)[3])))))))
#define _extrapolate_spline32(spline32,gap) ((double)i32tod((spline32)[0]) + ((gap) * ((double)i32tod(.001*.001*(spline32)[1]) + ((gap) * ((double)i32tod(.001*.001*.001*.001*(spline32)[2]) + ((gap) * (double)i32tod(.001*.001*.001*.001*.001*.001*(spline32)[3])))))))
double prices777_splineval(struct prices777_spline *spline,uint32_t timestamp,int32_t lookahead)
{
int32_t i,gap,ind = (spline->num - 1);
if ( timestamp >= spline->utc32[ind] )
{
gap = (timestamp - spline->utc32[ind]);
if ( gap < lookahead )
return(_extrapolate_spline64(spline->spline64[ind],gap));
else return(0.);
}
else if ( timestamp <= spline->utc32[0] )
{
gap = (spline->utc32[0] - timestamp);
if ( gap < lookahead )
return(_extrapolate_spline64(spline->spline64[0],gap));
else return(0.);
}
for (i=0; i<spline->num-1; i++)
{
ind = (i + spline->lasti) % (spline->num - 1);
if ( timestamp >= spline->utc32[ind] && timestamp < spline->utc32[ind+1] )
{
spline->lasti = ind;
return(_extrapolate_spline64(spline->spline64[ind],timestamp - spline->utc32[ind]));
}
}
return(0.);
}
double prices777_calcspline(struct prices777_spline *spline,double *outputs,double *slopes,int32_t dispwidth,uint32_t *utc32,double *splinevals,int32_t num)
{
static double errsums[3]; static int errcount;
double c[MAX_SPLINES],f[MAX_SPLINES],dd[MAX_SPLINES],dl[MAX_SPLINES],du[MAX_SPLINES],gaps[MAX_SPLINES];
int32_t n,i,lasti,x,numsplines,nonz; double vx,vy,vw,vz,gap,sum,xval,yval,abssum,lastval,lastxval,yval64,yval32,yval3; uint32_t gap32;
sum = lastxval = n = lasti = nonz = 0;
for (i=0; i<MAX_SPLINES&&i<num; i++)
{
if ( (f[n]= splinevals[i]) != 0. && utc32[i] != 0 )
{
//printf("i%d.(%f %f) ",i,utc[i],splinevals[i]);
if ( n > 0 )
{
if ( (gaps[n-1]= utc32[i] - lastxval) < 0 )
{
printf("illegal gap %f to t%d\n",lastxval,utc32[i]);
return(0);
}
}
spline->utc32[n] = lastxval = utc32[i];
n++;
}
}
if ( (numsplines= n) < 4 )
return(0);
for (i=0; i<n-3; i++)
dl[i] = du[i] = gaps[i+1];
for (i=0; i<n-2; i++)
{
dd[i] = 2.0 * (gaps[i] + gaps[i+1]);
c[i] = (3.0 / (double)gaps[i+1]) * (f[i+2] - f[i+1]) - (3.0 / (double)gaps[i]) * (f[i+1] - f[i]);
}
//for (i=0; i<n; i++) printf("%f ",f[i]);
//printf("F2[%d]\n",n);
dd[0] += (gaps[0] + (double)gaps[0]*gaps[0] / gaps[1]);
du[0] -= ((double)gaps[0]*gaps[0] / gaps[1]);
dd[n-3] += (gaps[n-2] + (double)gaps[n-2]*gaps[n-2] / gaps[n-3]);
dl[n-4] -= ((double)gaps[n-2]*gaps[n-2] / gaps[n-3]);
//tridiagonal(n-2, dl, dd, du, c);
for (i=0; i<n-1-2; i++)
{
du[i] /= dd[i];
dd[i+1] -= dl[i]*du[i];
}
c[0] /= dd[0];
for (i=1; i<n-2; i++)
c[i] = (c[i] - dl[i-1] * c[i-1]) / dd[i];
for (i=n-2-4; i>=0; i--)
c[i] -= c[i+1] * du[i];
//tridiagonal(n-2, dl, dd, du, c);
for (i=n-3; i>=0; i--)
c[i+1] = c[i];
c[0] = (1.0 + (double)gaps[0] / gaps[1]) * c[1] - ((double)gaps[0] / gaps[1] * c[2]);
c[n-1] = (1.0 + (double)gaps[n-2] / gaps[n-3] ) * c[n-2] - ((double)gaps[n-2] / gaps[n-3] * c[n-3]);
//printf("c[n-1] %f, n-2 %f, n-3 %f\n",c[n-1],c[n-2],c[n-3]);
abssum = nonz = lastval = 0;
outputs[spline->firstx] = f[0];
spline->num = numsplines;
for (i=0; i<n; i++)
{
vx = f[i];
vz = c[i];
if ( i < n-1 )
{
gap = gaps[i];
vy = ((f[i+1] - f[i]) / gap) - (gap * (c[i+1] + 2.*c[i]) / 3.);
vw = (c[i+1] - c[i]) / (3. * gap);
}
else
{
vy = 0;
vw = 0;
}
//printf("%3d: t%u [%14.11f %14.11f %14.11f %14.11f] gap %f | %d\n",i,spline->utc32[i],(vx),vy*1000*1000,vz*1000*1000*1000*1000,vw*1000*1000*1000*1000*1000*1000,gap,conv_unixtime(&tmp,spline->utc32[i]));
spline->dSplines[i][0] = vx, spline->dSplines[i][1] = vy, spline->dSplines[i][2] = vz, spline->dSplines[i][3] = vw;
spline->spline64[i][0] = dto64(vx), spline->spline64[i][1] = dto64(vy*1000*1000), spline->spline64[i][2] = dto64(vz*1000*1000*1000*1000), spline->spline64[i][3] = dto64(vw*1000*1000*1000*1000*1000*1000);
spline->spline32[i][0] = dto32(vx), spline->spline32[i][1] = dto32(vy*1000*1000), spline->spline32[i][2] = dto32(vz*1000*1000*1000*1000), spline->spline32[i][3] = dto32(vw*1000*1000*1000*1000*1000*1000);
gap32 = gap = spline->dispincr;
xval = spline->utc32[i] + gap;
lastval = vx;
while ( i < n-1 )
{
x = spline->firstx + ((xval - spline->utc32[0]) / spline->dispincr);
if ( x > dispwidth-1 ) x = dispwidth-1;
if ( x < 0 ) x = 0;
if ( (i < n-2 && gap > gaps[i] + spline->dispincr) )
break;
if ( i == n-2 && xval > spline->utc32[n-1] + MAX_LOOKAHEAD*spline->dispincr )
{
//printf("x.%d dispwidth.%d xval %f > utc[n-1] %f + %f\n",x,dispwidth,xval,utc[n-1],MAX_LOOKAHEAD*incr);
break;
}
if ( x >= 0 )
{
yval = _extrapolate_Spline(spline->dSplines[i],gap);
yval64 = _extrapolate_spline64(spline->spline64[i],gap32);
if ( (yval3 = prices777_splineval(spline,gap32 + spline->utc32[i],MAX_LOOKAHEAD*spline->dispincr)) != 0 )
{
yval32 = _extrapolate_spline32(spline->spline32[i],gap32);
errsums[0] += fabs(yval - yval64), errsums[1] += fabs(yval - yval32), errsums[2] += fabs(yval - yval3), errcount++;
if ( fabs(yval - yval3) > SMALLVAL )
printf("(%.10f vs %.10f %.10f %.10f [%.16f %.16f %.16f]) ",yval,yval64,yval32,yval3, errsums[0]/errcount,errsums[1]/errcount,errsums[2]/errcount);
}
if ( yval > 5000. ) yval = 5000.;
else if ( yval < -5000. ) yval = -5000.;
if ( isnan(yval) == 0 )
{
outputs[x] = yval;
spline->lastval = outputs[x], spline->lastutc = xval;
if ( 1 && fabs(lastval) > SMALLVAL )
{
if ( lastval != 0 && outputs[x] != 0 )
{
if ( slopes != 0 )
slopes[x] = (outputs[x] - lastval), abssum += fabs(slopes[x]);
nonz++;
}
}
}
//else outputs[x] = 0.;
//printf("x.%-4d %d %f %f %f i%-4d: gap %9.6f %9.6f last %9.6f slope %9.6f | %9.1f [%9.1f %9.6f %9.6f %9.6f %9.6f]\n",x,firstx,xval,utc[0],incr,i,gap,yval,lastval,slopes[x],xval,utc[i+1],dSplines[i][0],dSplines[i][1]*1000*1000,dSplines[i][2]*1000*1000*1000*1000,dSplines[i][3]*1000*1000*1000*1000*1000*1000);
}
gap32 += spline->dispincr, gap += spline->dispincr, xval += spline->dispincr;
}
//double pred = (i>0) ? _extrapolate_Spline(dSplines[i-1],gaps[i-1]) : 0.;
//printf("%2d: w%8.1f [gap %f -> %9.6f | %9.6f %9.6f %9.6f %9.6f %9.6f]\n",i,weekinds[i],gap,pred,f[i],dSplines[i].x,1000000*dSplines[i].y,1000000*1000000*dSplines[i].z,1000000*1000000*1000*dSplines[i].w);
}
if ( nonz != 0 )
abssum /= nonz;
spline->aveslopeabs = abssum;
return(lastval);
}
int32_t prices777_genspline(struct prices777_spline *spline,int32_t splineid,char *name,uint32_t *utc32,double *splinevals,int32_t maxsplines,double *refvals)
{
int32_t i; double output[2048],slopes[2048],origvals[MAX_SPLINES];
memset(spline,0,sizeof(*spline)), memset(output,0,sizeof(output)), memset(slopes,0,sizeof(slopes));
spline->dispincr = 3600, spline->basenum = splineid, strcpy(spline->name,name);
memcpy(origvals,splinevals,sizeof(*splinevals) * MAX_SPLINES);
spline->lastval = prices777_calcspline(spline,output,slopes,sizeof(output)/sizeof(*output),utc32,splinevals,maxsplines);
for (i=0; i<spline->num+3; i++)
{
if ( i < spline->num )
{
if ( refvals[i] != 0 && output[i * 24] != refvals[i] )
printf("{%.8f != %.8f}.%d ",output[i * 24],refvals[i],i);
}
else printf("{%.8f %.3f} ",output[i * 24],slopes[i * 24]/spline->aveslopeabs);
spline->pricevals[i] = output[i * 24];
}
printf("spline.%s num.%d\n",name,spline->num);
return(spline->num);
}
double prices777_baseprice(uint32_t timestamp,int32_t basenum)
{
double btc,btcd,btcdusd,usdval;
btc = 1000. * _pairaved(prices777_splineval(&BUNDLE.splines[MAX_CURRENCIES+0],timestamp,0),prices777_splineval(&BUNDLE.splines[MAX_CURRENCIES+1],timestamp,0));
btcd = .01 * prices777_splineval(&BUNDLE.splines[MAX_CURRENCIES+2],timestamp,0);
if ( btc != 0. && btcd != 0. )
{
btcdusd = (btc * btcd);
usdval = prices777_splineval(&BUNDLE.splines[USD],timestamp,0);
if ( basenum == USD )
return(1. / btcdusd);
else return(prices777_splineval(&BUNDLE.splines[basenum],timestamp,0) / (btcdusd * usdval));
}
return(0.);
}
int32_t prices777_ispair(char *base,char *rel,char *contract)
{
int32_t i,j;
base[0] = rel[0] = 0;
for (i=0; i<sizeof(CURRENCIES)/sizeof(*CURRENCIES); i++)
{
if ( strncmp(CURRENCIES[i],contract,strlen(CURRENCIES[i])) == 0 )
{
for (j=0; j<sizeof(CURRENCIES)/sizeof(*CURRENCIES); j++)
if ( strcmp(CURRENCIES[j],contract+strlen(CURRENCIES[i])) == 0 )
{
strcpy(base,CURRENCIES[i]);
strcpy(rel,CURRENCIES[j]);
/*USDCNY 6.209700 -> 0.655564
USDCNY 6.204146 -> 0.652686
USDHKD 7.753400 -> 0.749321
USDHKD 7.746396 -> 0.746445
USDZAR 12.694000 -> 1.101688
USDZAR 12.682408 -> 1.098811
USDTRY 2.779700 -> 0.341327
EURTRY 3.048500 -> 0.386351
TRYJPY 44.724000 -> 0.690171
TRYJPY 44.679966 -> 0.687290
USDSGD 1.375200 -> 0.239415*/
//if ( strcmp(contract,"USDCNY") == 0 || strcmp(contract,"TRYJPY") == 0 || strcmp(contract,"USDZAR") == 0 )
// printf("i.%d j.%d base.%s rel.%s\n",i,j,base,rel);
return((i<<8) | j);
}
break;
}
}
return(-1);
}
int32_t prices777_basenum(char *base)
{
int32_t i,j;
if ( 1 )
{
for (i=0; i<sizeof(CURRENCIES)/sizeof(*CURRENCIES); i++)
for (j=0; j<sizeof(CURRENCIES)/sizeof(*CURRENCIES); j++)
if ( i != j && strcmp(CURRENCIES[i],CURRENCIES[j]) == 0 )
printf("duplicate.(%s)\n",CURRENCIES[i]);//, getchar();
}
for (i=0; i<sizeof(CURRENCIES)/sizeof(*CURRENCIES); i++)
if ( strcmp(CURRENCIES[i],base) == 0 )
return(i);
return(-1);
}
int32_t prices777_contractnum(char *base,char *rel)
{
int32_t i,j,c; char contractstr[16],*contract = 0;
if ( 0 )
{
for (i=0; i<sizeof(CONTRACTS)/sizeof(*CONTRACTS); i++)
for (j=0; j<sizeof(CONTRACTS)/sizeof(*CONTRACTS); j++)
if ( i != j && strcmp(CONTRACTS[i],CONTRACTS[j]) == 0 )
printf("duplicate.(%s)\n",CONTRACTS[i]);//, getchar();
}
if ( base != 0 && base[0] != 0 && rel != 0 && rel[0] != 0 )
{
for (i=0; i<NUM_CURRENCIES; i++)
if ( strcmp(base,CURRENCIES[i]) == 0 )
{
for (j=0; j<NUM_CURRENCIES; j++)
if ( strcmp(rel,CURRENCIES[j]) == 0 )
return(Baserel_contractnum[i][j]);
break;
}
sprintf(contractstr,"%s%s",base,rel);
contract = contractstr;
} else contract = base;
if ( contract != 0 && contract[0] != 0 )
{
for (c=0; c<sizeof(CONTRACTS)/sizeof(*CONTRACTS); c++)
if ( strcmp(CONTRACTS[c],contract) == 0 )
return(c);
}
return(-1);
}
void init_Currencymasks()
{
int32_t base,j,c; uint64_t basemask;
for (base=0; base<NUM_CURRENCIES; base++)
{
basemask = 0L;
for (j=0; j<7; j++)
{
if ( (c= Currency_contracts[base][j]) >= 0 )
{
basemask |= (1L << c);
//printf("(%s %lx) ",CONTRACTS[c],1L<<c);
}
}
Currencymasks[base] = basemask;
printf("0x%llx, ",(long long)basemask);
}
}
double calc_primary_currencies(double logmatrix[8][8],double *bids,double *asks)
{
uint64_t nonzmask; int32_t c,base,rel; double bid,ask;
memset(logmatrix,0,sizeof(double)*8*8);
nonzmask = 0;
for (c=0; c<28; c++)
{
bid = bids[c];
ask = asks[c];
if ( bid != 0 && ask != 0 )
{
base = Contract_base[c];
rel = Contract_rel[c];
nonzmask |= (1L << c);
logmatrix[base][rel] = log(bid);
logmatrix[rel][base] = -log(ask);
//printf("[%f %f] ",bid,ask);
}
}
//printf("%07lx\n",nonzmask);
if ( nonzmask != 0 )
{
bids[USDNUM] = (logmatrix[USD][EUR] + logmatrix[USD][JPY] + logmatrix[USD][GBP] + logmatrix[USD][AUD] + logmatrix[USD][CAD] + logmatrix[USD][CHF] + logmatrix[USD][NZD]) / 8.;
asks[USDNUM] = -(logmatrix[EUR][USD] + logmatrix[JPY][USD] + logmatrix[GBP][USD] + logmatrix[AUD][USD] + logmatrix[CAD][USD] + logmatrix[CHF][USD] + logmatrix[NZD][USD]) / 8.;
bids[EURNUM] = (logmatrix[EUR][USD] + logmatrix[EUR][JPY] + logmatrix[EUR][GBP] + logmatrix[EUR][AUD] + logmatrix[EUR][CAD] + logmatrix[EUR][CHF] + logmatrix[EUR][NZD]) / 8.;
asks[EURNUM] = -(logmatrix[USD][EUR] + logmatrix[JPY][EUR] + logmatrix[GBP][EUR] + logmatrix[AUD][EUR] + logmatrix[CAD][EUR] + logmatrix[CHF][EUR] + logmatrix[NZD][EUR]) / 8.;
bids[JPYNUM] = (logmatrix[JPY][USD] + logmatrix[JPY][EUR] + logmatrix[JPY][GBP] + logmatrix[JPY][AUD] + logmatrix[JPY][CAD] + logmatrix[JPY][CHF] + logmatrix[JPY][NZD]) / 8.;
asks[JPYNUM] = -(logmatrix[USD][JPY] + logmatrix[EUR][JPY] + logmatrix[GBP][JPY] + logmatrix[AUD][JPY] + logmatrix[CAD][JPY] + logmatrix[CHF][JPY] + logmatrix[NZD][JPY]) / 8.;
bids[GBPNUM] = (logmatrix[GBP][USD] + logmatrix[GBP][EUR] + logmatrix[GBP][JPY] + logmatrix[GBP][AUD] + logmatrix[GBP][CAD] + logmatrix[GBP][CHF] + logmatrix[GBP][NZD]) / 8.;
asks[GBPNUM] = -(logmatrix[USD][GBP] + logmatrix[EUR][GBP] + logmatrix[JPY][GBP] + logmatrix[AUD][GBP] + logmatrix[CAD][GBP] + logmatrix[CHF][GBP] + logmatrix[NZD][GBP]) / 8.;
bids[AUDNUM] = (logmatrix[AUD][USD] + logmatrix[AUD][EUR] + logmatrix[AUD][JPY] + logmatrix[AUD][GBP] + logmatrix[AUD][CAD] + logmatrix[AUD][CHF] + logmatrix[AUD][NZD]) / 8.;
asks[AUDNUM] = -(logmatrix[USD][AUD] + logmatrix[EUR][AUD] + logmatrix[JPY][AUD] + logmatrix[GBP][AUD] + logmatrix[CAD][AUD] + logmatrix[CHF][AUD] + logmatrix[NZD][AUD]) / 8.;
bids[CADNUM] = (logmatrix[CAD][USD] + logmatrix[CAD][EUR] + logmatrix[CAD][JPY] + logmatrix[CAD][GBP] + logmatrix[CAD][AUD] + logmatrix[CAD][CHF] + logmatrix[CAD][NZD]) / 8.;
asks[CADNUM] = -(logmatrix[USD][CAD] + logmatrix[EUR][CAD] + logmatrix[JPY][CAD] + logmatrix[GBP][CAD] + logmatrix[AUD][CAD] + logmatrix[CHF][CAD] + logmatrix[NZD][CAD]) / 8.;
bids[CHFNUM] = (logmatrix[CHF][USD] + logmatrix[CHF][EUR] + logmatrix[CHF][JPY] + logmatrix[CHF][GBP] + logmatrix[CHF][AUD] + logmatrix[CHF][CAD] + logmatrix[CHF][NZD]) / 8.;
asks[CHFNUM] = -(logmatrix[USD][CHF] + logmatrix[EUR][CHF] + logmatrix[JPY][CHF] + logmatrix[GBP][CHF] + logmatrix[AUD][CHF] + logmatrix[CAD][CHF] + logmatrix[NZD][CHF]) / 8.;
bids[NZDNUM] = (logmatrix[NZD][USD] + logmatrix[NZD][EUR] + logmatrix[NZD][JPY] + logmatrix[NZD][GBP] + logmatrix[NZD][AUD] + logmatrix[NZD][CAD] + logmatrix[NZD][CHF]) / 8.;
asks[NZDNUM] = -(logmatrix[USD][NZD] + logmatrix[EUR][NZD] + logmatrix[JPY][NZD] + logmatrix[GBP][NZD] + logmatrix[AUD][NZD] + logmatrix[CAD][NZD] + logmatrix[CHF][NZD]) / 8.;
if ( nonzmask != ((1<<28)-1) )
{
for (base=0; base<8; base++)
{
if ( (nonzmask & Currencymasks[base]) != Currencymasks[base] )
bids[base+28] = asks[base+28] = 0;
//else printf("%s %9.6f | ",CONTRACTS[base+28],_pairaved(bids[base+28],asks[base+28]));
}
//printf("keep.%07lx\n",nonzmask);
return(0);
}
if ( 0 && nonzmask != 0 )
{
for (base=0; base<8; base++)
printf("%s.%9.6f | ",CONTRACTS[base+28],_pairaved(bids[base+28],asks[base+28]));
printf("%07llx\n",(long long)nonzmask);
}
}
return(0);
}
double prices777_getprice(char *retbuf,char *base,char *rel,char *contract)
{
int32_t i,c,basenum,relnum,n = 0; double yprice,daily,revdaily,price,bid,ask;
struct prices777 *prices; struct prices777_data *dp = &BUNDLE.data;
price = yprice = daily = revdaily = 0.;
prices777_ispair(base,rel,contract);
if ( base[0] != 0 && rel[0] != 0 )
{
basenum = prices777_basenum(base), relnum = prices777_basenum(rel);
if ( basenum >= 0 && relnum >= 0 && basenum < MAX_CURRENCIES && relnum < MAX_CURRENCIES )
daily = dp->dailyprices[basenum*MAX_CURRENCIES + relnum], revdaily = dp->dailyprices[relnum*MAX_CURRENCIES + basenum];
}
for (i=0; i<sizeof(Yahoo_metals)/sizeof(*Yahoo_metals); i++)
if ( strncmp(Yahoo_metals[i],contract,3) == 0 && strcmp(contract+3,"USD") == 0 )
{
yprice = dp->metals[i];
break;
}
sprintf(retbuf,"{\"result\":\"success\",\"contract\":\"%s\",\"base\":\"%s\",\"rel\":\"%s\"",contract,base,rel);
for (i=0; i<BUNDLE.num; i++)
{
if ( (prices= BUNDLE.ptrs[i]) != 0 )
{
//printf("(%s) (%s) (%s)\n",prices->contract,prices->base,prices->rel);
if ( strcmp(contract,prices->contract) == 0 && (bid= prices->lastbid) != 0 && (ask= prices->lastask) != 0 )
{
price += (bid + ask), n += 2;
printf("%s add %f %f -> %f [%f]\n",prices->exchange,bid,ask,price,price/n);
sprintf(retbuf+strlen(retbuf),",\"%s\":{\"bid\":%.8f,\"ask\":%.8f}",prices->exchange,bid,ask);
}
}
}
if ( (c= prices777_contractnum(contract,0)) >= 0 )
{
if ( dp->tbids[c] != 0. && dp->tasks[c] != 0. )
{
price += (dp->tbids[c] + dp->tasks[c]), n += 2;
sprintf(retbuf+strlen(retbuf),",\"truefx\":{\"millistamp\":\"%llu\",\"bid\":%.8f,\"ask\":%.8f,\"open\":%.8f,\"high\":%.8f,\"low\":%.8f}",(long long)dp->tmillistamps[c],dp->tbids[c],dp->tasks[c],dp->topens[c],dp->thighs[c],dp->tlows[c]);
}
if ( dp->fbids[c] != 0. && dp->fasks[c] != 0. )
{
price += (dp->fbids[c] + dp->fasks[c]), n += 2;
sprintf(retbuf+strlen(retbuf),",\"fxcm\":{\"bid\":%.8f,\"ask\":%.8f,\"high\":%.8f,\"low\":%.8f}",dp->fbids[c],dp->fasks[c],dp->fhighs[c],dp->flows[c]);
}
if ( dp->ibids[c] != 0. && dp->iasks[c] != 0. )
{
price += (dp->ibids[c] + dp->iasks[c]), n += 2;
sprintf(retbuf+strlen(retbuf),",\"instaforex\":{\"timestamp\":%u,\"bid\":%.8f,\"ask\":%.8f}",dp->itimestamps[c],dp->ibids[c],dp->iasks[c]);
}
if ( yprice != 0. )
sprintf(retbuf+strlen(retbuf),",\"yahoo\":{\"price\":%.8f}",yprice);
if ( daily != 0. || revdaily != 0. )
sprintf(retbuf+strlen(retbuf),",\"ecb\":{\"date\":\"%s\",\"daily\":%.8f,\"reverse\":%.8f}",dp->edate,daily,revdaily);
}
if ( n > 0 )
price /= n;
sprintf(retbuf+strlen(retbuf),",\"aveprice\":%.8f,\"n\":%d}",price,n);
return(price);
}
struct prices777 *prices777_initpair(int32_t needfunc,char *exchange,char *_base,char *_rel,double decay,char *_name,uint64_t baseid,uint64_t relid,int32_t basketsize)
{
static long allocated;
int32_t i,rellen; char basebuf[64],relbuf[64],base[64],rel[64],name[64]; struct exchange_info *exchangeptr;
struct prices777 *prices;
safecopy(base,_base,sizeof(base));
safecopy(rel,_rel,sizeof(rel));
safecopy(name,_name,sizeof(name));
if ( needfunc < 0 )
{
for (i=0; i<sizeof(funcs)/sizeof(*funcs); i++)
{
if ( (exchangeptr= find_exchange(0,funcs[i].exchange)) != 0 )
{
printf("%p %s set supports.%p %p coinbalance.%p\n",exchangeptr,funcs[i].exchange,funcs[i].supports,funcs[i].trade,funcs[i].parsebalance);
exchangeptr->issue = funcs[i];
}
}
return(0);
}
//printf("init.(%s/%s) name.(%s) %llu %llu\n",base,rel,name,(long long)baseid,(long long)relid);
if ( strcmp(exchange,"nxtae") == 0 || strcmp(exchange,"unconf") == 0 )//|| strcmp(exchange,"InstantDEX") == 0 )
{
if ( strcmp(base,"NXT") == 0 || baseid == NXT_ASSETID )
{
strcpy(base,rel), baseid = relid;
strcpy(rel,"NXT"), relid = NXT_ASSETID;
printf("flip.(%s/%s) %llu %llu\n",base,rel,(long long)baseid,(long long)relid);
}
}
for (i=0; i<BUNDLE.num; i++)
{
if ( strcmp(BUNDLE.ptrs[i]->exchange,exchange) == 0 )
{
if ( baseid != 0 && relid != 0 && BUNDLE.ptrs[i]->baseid == baseid && BUNDLE.ptrs[i]->relid == relid )
return(BUNDLE.ptrs[i]);
if ( strcmp(BUNDLE.ptrs[i]->origbase,base) == 0 && strcmp(BUNDLE.ptrs[i]->origrel,rel) == 0 )
return(BUNDLE.ptrs[i]);
}
}
printf("cant find (%s) (%llu) (%llu) (%s) (%s)\n",exchange,(long long)baseid,(long long)relid,base,rel);
prices = calloc(1,sizeof(*prices) + basketsize*sizeof(*prices->basket));
// printf("new prices %ld\n",sizeof(*prices));
strcpy(prices->exchange,exchange), strcpy(prices->contract,name), strcpy(prices->base,base), strcpy(prices->rel,rel);
prices->baseid = baseid, prices->relid = relid;
prices->contractnum = InstantDEX_name(prices->key,&prices->keysize,exchange,prices->contract,prices->base,&prices->baseid,prices->rel,&prices->relid);
portable_mutex_init(&prices->mutex);
strcpy(prices->origbase,base);
if ( rel[0] != 0 )
strcpy(prices->origrel,rel);
allocated += sizeof(*prices);
safecopy(prices->exchange,exchange,sizeof(prices->exchange));
if ( strcmp(exchange,"nxtae") == 0 || strcmp(exchange,"unconf") == 0 || strcmp(exchange,INSTANTDEX_NAME) == 0 )
{
char tmp[16];
_set_assetname(&prices->basemult,tmp,0,prices->baseid);
_set_assetname(&prices->relmult,tmp,0,prices->relid);
if ( (prices->relid != NXT_ASSETID && prices->relid < (1LL << (5*8))) || (prices->baseid != NXT_ASSETID && prices->baseid == (1LL << (5*8))) )
{
printf("illegal baseid.%llu or relid.%llu\n",(long long)prices->baseid,(long long)prices->relid);
free(prices);
return(0);
}
//prices->nxtbooks = calloc(1,sizeof(*prices->nxtbooks));
safecopy(prices->lbase,base,sizeof(prices->lbase)), tolowercase(prices->lbase);
safecopy(prices->lrel,rel,sizeof(prices->lrel)), tolowercase(prices->lrel);
rellen = (int32_t)(strlen(prices->rel) + 1);
tmp[0] = 0;
prices->type = _set_assetname(&prices->ap_mult,tmp,0,prices->baseid);
printf("nxtbook.(%s) -> NXT %s %llu/%llu vs (%s) mult.%llu (%llu/%llu)\n",base,prices->contract,(long long)prices->baseid,(long long)prices->relid,tmp,(long long)prices->ap_mult,(long long)prices->basemult,(long long)prices->relmult);
}
else
{
prices->basemult = prices->relmult = 1;
safecopy(prices->base,base,sizeof(prices->base)), touppercase(prices->base);
safecopy(prices->lbase,base,sizeof(prices->lbase)), tolowercase(prices->lbase);
if ( rel[0] == 0 && prices777_ispair(basebuf,relbuf,base) >= 0 )
{
strcpy(base,basebuf), strcpy(rel,relbuf);
//printf("(%s) is a pair (%s)+(%s)\n",base,basebuf,relbuf);
}
if ( rel[0] != 0 )
{
rellen = (int32_t)(strlen(rel) + 1);
safecopy(prices->rel,rel,sizeof(prices->rel)), touppercase(prices->rel);
safecopy(prices->lrel,rel,sizeof(prices->lrel)), tolowercase(prices->lrel);
if ( prices->contract[0] == 0 )
{
strcpy(prices->contract,prices->base);
if ( strcmp(prices->rel,&prices->contract[strlen(prices->contract)-3]) != 0 )
strcat(prices->contract,"/"), strcat(prices->contract,prices->rel);
}
//printf("create base.(%s) rel.(%s)\n",prices->base,prices->rel);
}
else
{
if ( prices->contract[0] == 0 )
strcpy(prices->contract,base);
}
}
char str[65]; printf("%s init_pair.(%s) (%s)(%s).%llu -> (%s) keysize.%d crc.%u (baseid.%llu relid.%llu)\n",mbstr(str,allocated),exchange,base,rel,(long long)prices->contractnum,prices->contract,prices->keysize,calc_crc32(0,(void *)prices->key,prices->keysize),(long long)prices->baseid,(long long)prices->relid);
prices->decay = decay, prices->oppodecay = (1. - decay);
prices->RTflag = 1;
if ( (exchangeptr= find_exchange(0,exchange)) != 0 )
{
if ( prices->commission == 0. )
prices->commission = exchangeptr->commission;
prices->exchangeid = exchangeptr->exchangeid;
if ( exchangeptr->issue.update == 0 )
{
for (i=0; i<sizeof(funcs)/sizeof(*funcs); i++)
{
if ( strcmp(exchange,funcs[i].exchange) == 0 )
{
exchangeptr->issue = funcs[i];
//printf("return prices.%p\n",prices);
}
}
}
if ( exchangeptr->refcount == 0 )
{
printf("incr refcount.%s from %d\n",exchangeptr->name,exchangeptr->refcount);
exchangeptr->refcount++;
}
return(prices);
}
//printf("initialized.(%s).%lld\n",prices->contract,(long long)prices->contractnum);
return(prices);
}
int32_t is_pair(char *base,char *rel,char *refbase,char *refrel)
{
if ( strcmp(base,refbase) == 0 && strcmp(rel,refrel) == 0 )
return(1);
else if ( strcmp(rel,refbase) == 0 && strcmp(base,refrel) == 0 )
return(-1);
return(0);
}
struct prices777 *prices777_poll(char *_exchangestr,char *_name,char *_base,uint64_t refbaseid,char *_rel,uint64_t refrelid)
{
char exchangestr[64],base[64],rel[64],name[64],key[1024]; uint64_t baseid,relid;
int32_t keysize,exchangeid,valid; struct exchange_info *exchange; struct prices777 *prices;
baseid = refbaseid, relid = refrelid;
strcpy(exchangestr,_exchangestr), strcpy(base,_base), strcpy(rel,_rel), strcpy(name,_name);
if ( (strcmp(exchangestr,"huobi") == 0 && is_pair(base,rel,"BTC","CNY") == 0 && is_pair(base,rel,"LTC","CNY") == 0) ||
((strcmp(exchangestr,"bityes") == 0 || strcmp(exchangestr,"okcoin") == 0) && is_pair(base,rel,"BTC","USD") == 0 && is_pair(base,rel,"LTC","USD") == 0) ||
((strcmp(exchangestr,"bitstamp") == 0 || strcmp(exchangestr,"coinbase") == 0) && is_pair(base,rel,"BTC","USD") == 0) ||
(strcmp(exchangestr,"lakebtc") == 0 && is_pair(base,rel,"BTC","CNY") == 0 && is_pair(base,rel,"BTC","USD") == 0) ||
(strcmp(exchangestr,"quadriga") == 0 && is_pair(base,rel,"BTC","CAD") == 0 && is_pair(base,rel,"BTC","USD") == 0) ||
0 )
{
printf("%s (%s/%s) is not a supported trading pair\n",exchangestr,base,rel);
return(0);
}
InstantDEX_name(key,&keysize,exchangestr,name,base,&baseid,rel,&relid);
//printf("call addbundle\n");
if ( (prices= prices777_addbundle(&valid,0,0,exchangestr,baseid,relid)) != 0 )
{
printf("found (%s/%s).%s %llu %llu in slot-> %p\n",base,rel,exchangestr,(long long)baseid,(long long)relid,prices);
return(prices);
}
//printf("call find_exchange\n");
if ( (exchange= find_exchange(&exchangeid,exchangestr)) == 0 )
{
printf("cant add exchange.(%s)\n",exchangestr);
return(0);
}
if ( strcmp(exchangestr,"nxtae") == 0 || strcmp(exchangestr,"unconf") == 0 )
{
if ( strcmp(base,"NXT") != 0 && strcmp(rel,"NXT") != 0 )
{
printf("nxtae/unconf needs to be relative to NXT (%s/%s) %llu/%llu\n",base,rel,(long long)baseid,(long long)relid);
return(0);
}
}
if ( (prices= prices777_initpair(1,exchangestr,base,rel,0.,name,baseid,relid,0)) != 0 )
{
//printf("call addbundle after initpair\n");
prices777_addbundle(&valid,1,prices,0,0,0);
}
return(prices);
}
int32_t prices777_propagate(struct prices777 *prices)
{
int32_t i,n = 0;
for (i=0; i<prices->numdependents; i++)
{
n++;
if ( (*prices->dependents[i]) < 0xff )
(*prices->dependents[i])++;
if ( Debuglevel > 2 )
printf("numdependents.%d of %d %p %d\n",i,prices->numdependents,prices->dependents[i],*prices->dependents[i]);
}
return(n);
}
int32_t prices777_updated;
void prices777_basketsloop(void *ptr)
{
extern int32_t prices777_NXTBLOCK;
int32_t i,n; uint32_t updated; struct prices777 *prices;
while ( 1 )
{
for (i=n=0; i<BUNDLE.num; i++)
{
updated = (uint32_t)time(NULL);
if ( (prices= BUNDLE.ptrs[i]) != 0 && prices->disabled == 0 && prices->basketsize != 0 )
{
if ( prices->changed != 0 )
{
if ( Debuglevel > 2 )
printf("%s updating basket(%s) lastprice %.8f changed.%p %d\n",prices->exchange,prices->contract,prices->lastprice,&prices->changed,prices->changed);
prices->pollnxtblock = prices777_NXTBLOCK;
n++;
prices->lastupdate = updated;
if ( (prices->lastprice= prices777_basket(prices,MAX_DEPTH)) != 0. )
{
if ( prices->O.numbids > 0 || prices->O.numasks > 0 )
{
prices777_jsonstrs(prices,&prices->O);
prices777_updated += prices777_propagate(prices);
}
}
prices->changed = 0;
}
}
}
if ( n == 0 )
usleep(250000);
else usleep(10000);
}
}
void prices777_exchangeloop(void *ptr)
{
extern int32_t prices777_NXTBLOCK;
struct prices777 *prices; int32_t i,n,pollflag,isnxtae = 0; double updated = 0.; struct exchange_info *exchange = ptr;
if ( strcmp(exchange->name,"nxtae") == 0 || strcmp(exchange->name,"unconf") == 0 )
isnxtae = 1;
printf("POLL.(%s)\n",exchange->name);
while ( 1 )
{
for (i=n=0; i<BUNDLE.num; i++)
{
if ( (prices= BUNDLE.ptrs[i]) != 0 && prices->disabled == 0 && prices->basketsize == 0 && prices->exchangeid == exchange->exchangeid )
{
if ( prices->exchangeid == INSTANTDEX_EXCHANGEID && prices->dirty != 0 )
pollflag = 1;
else if ( isnxtae == 0 )
pollflag = milliseconds() > (exchange->lastupdate + exchange->pollgap*1000) && milliseconds() > (prices->lastupdate + 1000*IGUANA_EXCHANGEIDLE);
else if ( (strcmp(exchange->name,"unconf") == 0 && milliseconds() > prices->lastupdate + 5000) || prices->pollnxtblock < prices777_NXTBLOCK || milliseconds() > prices->lastupdate + 1000*IGUANA_EXCHANGEIDLE )
pollflag = 1;
else continue;
//printf("(%s) pollflag.%d %p\n",exchange->name,pollflag,exchange->issue.update);
if ( pollflag != 0 && exchange->issue.update != 0 )
{
portable_mutex_lock(&exchange->mutex);
prices->lastprice = (*exchange->issue.update)(prices,MAX_DEPTH);
portable_mutex_unlock(&exchange->mutex);
updated = exchange->lastupdate = milliseconds(), prices->lastupdate = milliseconds();
if ( prices->lastprice != 0. )
{
if ( Debuglevel > 2 && strcmp(exchange->name,"unconf") != 0 )
printf("%-8s %8s (%8s %8s) %llu %llu isnxtae.%d poll %u -> %u %.8f hbla %.8f %.8f\n",prices->exchange,prices->contract,prices->base,prices->rel,(long long)prices->baseid,(long long)prices->relid,isnxtae,prices->pollnxtblock,prices777_NXTBLOCK,prices->lastprice,prices->lastbid,prices->lastask);
prices777_propagate(prices);
}
prices->pollnxtblock = prices777_NXTBLOCK;
prices->dirty = 0;
n++;
}
/*if ( 0 && exchange->issue.trade != 0 && exchange->apikey[0] != 0 && exchange->exchangeid >= FIRST_EXTERNAL && time(NULL) > exchange->lastbalancetime+300 )
{
if ( (json= (*exchange->issue.balances)(exchange)) != 0 )
{
if ( exchange->balancejson != 0 )
free_json(exchange->balancejson);
exchange->balancejson = json;
}
exchange->lastbalancetime = (uint32_t)time(NULL);
}*/
}
}
if ( n == 0 )
sleep(3);
else sleep(1);
}
}
int32_t prices777_init(char *jsonstr,int32_t peggyflag)
{
static int32_t didinit;
char *btcdexchanges[] = { "poloniex", "bittrex" };//, "bter" };
char *btcusdexchanges[] = { "bityes", "bitfinex", "bitstamp", "okcoin", "coinbase", "btce", "lakebtc", "kraken" };
cJSON *json=0,*item,*exchanges; int32_t i,n; char *exchange,*base,*rel,*contract; struct exchange_info *exchangeptr=0; struct destbuf tmp;
if ( didinit != 0 )
return(0);
didinit = 1;
if ( (BUNDLE.ptrs[BUNDLE.num]= prices777_initpair(1,"unconf","BTC","NXT",0,"BTC/NXT",calc_nxt64bits("12659653638116877017"),NXT_ASSETID,0)) != 0 )
BUNDLE.num++;
if ( peggyflag != 0 )
{
if ( (BUNDLE.ptrs[BUNDLE.num]= prices777_initpair(1,"huobi","BTC","USD",0.,0,0,0,0)) != 0 )
BUNDLE.num++;
if ( (BUNDLE.ptrs[BUNDLE.num]= prices777_initpair(1,"btc38","CNY","NXT",0.,0,0,0,0)) != 0 )
BUNDLE.num++;
if ( (BUNDLE.ptrs[BUNDLE.num]= prices777_initpair(1,"okcoin","LTC","BTC",0.,0,0,0,0)) != 0 )
BUNDLE.num++;
if ( (BUNDLE.ptrs[BUNDLE.num]= prices777_initpair(1,"poloniex","LTC","BTC",0.,0,0,0,0)) != 0 )
BUNDLE.num++;
if ( (BUNDLE.ptrs[BUNDLE.num]= prices777_initpair(1,"poloniex","XMR","BTC",0.,0,0,0,0)) != 0 )
BUNDLE.num++;
if ( (BUNDLE.ptrs[BUNDLE.num]= prices777_initpair(1,"poloniex","BTS","BTC",0.,0,0,0,0)) != 0 )
BUNDLE.num++;
if ( (BUNDLE.ptrs[BUNDLE.num]= prices777_initpair(1,"poloniex","XCP","BTC",0.,0,0,0,0)) != 0 )
BUNDLE.num++;
for (i=0; i<sizeof(btcdexchanges)/sizeof(*btcdexchanges); i++)
if ( (BUNDLE.ptrs[BUNDLE.num]= prices777_initpair(1,btcusdexchanges[i],"BTC","USD",0.,0,0,0,0)) != 0 )
BUNDLE.num++;
for (i=0; i<sizeof(btcdexchanges)/sizeof(*btcdexchanges); i++)
if ( (BUNDLE.ptrs[BUNDLE.num]= prices777_initpair(1,btcdexchanges[i],"BTCD","BTC",0.,0,0,0,0)) != 0 )
BUNDLE.num++;
}
if ( (json= cJSON_Parse(jsonstr)) != 0 && (exchanges= jarray(&n,json,"prices")) != 0 )
{
printf("prices has %d items\n",n);
for (i=0; i<n; i++)
{
item = jitem(exchanges,i);
exchange = jstr(item,"exchange"), base = jstr(item,"base"), rel = jstr(item,"rel");
if ( (base == 0 || rel == 0) && (contract= jstr(item,"contract")) != 0 )
rel = 0, base = contract;
else contract = 0;
//printf("PRICES[%d] %p %p %p\n",i,exchange,base,rel);
if ( exchange != 0 && (strcmp(exchange,"bter") == 0 || strcmp(exchange,"exmo") == 0) )
continue;
if ( exchange != 0 && (exchangeptr= find_exchange(0,exchange)) != 0 )
{
exchangeptr->pollgap = get_API_int(cJSON_GetObjectItem(item,"pollgap"),IGUANA_EXCHANGEIDLE);
extract_cJSON_str(exchangeptr->apikey,sizeof(exchangeptr->apikey),item,"key");
if ( exchangeptr->apikey[0] == 0 )
extract_cJSON_str(exchangeptr->apikey,sizeof(exchangeptr->apikey),item,"apikey");
extract_cJSON_str(exchangeptr->userid,sizeof(exchangeptr->userid),item,"userid");
extract_cJSON_str(exchangeptr->apisecret,sizeof(exchangeptr->apisecret),item,"secret");
if ( exchangeptr->apisecret[0] == 0 )
extract_cJSON_str(exchangeptr->apisecret,sizeof(exchangeptr->apisecret),item,"apisecret");
if ( exchangeptr->commission == 0. )
exchangeptr->commission = jdouble(item,"commission");
printf("%p ADDEXCHANGE.(%s) [%s, %s, %s] commission %.3f%%\n",exchangeptr,exchange,exchangeptr->apikey,exchangeptr->userid,exchangeptr->apisecret,exchangeptr->commission * 100);
} else printf(" exchangeptr.%p for (%p)\n",exchangeptr,exchange);
if ( exchange != 0 && strcmp(exchange,"truefx") == 0 )
{
copy_cJSON(&tmp,jobj(item,"truefxuser")), safecopy(BUNDLE.truefxuser,tmp.buf,sizeof(BUNDLE.truefxuser));
copy_cJSON(&tmp,jobj(item,"truefxpass")), safecopy(BUNDLE.truefxpass,tmp.buf,sizeof(BUNDLE.truefxpass));;
printf("truefx.(%s %s)\n",BUNDLE.truefxuser,BUNDLE.truefxpass);
}
else if ( base != 0 && rel != 0 && base[0] != 0 && rel[0] != 0 && (BUNDLE.ptrs[BUNDLE.num]= prices777_initpair(1,exchange,base,rel,jdouble(item,"decay"),contract,stringbits(base),stringbits(rel),0)) != 0 )
{
if ( exchangeptr != 0 && (BUNDLE.ptrs[BUNDLE.num]->commission= jdouble(item,"commission")) == 0. )
BUNDLE.ptrs[BUNDLE.num]->commission = exchangeptr->commission;
printf("SET COMMISSION.%s %f for %s/%s\n",exchange,exchangeptr!=0?exchangeptr->commission:0,base,rel);
BUNDLE.num++;
}
}
} else printf("(%s) has no prices[]\n",jsonstr);
if ( json != 0 )
free_json(json);
for (i=0; i<MAX_EXCHANGES; i++)
{
exchangeptr = &Exchanges[i];
if ( (exchangeptr->refcount > 0 || strcmp(exchangeptr->name,"unconf") == 0) )//&& strcmp(exchangeptr->name,"pangea") != 0 && strcmp(exchangeptr->name,"jumblr") != 0 )
9 years ago
iguana_launch(0,"exchangeloop",(void *)prices777_exchangeloop,exchangeptr,IGUANA_EXCHANGETHREAD);
9 years ago
}
return(0);
}
double prices777_yahoo(char *metal)
{
// http://finance.yahoo.com/webservice/v1/symbols/allcurrencies/quote?format=json
// http://finance.yahoo.com/webservice/v1/symbols/XAU=X/quote?format=json
// http://finance.yahoo.com/webservice/v1/symbols/XAG=X/quote?format=json
// http://finance.yahoo.com/webservice/v1/symbols/XPT=X/quote?format=json
// http://finance.yahoo.com/webservice/v1/symbols/XPD=X/quote?format=json
char url[1024],*jsonstr; cJSON *json,*obj,*robj,*item,*field; double price = 0.;
sprintf(url,"http://finance.yahoo.com/webservice/v1/symbols/%s=X/quote?format=json",metal);
if ( (jsonstr= issue_curl(url)) != 0 )
{
//printf("(%s)\n",jsonstr);
if ( (json= cJSON_Parse(jsonstr)) != 0 )
{
if ( (obj= jobj(json,"list")) != 0 && (robj= jobj(obj,"resources")) != 0 && (item= jitem(robj,0)) != 0 )
{
if ( (robj= jobj(item,"resource")) != 0 && (field= jobj(robj,"fields")) != 0 && (price= jdouble(field,"price")) != 0 )
price = 1. / price;
}
free_json(json);
}
free(jsonstr);
}
if ( Debuglevel > 2 )
printf("(%s %f) ",metal,price);
return(price);
}
cJSON *url_json(char *url)
{
char *jsonstr; cJSON *json = 0;
if ( (jsonstr= issue_curl(url)) != 0 )
{
//printf("(%s) -> (%s)\n",url,jsonstr);
json = cJSON_Parse(jsonstr);
free(jsonstr);
}
return(json);
}
cJSON *url_json2(char *url)
{
char *jsonstr; cJSON *json = 0;
if ( (jsonstr= issue_curl(url)) != 0 )
{
//printf("(%s) -> (%s)\n",url,jsonstr);
json = cJSON_Parse(jsonstr);
free(jsonstr);
}
return(json);
}
many changes blockexplorer tab: needs to allow to input height, blockhash or txid. also please display images/BTC_blocks.jpg below the text as a w800 x h400 bitmap, which is active using the mouse api for coin management, below the active coins have a form that arbitrary json can be input with an add button to the right that will call &#34;addcoin&#34; API. this way I can test adding new coins dynamically. dont worry if it doesnt work, just as long as it submits the json to the C code. I am pretty sure I need to do some debugging of this peers management is not working for me at all. maybe it is due to bad internet. On initialization you need to read in the confs/BTCD_peers.txt from the native filesystem and save it into the chrome app filesystem. same thing for confs/BTCD_hdrs.txt. But this is only to be done if there isnt already such a file inside chrome. if there is, only do it upon a button invoked by the user. the reason is that the pexe is updating this file with the latest. Maybe it is nice to have an &#34;extract&#34; button that will copy out from the chrome storage into the native filesystem. There is also the manifest issue about localstorage vs chrome.localstorage. not sure what is needed to be done, but certainly a priority to get it so everything works as a chrome app. I know before it was making ramchain files inside the chrome filesystem, so it is probably things the GUI is doing. maybe in the settings tab, which has obsolete stuff that can be removed. anyway, the issue about files existing in the native filesystem -&gt; chrome and optionally extracting them is an issue for the confs files and .html template files used to autogenerate the port7778, maybe other files are affected. i think we need a way to have a list of hardcoded files that are just copied into chrome on startup if they dont exist already (or if possible copy over if the native version is bigger?) and buttons to extract them for debug tab: THREE_STRINGS(SuperNET,encryptjson,passphrase,permanentfile,anything); TWO_STRINGS(SuperNET,decryptjson,passphrase,permanentfile); at the top of page a way to put in passphrase and optional permanentfile along with arbitrary json. The standard form template has no easy way to describe to pass in everything as it is oriented to specific fields. but the encryptjson API saves all the fields, so the arbitrary json from the form needs to be combined at the same level as the &#34;agent&#34;, &#34;method&#34;, etc. I know, not the best, but internally it makes it easier. so {&#34;agent&#34;:&#34;SuperNET&#34;,&#34;method&#34;:&#34;encryptjson&#34;,&#34;passphrase&#34;:&#34;&lt;passphrase&gt;&#34;,&#34; permanentfile&#34;:&#34;&lt;filename&gt;&#34;,&#34;fromform&#34;:&#34;valuefromform&#34;,&#34;fromform2&#34;:&#34;valu efromform2&#34;,...rest of form at top level} then this will save it into a file with crazy number (it is a hash like txid) but given the same passphrase and filename, it will regenerate this hash so you dont actually have to store it, but it helps during debugging. for the filename, we must warn quite strongly to the user that if the file is ever lost or even changed in any way that the data will not be recoverable. also best to not allow the user to specify a file that does not exist. I think at this point chrome app version gets a bit tricky. we could simply push the native file into the chrome storage, but then an attacker who gets access to the computer could just get a list of these files and it really wont be much protection. So that means if a filename is specified, it needs to be copied into the chrome space, then immediately deleted... ok, this seems like not a good approach. let us make it so that the permanentfile option is not available from the chrome app, but only if the native version is running. that way we sidestep the issue of the pexe not having access to the specified file. Speaking of native vs pexe, on the startup page we should have a radio button that allows the user to select which the GUI will talk to. It should default based on a self test to the more likely value, but it is possible that the user wants to use the native version, even if the pexe is running. another thing to have on the startup page is a simple login: THREE_STRINGS(SuperNET,login,passphrase,permanentfile,handle); ZERO_ARGS(SuperNET,logout); ZERO_ARGS(SuperNET,activehandle); the handle is a human readable name that is associated with the passphrase/permanentfile. There can only be one active account (though it will be possible to associate different accounts with tradebots). use the activehandle API to find out who is logged in and the associated addresses and pubkeys The above is not yet tested so if it doesnt work, dont fret, just let me know. Once set the handle can be displayed in various places to let the user know which account is logged in. The standard 12 dictionary word passphrases should be used, but any string can be sent in as the password for Pangea: INT_AND_ARRAY(pangea,host,minplayers,params); ZERO_ARGS(pangea,lobby); HASH_AND_STRING(pangea,join,tablehash,handle); HASH_AND_INT(pangea,buyin,tablehash,numchips); HASH_ARG(pangea,start,tablehash); // by host only HASH_ARG(pangea,status,tablehash); HASH_ARG(pangea,call,tablehash); HASH_ARG(pangea,check,tablehash); HASH_AND_INT(pangea,raise,tablehash,numchips); HASH_AND_INT(pangea,bet,tablehash,numchips); HASH_ARG(pangea,fold,tablehash); HASH_AND_STRING(pangea,mode,tablehash,modestr); HASH_ARG(pangea,history,tablehash); HASH_AND_INT(pangea,handhistory,tablehash,hand); The first thing that is done is a &#34;host&#34; by any node. the &#34;params&#34; should be an arbitrary json (like encryptjson) as it needs to be at the top level and it has quite a few different parameters still subject to change. The lobby API will just display all the hosted tables. once a table exists, players can join and then buyin. the buyin is denominated in chips, each chip&#39;s value is determined by the host&#39;s initial parameters. once there are enough players joined with adequate buyin&#39;s verified, the host will be able to do a start. if done before it will (eventually) give an error. for now it will just proceed. The host and players that have joined a tablehash, need to do regular status calls to see if the game has started. Probably just once per 5 or even 10 seconds is fine before the start. Once the game starts (the status will have this info) then once per second polling is needed. Then when it is your turn (as indicated by status) you need to do one of the 5 actions (fold, call, check, raise, bet). do not worry if you dont understand what all these do, just allow the user to do any of these. I guess it is possible to submit it ahead of time. I will support internally remembering the most recent action done prior to it being your turn. once it is your turn and an action is sent to the table, it is too late to change. The last API calls are for getting handhistory where hand is 0 to N-1, being the numbering of the hands played at that table. if just history, all the history for all hands at the table is coming back, so it could be quite big. probably I will make it a summary, but for the GUI just display the returned values. the mode is to change some poker specific modes, so just allow there to be a string entered. do not worry about understanding the pokerness of the API, just the overall flow: host -&gt; creates, join/buyin -&gt; fills up player slots, start -&gt; starts the game status -&gt; to determine when the game starts (or if it is cancelled) and once started actions -&gt; game specific but basically just (button + arg) that is the user input results are via status for current game and history for past ones please try to do the above logic in a generic way so it can be reused for other games. The basic flow should be the same for almost all multiplayer turn based games and even for multiplayer realtime games For InstantDEX: on the apikeypair/userid there needs to be two modes. one for when there is no stored apikey and the current form is fine, just need to make it wider as most apikeys are quite long. Now once there is an apikey saved all that is needed is the passphrase to unlock it. So here is where the encrptjson/decryptjson is used. When saving the apikey for the first time, it can be: a) not saved -&gt; nothing extra to do b) saved without password -&gt; you can just save to a file and use it to load it back in. use confs dir confs/instantdex.exchange.api or something like that c) saved with password (optional filename for native) -&gt; probably best to save in the confs dir to indicate that there is an encrypted file for this, so just that and not the actual passphrase in the file with the above, when the exchange is selected, you can see if the confs file exists and if it has the plaintext, just populate the field, if not, then indicate that a passphrase is needed. if the user provides the passphrase, then decryptjson and populate the fields and autosubmit. A special case is to encrypt the apikeys with the passphrase used when logging in. This is only available if the checkbox to &#34;remember passphrase during session&#34; is set on the main iguana login screen. (i forgot to mention that checkbox!) So the login passphrase is stored in memory, then the GUI simply uses that + encryptjson for storing/decrypting. I would imagine that storing in the confs file that it is encrypted using &#34;handle&#34;&#39;s account login might be a good way to differentiate between this mode of password usage. OK, so we now have the insecure plaintext, the decent using handle&#39;s passphrase and paranoid different passphrase for each exchange (with additional permanentfile for native versions) &#34;SUPPORT&#34; -&gt; &#34;SUPPORTS&#34; just a typo and &#34;allpairs&#34; API is missing from the selection Might as well add a &#34;tradebots&#34; tab: THREE_STRINGS_AND_DOUBLE(tradebot,monitor,exchange,base,rel,commission); STRING_AND_DOUBLE(tradebot,monitorall,exchange,commission); THREE_STRINGS(tradebot,unmonitor,exchange,base,rel); THREE_STRINGS_AND_THREE_DOUBLES(tradebot,accumulate,exchange,base,rel,pr ice,volume,duration); THREE_STRINGS_AND_THREE_DOUBLES(tradebot,divest,exchange,base,rel,price, volume,duration); STRING_ARG(tradebot,activebots,exchange); TWO_STRINGS(tradebot,status,exchange,botid); TWO_STRINGS(tradebot,pause,exchange,botid); TWO_STRINGS(tradebot,stop,exchange,botid); TWO_STRINGS(tradebot,resume,exchange,botid); the above are API for exchange specific bots, most should be self-explanatory. bots are created via &#34;accumulate&#34; or &#34;divest&#34; API call. it returns botid. once created, you can do status, pause, stop, resume to a botid. and an activebots API call lists all the active bots for an exchange. duration is in seconds the &#34;monitor&#34; API starts background monitoring of a specific base/rel, &#34;unmonitor&#34; stops this. &#34;monitorall&#34; just does a monitor to the entire list of &#34;allpairs&#34; for that exchange. Keep in mind that doing a monitorall will not add load to an exchange as the request to each exchange is governed by pollgap, but if you have 3 things monitored, it will take 3*pollgap + time each one takes to execute. and if N are monitored it is N*pollgap + time of each, with the &#34;time of each&#34; possibly taking a very long time. And one final request for today: Bitmap tab. It should be an active bitmap using mouse api. either a dropdown to select the bitmap or a form entry. then the rest of the page (resize the bitmap to the page size) being the active bitmap. So on a small screen the bitmap is smaller x/y dimensions and larger on larger screens. plz make sure the proper dimensions are communicated to the pexe via API if it ever is changed. @vineet.bhargav86: I changed the &#34;passphrase&#34; fieldname to &#34;password&#34; for the encryptjson/decryptjson related API. The reason is that the password is like a wallet password and is only local, so it doesnt need to be as high entropy as passphrase. I also added a field to the login API as I realized that the 12 word &#34;passphrase&#34; is the payload and usually wont be sent in: FOUR_STRINGS(SuperNET,login,handle,password,permanentfile,passphrase); using &#34;abiglongpassword&#34; for the passphrase -&gt; {&#34;pubkey&#34;:&#34;6c469ba10b40b3eb9d1dba569d7f929d55a29d8f97cd5425907ef2f38f906 209&#34;,&#34;RS&#34;:&#34;NXT-KGV9-DXX8-TM86-DXR96&#34;,&#34;NXT&#34;:&#34;12834974574569896807&#34;,&#34;btcpu bkey&#34;:&#34;024e7641dc947b211bc30fe3339765258902794687b227121fc217284f9d8503c 8&#34;,&#34;rmd160&#34;:&#34;33453c24914db7b77069b7ea24df44f6be145938&#34;,&#34;BTC&#34;:&#34;15g6QK2dSd iW9ZTQEnnJxKrSph6uP7uU23&#34;,&#34;BTCD&#34;:&#34;RDxHUpuv3TX5DZpbhxmS3rBeaxZW1fvYvC&#34;,&#34;r esult&#34;:&#34;success&#34;,&#34;handle&#34;:&#34;test&#34;,&#34;tag&#34;:&#34;14805226009240621255&#34;} and if you use that to log into NXT, it gives the same address. The BTC and BTCD addresses are all derived from the same privkey so they are all interchangeable with the NXT address. The user can therefore select which coin&#39;s addressing they are most comfortable with I also added an &#34;allin&#34; action API for pangea. all the action API will autocalculate the number of chips if passed in 0 for numchips ***************** security issue ******** please dont use the GET URL method when dealing with passphrase!!! Those URL&#39;s tend to get logged and available in browser histories. so anything dealing with the actual passphrase needs to use the postCall form or POST
9 years ago
void PAX_btcprices(int32_t enddatenum,int32_t numdates)
9 years ago
{
int32_t i,n,year,month,day,seconds,datenum; char url[1024],date[64],*dstr,*str; uint32_t timestamp,utc32[MAX_SPLINES];
cJSON *coindesk,*quandl,*btcdhist,*bpi,*array,*item;
double btcddaily[MAX_SPLINES],cdaily[MAX_SPLINES],qdaily[MAX_SPLINES],ask,high,low,bid,close,vol,quotevol,open,price = 0.;
coindesk = url_json("http://api.coindesk.com/v1/bpi/historical/close.json");
sprintf(url,"https://poloniex.com/public?command=returnChartData&currencyPair=BTC_BTCD&start=%ld&end=9999999999&period=86400",(long)(time(NULL)-numdates*3600*24));
if ( (bpi= jobj(coindesk,"bpi")) != 0 )
{
datenum = enddatenum;
memset(utc32,0,sizeof(utc32));
memset(cdaily,0,sizeof(cdaily));
if ( datenum == 0 )
{
datenum = OS_conv_unixtime(&seconds,(uint32_t)time(NULL));
printf("got datenum.%d %d %d %d\n",datenum,seconds/3600,(seconds/60)%24,seconds%60);
}
for (i=0; i<numdates; i++)
{
expand_datenum(date,datenum);
if ( (price= jdouble(bpi,date)) != 0 )
{
utc32[numdates - 1 - i] = OS_conv_datenum(datenum,12,0,0);
cdaily[numdates - 1 - i] = price * .001;
//printf("(%s %u %f) ",date,utc32[numdates - 1 - i],price);
}
datenum = ecb_decrdate(&year,&month,&day,date,datenum);
}
prices777_genspline(&BUNDLE.splines[MAX_CURRENCIES],MAX_CURRENCIES,"coindesk",utc32,cdaily,numdates,cdaily);
} else printf("no bpi\n");
quandl = url_json("https://www.quandl.com/api/v1/datasets/BAVERAGE/USD.json?rows=64");
if ( (str= jstr(quandl,"updated_at")) != 0 && (datenum= conv_date(&seconds,str)) > 0 && (array= jarray(&n,quandl,"data")) != 0 )
{
printf("datenum.%d data.%d %d\n",datenum,n,cJSON_GetArraySize(array));
memset(utc32,0,sizeof(utc32)), memset(qdaily,0,sizeof(qdaily));
for (i=0; i<n&&i<MAX_SPLINES; i++)
{
// ["Date","24h Average","Ask","Bid","Last","Total Volume"]
// ["2015-07-25",289.27,288.84,288.68,288.87,44978.61]
item = jitem(array,i);
if ( Debuglevel > 2 )
printf("(%s) ",cJSON_Print(item));
if ( (dstr= jstr(jitem(item,0),0)) != 0 && (datenum= conv_date(&seconds,dstr)) > 0 )
{
price = jdouble(jitem(item,1),0), ask = jdouble(jitem(item,2),0), bid = jdouble(jitem(item,3),0);
close = jdouble(jitem(item,4),0), vol = jdouble(jitem(item,5),0);
if ( Debuglevel > 2 )
fprintf(stderr,"%d.[%d %f %f %f %f %f].%d ",i,datenum,price,ask,bid,close,vol,n);
utc32[numdates - 1 - i] = OS_conv_datenum(datenum,12,0,0), qdaily[numdates - 1 - i] = price * .001;
}
}
prices777_genspline(&BUNDLE.splines[MAX_CURRENCIES+1],MAX_CURRENCIES+1,"quandl",utc32,qdaily,n<MAX_SPLINES?n:MAX_SPLINES,qdaily);
}
btcdhist = url_json(url);
//{"date":1406160000,"high":0.01,"low":0.00125,"open":0.01,"close":0.001375,"volume":1.50179994,"quoteVolume":903.58818412,"weightedAverage":0.00166204},
if ( (array= jarray(&n,btcdhist,0)) != 0 )
{
memset(utc32,0,sizeof(utc32)), memset(btcddaily,0,sizeof(btcddaily));
//printf("GOT.(%s)\n",cJSON_Print(array));
for (i=0; i<n; i++)
{
item = jitem(array,i);
timestamp = juint(item,"date"), high = jdouble(item,"high"), low = jdouble(item,"low"), open = jdouble(item,"open");
close = jdouble(item,"close"), vol = jdouble(item,"volume"), quotevol = jdouble(item,"quoteVolume"), price = jdouble(item,"weightedAverage");
//printf("[%u %f %f %f %f %f %f %f]",timestamp,high,low,open,close,vol,quotevol,price);
if ( Debuglevel > 2 )
printf("[%u %d %f]",timestamp,OS_conv_unixtime(&seconds,timestamp),price);
utc32[i] = timestamp - 12*3600, btcddaily[i] = price * 100.;
}
if ( Debuglevel > 2 )
printf("poloniex.%d\n",n);
prices777_genspline(&BUNDLE.splines[MAX_CURRENCIES+2],MAX_CURRENCIES+2,"btcdhist",utc32,btcddaily,n<MAX_SPLINES?n:MAX_SPLINES,btcddaily);
}
// https://poloniex.com/public?command=returnChartData&currencyPair=BTC_BTCD&start=1405699200&end=9999999999&period=86400
}
many changes blockexplorer tab: needs to allow to input height, blockhash or txid. also please display images/BTC_blocks.jpg below the text as a w800 x h400 bitmap, which is active using the mouse api for coin management, below the active coins have a form that arbitrary json can be input with an add button to the right that will call &#34;addcoin&#34; API. this way I can test adding new coins dynamically. dont worry if it doesnt work, just as long as it submits the json to the C code. I am pretty sure I need to do some debugging of this peers management is not working for me at all. maybe it is due to bad internet. On initialization you need to read in the confs/BTCD_peers.txt from the native filesystem and save it into the chrome app filesystem. same thing for confs/BTCD_hdrs.txt. But this is only to be done if there isnt already such a file inside chrome. if there is, only do it upon a button invoked by the user. the reason is that the pexe is updating this file with the latest. Maybe it is nice to have an &#34;extract&#34; button that will copy out from the chrome storage into the native filesystem. There is also the manifest issue about localstorage vs chrome.localstorage. not sure what is needed to be done, but certainly a priority to get it so everything works as a chrome app. I know before it was making ramchain files inside the chrome filesystem, so it is probably things the GUI is doing. maybe in the settings tab, which has obsolete stuff that can be removed. anyway, the issue about files existing in the native filesystem -&gt; chrome and optionally extracting them is an issue for the confs files and .html template files used to autogenerate the port7778, maybe other files are affected. i think we need a way to have a list of hardcoded files that are just copied into chrome on startup if they dont exist already (or if possible copy over if the native version is bigger?) and buttons to extract them for debug tab: THREE_STRINGS(SuperNET,encryptjson,passphrase,permanentfile,anything); TWO_STRINGS(SuperNET,decryptjson,passphrase,permanentfile); at the top of page a way to put in passphrase and optional permanentfile along with arbitrary json. The standard form template has no easy way to describe to pass in everything as it is oriented to specific fields. but the encryptjson API saves all the fields, so the arbitrary json from the form needs to be combined at the same level as the &#34;agent&#34;, &#34;method&#34;, etc. I know, not the best, but internally it makes it easier. so {&#34;agent&#34;:&#34;SuperNET&#34;,&#34;method&#34;:&#34;encryptjson&#34;,&#34;passphrase&#34;:&#34;&lt;passphrase&gt;&#34;,&#34; permanentfile&#34;:&#34;&lt;filename&gt;&#34;,&#34;fromform&#34;:&#34;valuefromform&#34;,&#34;fromform2&#34;:&#34;valu efromform2&#34;,...rest of form at top level} then this will save it into a file with crazy number (it is a hash like txid) but given the same passphrase and filename, it will regenerate this hash so you dont actually have to store it, but it helps during debugging. for the filename, we must warn quite strongly to the user that if the file is ever lost or even changed in any way that the data will not be recoverable. also best to not allow the user to specify a file that does not exist. I think at this point chrome app version gets a bit tricky. we could simply push the native file into the chrome storage, but then an attacker who gets access to the computer could just get a list of these files and it really wont be much protection. So that means if a filename is specified, it needs to be copied into the chrome space, then immediately deleted... ok, this seems like not a good approach. let us make it so that the permanentfile option is not available from the chrome app, but only if the native version is running. that way we sidestep the issue of the pexe not having access to the specified file. Speaking of native vs pexe, on the startup page we should have a radio button that allows the user to select which the GUI will talk to. It should default based on a self test to the more likely value, but it is possible that the user wants to use the native version, even if the pexe is running. another thing to have on the startup page is a simple login: THREE_STRINGS(SuperNET,login,passphrase,permanentfile,handle); ZERO_ARGS(SuperNET,logout); ZERO_ARGS(SuperNET,activehandle); the handle is a human readable name that is associated with the passphrase/permanentfile. There can only be one active account (though it will be possible to associate different accounts with tradebots). use the activehandle API to find out who is logged in and the associated addresses and pubkeys The above is not yet tested so if it doesnt work, dont fret, just let me know. Once set the handle can be displayed in various places to let the user know which account is logged in. The standard 12 dictionary word passphrases should be used, but any string can be sent in as the password for Pangea: INT_AND_ARRAY(pangea,host,minplayers,params); ZERO_ARGS(pangea,lobby); HASH_AND_STRING(pangea,join,tablehash,handle); HASH_AND_INT(pangea,buyin,tablehash,numchips); HASH_ARG(pangea,start,tablehash); // by host only HASH_ARG(pangea,status,tablehash); HASH_ARG(pangea,call,tablehash); HASH_ARG(pangea,check,tablehash); HASH_AND_INT(pangea,raise,tablehash,numchips); HASH_AND_INT(pangea,bet,tablehash,numchips); HASH_ARG(pangea,fold,tablehash); HASH_AND_STRING(pangea,mode,tablehash,modestr); HASH_ARG(pangea,history,tablehash); HASH_AND_INT(pangea,handhistory,tablehash,hand); The first thing that is done is a &#34;host&#34; by any node. the &#34;params&#34; should be an arbitrary json (like encryptjson) as it needs to be at the top level and it has quite a few different parameters still subject to change. The lobby API will just display all the hosted tables. once a table exists, players can join and then buyin. the buyin is denominated in chips, each chip&#39;s value is determined by the host&#39;s initial parameters. once there are enough players joined with adequate buyin&#39;s verified, the host will be able to do a start. if done before it will (eventually) give an error. for now it will just proceed. The host and players that have joined a tablehash, need to do regular status calls to see if the game has started. Probably just once per 5 or even 10 seconds is fine before the start. Once the game starts (the status will have this info) then once per second polling is needed. Then when it is your turn (as indicated by status) you need to do one of the 5 actions (fold, call, check, raise, bet). do not worry if you dont understand what all these do, just allow the user to do any of these. I guess it is possible to submit it ahead of time. I will support internally remembering the most recent action done prior to it being your turn. once it is your turn and an action is sent to the table, it is too late to change. The last API calls are for getting handhistory where hand is 0 to N-1, being the numbering of the hands played at that table. if just history, all the history for all hands at the table is coming back, so it could be quite big. probably I will make it a summary, but for the GUI just display the returned values. the mode is to change some poker specific modes, so just allow there to be a string entered. do not worry about understanding the pokerness of the API, just the overall flow: host -&gt; creates, join/buyin -&gt; fills up player slots, start -&gt; starts the game status -&gt; to determine when the game starts (or if it is cancelled) and once started actions -&gt; game specific but basically just (button + arg) that is the user input results are via status for current game and history for past ones please try to do the above logic in a generic way so it can be reused for other games. The basic flow should be the same for almost all multiplayer turn based games and even for multiplayer realtime games For InstantDEX: on the apikeypair/userid there needs to be two modes. one for when there is no stored apikey and the current form is fine, just need to make it wider as most apikeys are quite long. Now once there is an apikey saved all that is needed is the passphrase to unlock it. So here is where the encrptjson/decryptjson is used. When saving the apikey for the first time, it can be: a) not saved -&gt; nothing extra to do b) saved without password -&gt; you can just save to a file and use it to load it back in. use confs dir confs/instantdex.exchange.api or something like that c) saved with password (optional filename for native) -&gt; probably best to save in the confs dir to indicate that there is an encrypted file for this, so just that and not the actual passphrase in the file with the above, when the exchange is selected, you can see if the confs file exists and if it has the plaintext, just populate the field, if not, then indicate that a passphrase is needed. if the user provides the passphrase, then decryptjson and populate the fields and autosubmit. A special case is to encrypt the apikeys with the passphrase used when logging in. This is only available if the checkbox to &#34;remember passphrase during session&#34; is set on the main iguana login screen. (i forgot to mention that checkbox!) So the login passphrase is stored in memory, then the GUI simply uses that + encryptjson for storing/decrypting. I would imagine that storing in the confs file that it is encrypted using &#34;handle&#34;&#39;s account login might be a good way to differentiate between this mode of password usage. OK, so we now have the insecure plaintext, the decent using handle&#39;s passphrase and paranoid different passphrase for each exchange (with additional permanentfile for native versions) &#34;SUPPORT&#34; -&gt; &#34;SUPPORTS&#34; just a typo and &#34;allpairs&#34; API is missing from the selection Might as well add a &#34;tradebots&#34; tab: THREE_STRINGS_AND_DOUBLE(tradebot,monitor,exchange,base,rel,commission); STRING_AND_DOUBLE(tradebot,monitorall,exchange,commission); THREE_STRINGS(tradebot,unmonitor,exchange,base,rel); THREE_STRINGS_AND_THREE_DOUBLES(tradebot,accumulate,exchange,base,rel,pr ice,volume,duration); THREE_STRINGS_AND_THREE_DOUBLES(tradebot,divest,exchange,base,rel,price, volume,duration); STRING_ARG(tradebot,activebots,exchange); TWO_STRINGS(tradebot,status,exchange,botid); TWO_STRINGS(tradebot,pause,exchange,botid); TWO_STRINGS(tradebot,stop,exchange,botid); TWO_STRINGS(tradebot,resume,exchange,botid); the above are API for exchange specific bots, most should be self-explanatory. bots are created via &#34;accumulate&#34; or &#34;divest&#34; API call. it returns botid. once created, you can do status, pause, stop, resume to a botid. and an activebots API call lists all the active bots for an exchange. duration is in seconds the &#34;monitor&#34; API starts background monitoring of a specific base/rel, &#34;unmonitor&#34; stops this. &#34;monitorall&#34; just does a monitor to the entire list of &#34;allpairs&#34; for that exchange. Keep in mind that doing a monitorall will not add load to an exchange as the request to each exchange is governed by pollgap, but if you have 3 things monitored, it will take 3*pollgap + time each one takes to execute. and if N are monitored it is N*pollgap + time of each, with the &#34;time of each&#34; possibly taking a very long time. And one final request for today: Bitmap tab. It should be an active bitmap using mouse api. either a dropdown to select the bitmap or a form entry. then the rest of the page (resize the bitmap to the page size) being the active bitmap. So on a small screen the bitmap is smaller x/y dimensions and larger on larger screens. plz make sure the proper dimensions are communicated to the pexe via API if it ever is changed. @vineet.bhargav86: I changed the &#34;passphrase&#34; fieldname to &#34;password&#34; for the encryptjson/decryptjson related API. The reason is that the password is like a wallet password and is only local, so it doesnt need to be as high entropy as passphrase. I also added a field to the login API as I realized that the 12 word &#34;passphrase&#34; is the payload and usually wont be sent in: FOUR_STRINGS(SuperNET,login,handle,password,permanentfile,passphrase); using &#34;abiglongpassword&#34; for the passphrase -&gt; {&#34;pubkey&#34;:&#34;6c469ba10b40b3eb9d1dba569d7f929d55a29d8f97cd5425907ef2f38f906 209&#34;,&#34;RS&#34;:&#34;NXT-KGV9-DXX8-TM86-DXR96&#34;,&#34;NXT&#34;:&#34;12834974574569896807&#34;,&#34;btcpu bkey&#34;:&#34;024e7641dc947b211bc30fe3339765258902794687b227121fc217284f9d8503c 8&#34;,&#34;rmd160&#34;:&#34;33453c24914db7b77069b7ea24df44f6be145938&#34;,&#34;BTC&#34;:&#34;15g6QK2dSd iW9ZTQEnnJxKrSph6uP7uU23&#34;,&#34;BTCD&#34;:&#34;RDxHUpuv3TX5DZpbhxmS3rBeaxZW1fvYvC&#34;,&#34;r esult&#34;:&#34;success&#34;,&#34;handle&#34;:&#34;test&#34;,&#34;tag&#34;:&#34;14805226009240621255&#34;} and if you use that to log into NXT, it gives the same address. The BTC and BTCD addresses are all derived from the same privkey so they are all interchangeable with the NXT address. The user can therefore select which coin&#39;s addressing they are most comfortable with I also added an &#34;allin&#34; action API for pangea. all the action API will autocalculate the number of chips if passed in 0 for numchips ***************** security issue ******** please dont use the GET URL method when dealing with passphrase!!! Those URL&#39;s tend to get logged and available in browser histories. so anything dealing with the actual passphrase needs to use the postCall form or POST
9 years ago
int32_t PAX_calcmatrix(double matrix[32][32])
9 years ago
{
int32_t basenum,relnum,nonz,vnum,iter,numbase,numerrs = 0; double sum,vsum,price,price2,basevals[32],errsum=0;
memset(basevals,0,sizeof(basevals));
for (iter=0; iter<2; iter++)
{
numbase = 32;
for (basenum=0; basenum<numbase; basenum++)
{
for (vsum=sum=vnum=nonz=relnum=0; relnum<numbase; relnum++)
{
if ( basenum != relnum )
{
if ( (price= matrix[basenum][relnum]) != 0. )
{
price /= (MINDENOMS[relnum] * .001);
price *= (MINDENOMS[basenum] * .001);
if ( iter == 0 )
sum += (price), nonz++;//, printf("%.8f ",price);
else sum += fabs((price) - (basevals[basenum] / basevals[relnum])), nonz++;
}
if ( (price2= matrix[relnum][basenum]) != 0. )
{
price2 *= (MINDENOMS[relnum] * .001);
price2 /= (MINDENOMS[basenum] * .001);
if ( iter == 0 )
vsum += (price2), vnum++;
else vsum += fabs(price2 - (basevals[relnum] / basevals[basenum])), vnum++;
}
//if ( iter == 0 && 1/price2 > price )
// printf("base.%d rel.%d price2 %f vs %f\n",basenum,relnum,1/price2,price);
}
}
if ( iter == 0 )
sum += 1., vsum += 1.;
if ( nonz != 0 )
sum /= nonz;
if ( vnum != 0 )
vsum /= vnum;
if ( iter == 0 )
basevals[basenum] = (sum + 1./vsum) / 2.;
else errsum += (sum + vsum)/2, numerrs++;//, printf("(%.8f %.8f) ",sum,vsum);
//printf("date.%d (%.8f/%d %.8f/%d).%02d -> %.8f\n",i,sum,nonz,vsum,vnum,basenum,basevals[basenum]);
}
if ( iter == 0 )
{
for (sum=relnum=0; relnum<numbase; relnum++)
sum += (basevals[relnum]);//, printf("%.8f ",(basevals[relnum]));
//printf("date.%d sums %.8f and vsums iter.%d\n",i,sum/7,iter);
sum /= (numbase - 1);
for (relnum=0; relnum<numbase; relnum++)
basevals[relnum] /= sum;//, printf("%.8f ",basevals[relnum]);
//printf("date.%d sums %.8f and vsums iter.%d\n",i,sum,iter);
}
else
{
for (basenum=0; basenum<numbase; basenum++)
matrix[basenum][basenum] = basevals[basenum];
}
}
if ( numerrs != 0 )
errsum /= numerrs;
return(errsum);
}
many changes blockexplorer tab: needs to allow to input height, blockhash or txid. also please display images/BTC_blocks.jpg below the text as a w800 x h400 bitmap, which is active using the mouse api for coin management, below the active coins have a form that arbitrary json can be input with an add button to the right that will call &#34;addcoin&#34; API. this way I can test adding new coins dynamically. dont worry if it doesnt work, just as long as it submits the json to the C code. I am pretty sure I need to do some debugging of this peers management is not working for me at all. maybe it is due to bad internet. On initialization you need to read in the confs/BTCD_peers.txt from the native filesystem and save it into the chrome app filesystem. same thing for confs/BTCD_hdrs.txt. But this is only to be done if there isnt already such a file inside chrome. if there is, only do it upon a button invoked by the user. the reason is that the pexe is updating this file with the latest. Maybe it is nice to have an &#34;extract&#34; button that will copy out from the chrome storage into the native filesystem. There is also the manifest issue about localstorage vs chrome.localstorage. not sure what is needed to be done, but certainly a priority to get it so everything works as a chrome app. I know before it was making ramchain files inside the chrome filesystem, so it is probably things the GUI is doing. maybe in the settings tab, which has obsolete stuff that can be removed. anyway, the issue about files existing in the native filesystem -&gt; chrome and optionally extracting them is an issue for the confs files and .html template files used to autogenerate the port7778, maybe other files are affected. i think we need a way to have a list of hardcoded files that are just copied into chrome on startup if they dont exist already (or if possible copy over if the native version is bigger?) and buttons to extract them for debug tab: THREE_STRINGS(SuperNET,encryptjson,passphrase,permanentfile,anything); TWO_STRINGS(SuperNET,decryptjson,passphrase,permanentfile); at the top of page a way to put in passphrase and optional permanentfile along with arbitrary json. The standard form template has no easy way to describe to pass in everything as it is oriented to specific fields. but the encryptjson API saves all the fields, so the arbitrary json from the form needs to be combined at the same level as the &#34;agent&#34;, &#34;method&#34;, etc. I know, not the best, but internally it makes it easier. so {&#34;agent&#34;:&#34;SuperNET&#34;,&#34;method&#34;:&#34;encryptjson&#34;,&#34;passphrase&#34;:&#34;&lt;passphrase&gt;&#34;,&#34; permanentfile&#34;:&#34;&lt;filename&gt;&#34;,&#34;fromform&#34;:&#34;valuefromform&#34;,&#34;fromform2&#34;:&#34;valu efromform2&#34;,...rest of form at top level} then this will save it into a file with crazy number (it is a hash like txid) but given the same passphrase and filename, it will regenerate this hash so you dont actually have to store it, but it helps during debugging. for the filename, we must warn quite strongly to the user that if the file is ever lost or even changed in any way that the data will not be recoverable. also best to not allow the user to specify a file that does not exist. I think at this point chrome app version gets a bit tricky. we could simply push the native file into the chrome storage, but then an attacker who gets access to the computer could just get a list of these files and it really wont be much protection. So that means if a filename is specified, it needs to be copied into the chrome space, then immediately deleted... ok, this seems like not a good approach. let us make it so that the permanentfile option is not available from the chrome app, but only if the native version is running. that way we sidestep the issue of the pexe not having access to the specified file. Speaking of native vs pexe, on the startup page we should have a radio button that allows the user to select which the GUI will talk to. It should default based on a self test to the more likely value, but it is possible that the user wants to use the native version, even if the pexe is running. another thing to have on the startup page is a simple login: THREE_STRINGS(SuperNET,login,passphrase,permanentfile,handle); ZERO_ARGS(SuperNET,logout); ZERO_ARGS(SuperNET,activehandle); the handle is a human readable name that is associated with the passphrase/permanentfile. There can only be one active account (though it will be possible to associate different accounts with tradebots). use the activehandle API to find out who is logged in and the associated addresses and pubkeys The above is not yet tested so if it doesnt work, dont fret, just let me know. Once set the handle can be displayed in various places to let the user know which account is logged in. The standard 12 dictionary word passphrases should be used, but any string can be sent in as the password for Pangea: INT_AND_ARRAY(pangea,host,minplayers,params); ZERO_ARGS(pangea,lobby); HASH_AND_STRING(pangea,join,tablehash,handle); HASH_AND_INT(pangea,buyin,tablehash,numchips); HASH_ARG(pangea,start,tablehash); // by host only HASH_ARG(pangea,status,tablehash); HASH_ARG(pangea,call,tablehash); HASH_ARG(pangea,check,tablehash); HASH_AND_INT(pangea,raise,tablehash,numchips); HASH_AND_INT(pangea,bet,tablehash,numchips); HASH_ARG(pangea,fold,tablehash); HASH_AND_STRING(pangea,mode,tablehash,modestr); HASH_ARG(pangea,history,tablehash); HASH_AND_INT(pangea,handhistory,tablehash,hand); The first thing that is done is a &#34;host&#34; by any node. the &#34;params&#34; should be an arbitrary json (like encryptjson) as it needs to be at the top level and it has quite a few different parameters still subject to change. The lobby API will just display all the hosted tables. once a table exists, players can join and then buyin. the buyin is denominated in chips, each chip&#39;s value is determined by the host&#39;s initial parameters. once there are enough players joined with adequate buyin&#39;s verified, the host will be able to do a start. if done before it will (eventually) give an error. for now it will just proceed. The host and players that have joined a tablehash, need to do regular status calls to see if the game has started. Probably just once per 5 or even 10 seconds is fine before the start. Once the game starts (the status will have this info) then once per second polling is needed. Then when it is your turn (as indicated by status) you need to do one of the 5 actions (fold, call, check, raise, bet). do not worry if you dont understand what all these do, just allow the user to do any of these. I guess it is possible to submit it ahead of time. I will support internally remembering the most recent action done prior to it being your turn. once it is your turn and an action is sent to the table, it is too late to change. The last API calls are for getting handhistory where hand is 0 to N-1, being the numbering of the hands played at that table. if just history, all the history for all hands at the table is coming back, so it could be quite big. probably I will make it a summary, but for the GUI just display the returned values. the mode is to change some poker specific modes, so just allow there to be a string entered. do not worry about understanding the pokerness of the API, just the overall flow: host -&gt; creates, join/buyin -&gt; fills up player slots, start -&gt; starts the game status -&gt; to determine when the game starts (or if it is cancelled) and once started actions -&gt; game specific but basically just (button + arg) that is the user input results are via status for current game and history for past ones please try to do the above logic in a generic way so it can be reused for other games. The basic flow should be the same for almost all multiplayer turn based games and even for multiplayer realtime games For InstantDEX: on the apikeypair/userid there needs to be two modes. one for when there is no stored apikey and the current form is fine, just need to make it wider as most apikeys are quite long. Now once there is an apikey saved all that is needed is the passphrase to unlock it. So here is where the encrptjson/decryptjson is used. When saving the apikey for the first time, it can be: a) not saved -&gt; nothing extra to do b) saved without password -&gt; you can just save to a file and use it to load it back in. use confs dir confs/instantdex.exchange.api or something like that c) saved with password (optional filename for native) -&gt; probably best to save in the confs dir to indicate that there is an encrypted file for this, so just that and not the actual passphrase in the file with the above, when the exchange is selected, you can see if the confs file exists and if it has the plaintext, just populate the field, if not, then indicate that a passphrase is needed. if the user provides the passphrase, then decryptjson and populate the fields and autosubmit. A special case is to encrypt the apikeys with the passphrase used when logging in. This is only available if the checkbox to &#34;remember passphrase during session&#34; is set on the main iguana login screen. (i forgot to mention that checkbox!) So the login passphrase is stored in memory, then the GUI simply uses that + encryptjson for storing/decrypting. I would imagine that storing in the confs file that it is encrypted using &#34;handle&#34;&#39;s account login might be a good way to differentiate between this mode of password usage. OK, so we now have the insecure plaintext, the decent using handle&#39;s passphrase and paranoid different passphrase for each exchange (with additional permanentfile for native versions) &#34;SUPPORT&#34; -&gt; &#34;SUPPORTS&#34; just a typo and &#34;allpairs&#34; API is missing from the selection Might as well add a &#34;tradebots&#34; tab: THREE_STRINGS_AND_DOUBLE(tradebot,monitor,exchange,base,rel,commission); STRING_AND_DOUBLE(tradebot,monitorall,exchange,commission); THREE_STRINGS(tradebot,unmonitor,exchange,base,rel); THREE_STRINGS_AND_THREE_DOUBLES(tradebot,accumulate,exchange,base,rel,pr ice,volume,duration); THREE_STRINGS_AND_THREE_DOUBLES(tradebot,divest,exchange,base,rel,price, volume,duration); STRING_ARG(tradebot,activebots,exchange); TWO_STRINGS(tradebot,status,exchange,botid); TWO_STRINGS(tradebot,pause,exchange,botid); TWO_STRINGS(tradebot,stop,exchange,botid); TWO_STRINGS(tradebot,resume,exchange,botid); the above are API for exchange specific bots, most should be self-explanatory. bots are created via &#34;accumulate&#34; or &#34;divest&#34; API call. it returns botid. once created, you can do status, pause, stop, resume to a botid. and an activebots API call lists all the active bots for an exchange. duration is in seconds the &#34;monitor&#34; API starts background monitoring of a specific base/rel, &#34;unmonitor&#34; stops this. &#34;monitorall&#34; just does a monitor to the entire list of &#34;allpairs&#34; for that exchange. Keep in mind that doing a monitorall will not add load to an exchange as the request to each exchange is governed by pollgap, but if you have 3 things monitored, it will take 3*pollgap + time each one takes to execute. and if N are monitored it is N*pollgap + time of each, with the &#34;time of each&#34; possibly taking a very long time. And one final request for today: Bitmap tab. It should be an active bitmap using mouse api. either a dropdown to select the bitmap or a form entry. then the rest of the page (resize the bitmap to the page size) being the active bitmap. So on a small screen the bitmap is smaller x/y dimensions and larger on larger screens. plz make sure the proper dimensions are communicated to the pexe via API if it ever is changed. @vineet.bhargav86: I changed the &#34;passphrase&#34; fieldname to &#34;password&#34; for the encryptjson/decryptjson related API. The reason is that the password is like a wallet password and is only local, so it doesnt need to be as high entropy as passphrase. I also added a field to the login API as I realized that the 12 word &#34;passphrase&#34; is the payload and usually wont be sent in: FOUR_STRINGS(SuperNET,login,handle,password,permanentfile,passphrase); using &#34;abiglongpassword&#34; for the passphrase -&gt; {&#34;pubkey&#34;:&#34;6c469ba10b40b3eb9d1dba569d7f929d55a29d8f97cd5425907ef2f38f906 209&#34;,&#34;RS&#34;:&#34;NXT-KGV9-DXX8-TM86-DXR96&#34;,&#34;NXT&#34;:&#34;12834974574569896807&#34;,&#34;btcpu bkey&#34;:&#34;024e7641dc947b211bc30fe3339765258902794687b227121fc217284f9d8503c 8&#34;,&#34;rmd160&#34;:&#34;33453c24914db7b77069b7ea24df44f6be145938&#34;,&#34;BTC&#34;:&#34;15g6QK2dSd iW9ZTQEnnJxKrSph6uP7uU23&#34;,&#34;BTCD&#34;:&#34;RDxHUpuv3TX5DZpbhxmS3rBeaxZW1fvYvC&#34;,&#34;r esult&#34;:&#34;success&#34;,&#34;handle&#34;:&#34;test&#34;,&#34;tag&#34;:&#34;14805226009240621255&#34;} and if you use that to log into NXT, it gives the same address. The BTC and BTCD addresses are all derived from the same privkey so they are all interchangeable with the NXT address. The user can therefore select which coin&#39;s addressing they are most comfortable with I also added an &#34;allin&#34; action API for pangea. all the action API will autocalculate the number of chips if passed in 0 for numchips ***************** security issue ******** please dont use the GET URL method when dealing with passphrase!!! Those URL&#39;s tend to get logged and available in browser histories. so anything dealing with the actual passphrase needs to use the postCall form or POST
9 years ago
int32_t prices777_ecbparse(char *date,double *prices,char *url,int32_t basenum)
{
char *jsonstr,*relstr,*basestr; int32_t count=0,i,relnum; cJSON *json,*ratesobj,*item; struct destbuf tmp;
if ( (jsonstr= issue_curl(url)) != 0 )
{
//if ( Debuglevel > 2 )
printf("(%s)\n",jsonstr);
if ( (json= cJSON_Parse(jsonstr)) != 0 )
{
copy_cJSON(&tmp,jobj(json,"date")), safecopy(date,tmp.buf,64);
if ( (basestr= jstr(json,"base")) != 0 && strcmp(basestr,CURRENCIES[basenum]) == 0 && (ratesobj= jobj(json,"rates")) != 0 && (item= ratesobj->child) != 0 )
{
while ( item != 0 )
{
if ( (relstr= get_cJSON_fieldname(item)) != 0 && (relnum= prices777_basenum(relstr)) >= 0 )
{
i = basenum*MAX_CURRENCIES + relnum;
prices[i] = item->valuedouble;
//if ( basenum == JPYNUM )
// prices[i] *= 100.;
// else if ( relnum == JPYNUM )
// prices[i] /= 100.;
count++;
//if ( Debuglevel > 2 )
printf("(%02d:%02d %f) ",basenum,relnum,prices[i]);
} else printf("cant find.(%s)\n",relstr);//, getchar();
item = item->next;
}
}
free_json(json);
}
free(jsonstr);
}
return(count);
}
int32_t prices777_ecb(char *date,double *prices,int32_t year,int32_t month,int32_t day)
{
// http://api.fixer.io/latest?base=CNH
// http://api.fixer.io/2000-01-03?base=USD
// "USD", "EUR", "JPY", "GBP", "AUD", "CAD", "CHF", "NZD"
char baseurl[512],tmpdate[64],url[512],checkdate[16]; int32_t basenum,count,i,iter,nonz;
checkdate[0] = 0;
if ( year == 0 )
strcpy(baseurl,"http://api.fixer.io/latest?base=");
else
{
sprintf(checkdate,"%d-%02d-%02d",year,month,day);
sprintf(baseurl,"http://api.fixer.io/%s?base=",checkdate);
}
count = 0;
for (iter=0; iter<2; iter++)
{
for (basenum=0; basenum<sizeof(CURRENCIES)/sizeof(*CURRENCIES); basenum++)
{
if ( strcmp(CURRENCIES[basenum],"XAU") == 0 )
break;
if ( iter == 0 )
{
sprintf(url,"%s%s",baseurl,CURRENCIES[basenum]);
count += prices777_ecbparse(basenum == 0 ? date : tmpdate,prices,url,basenum);
if ( (basenum != 0 && strcmp(tmpdate,date) != 0) || (checkdate[0] != 0 && strcmp(checkdate,date) != 0) )
{
printf("date mismatch (%s) != (%s) or checkdate.(%s)\n",tmpdate,date,checkdate);
return(-1);
}
}
else
{
for (nonz=i=0; i<sizeof(CURRENCIES)/sizeof(*CURRENCIES); i++)
{
if ( strcmp(CURRENCIES[i],"XAU") == 0 )
break;
if ( prices[MAX_CURRENCIES*basenum + i] != 0. )
nonz++;
//if ( Debuglevel > 2 )
printf("%8.5f ",prices[MAX_CURRENCIES*basenum + i]);
}
//if ( Debuglevel > 2 )
printf("%s.%d %d\n",CURRENCIES[basenum],basenum,nonz);
}
}
}
return(count);
}
9 years ago
int32_t ecb_matrix(double matrix[32][32],char *date)
{
FILE *fp=0; int32_t n=0,datenum,year=0,seconds,month=0,day=0,loaded = 0; char fname[64],_date[64];
if ( date == 0 )
date = _date, memset(_date,0,sizeof(_date));
sprintf(fname,"ECB/%s",date), iguana_compatible_path(fname);
if ( date[0] != 0 && (fp= fopen(fname,"rb")) != 0 )
{
if ( fread(matrix,1,sizeof(matrix[0][0])*32*32,fp) == sizeof(matrix[0][0])*32*32 )
loaded = 1;
else printf("fread error\n");
fclose(fp);
} else printf("ecb_matrix.(%s) load error fp.%p\n",fname,fp);
if ( loaded == 0 )
{
datenum = conv_date(&seconds,date);
year = datenum / 10000, month = (datenum / 100) % 100, day = (datenum % 100);
if ( (n= prices777_ecb(date,&matrix[0][0],year,month,day)) > 0 )
{
sprintf(fname,"ECB/%s",date), iguana_compatible_path(fname);
if ( (fp= fopen(fname,"wb")) != 0 )
{
if ( fwrite(matrix,1,sizeof(matrix[0][0])*32*32,fp) == sizeof(matrix[0][0])*32*32 )
loaded = 1;
fclose(fp);
}
} else printf("peggy_matrix error loading %d.%d.%d\n",year,month,day);
}
if ( loaded == 0 && n == 0 )
{
printf("peggy_matrix couldnt process loaded.%d n.%d\n",loaded,n);
return(-1);
}
//"2000-01-03"
if ( (datenum= conv_date(&seconds,date)) < 0 )
return(-1);
printf("loaded.(%s) nonz.%d (%d %d %d) datenum.%d\n",date,n,year,month,day,datenum);
return(datenum);
}
void price777_update(double *btcusdp,double *btcdbtcp)
{
int32_t i,n,seconds,datenum; uint32_t timestamp; char url[1024],*dstr,*str;
double btcddaily=0.,btcusd=0.,ask,high,low,bid,close,vol,quotevol,open,price = 0.;
//cJSON *btcdtrades,*btcdtrades2,*,*bitcoincharts,;
cJSON *quandl,*btcdhist,*array,*item,*bitcoinave,*blockchaininfo,*coindesk=0;
//btcdtrades = url_json("https://poloniex.com/public?command=returnTradeHistory&currencyPair=BTC_BTCD");
//btcdtrades2 = url_json("https://bittrex.com/api/v1.1/public/getmarkethistory?market=BTC-BTCD&count=50");
bitcoinave = url_json("https://api.bitcoinaverage.com/ticker/USD/");
//bitcoincharts = url_json("http://api.bitcoincharts.com/v1/weighted_prices.json");
blockchaininfo = url_json("https://blockchain.info/ticker");
coindesk = url_json("http://api.coindesk.com/v1/bpi/historical/close.json");
sprintf(url,"https://poloniex.com/public?command=returnChartData&currencyPair=BTC_BTCD&start=%ld&end=9999999999&period=86400",(long)(time(NULL)-2*3600*24));
quandl = url_json("https://www.quandl.com/api/v1/datasets/BAVERAGE/USD.json?rows=1");
if ( quandl != 0 && (str= jstr(quandl,"updated_at")) != 0 && (datenum= conv_date(&seconds,str)) > 0 && (array= jarray(&n,quandl,"data")) != 0 )
{
//printf("datenum.%d data.%d %d\n",datenum,n,cJSON_GetArraySize(array));
for (i=0; i<1; i++)
{
// ["Date","24h Average","Ask","Bid","Last","Total Volume"]
// ["2015-07-25",289.27,288.84,288.68,288.87,44978.61]
item = jitem(array,i);
if ( (dstr= jstr(jitem(item,0),0)) != 0 && (datenum= conv_date(&seconds,dstr)) > 0 )
{
btcusd = price = jdouble(jitem(item,1),0), ask = jdouble(jitem(item,2),0), bid = jdouble(jitem(item,3),0);
close = jdouble(jitem(item,4),0), vol = jdouble(jitem(item,5),0);
//fprintf(stderr,"%d.[%d %f %f %f %f %f].%d ",i,datenum,price,ask,bid,close,vol,n);
}
}
}
price = 0.;
for (i=n=0; i<BUNDLE.num; i++)
{
if ( strcmp(BUNDLE.ptrs[i]->lbase,"btcd") == 0 && strcmp(BUNDLE.ptrs[i]->lrel,"btc") == 0 && BUNDLE.ptrs[i]->lastprice != 0. )
{
price += BUNDLE.ptrs[i]->lastprice;
n++;
}
}
if ( n != 0 )
{
price /= n;
*btcdbtcp = price;
//printf("set BTCD price %f\n",price);
BUNDLE.btcdbtc = price;
}
else
{
btcdhist = url_json(url);
//{"date":1406160000,"high":0.01,"low":0.00125,"open":0.01,"close":0.001375,"volume":1.50179994,"quoteVolume":903.58818412,"weightedAverage":0.00166204},
if ( btcdhist != 0 && (array= jarray(&n,btcdhist,0)) != 0 )
{
//printf("GOT.(%s)\n",cJSON_Print(array));
for (i=0; i<1; i++)
{
item = jitem(array,i);
timestamp = juint(item,"date"), high = jdouble(item,"high"), low = jdouble(item,"low"), open = jdouble(item,"open");
close = jdouble(item,"close"), vol = jdouble(item,"volume"), quotevol = jdouble(item,"quoteVolume"), price = jdouble(item,"weightedAverage");
//printf("[%u %f %f %f %f %f %f %f]",timestamp,high,low,open,close,vol,quotevol,price);
//printf("[%u %d %f]",timestamp,OS_conv_unixtime(&seconds,timestamp),price);
btcddaily = price;
if ( btcddaily != 0 )
BUNDLE.btcdbtc = *btcdbtcp = btcddaily;
}
//printf("poloniex.%d\n",n);
}
if ( btcdhist != 0 )
free_json(btcdhist);
}
// https://blockchain.info/ticker
/*
{
"USD" : {"15m" : 288.22, "last" : 288.22, "buy" : 288.54, "sell" : 288.57, "symbol" : "$"},
"ISK" : {"15m" : 38765.88, "last" : 38765.88, "buy" : 38808.92, "sell" : 38812.95, "symbol" : "kr"},
"HKD" : {"15m" : 2234, "last" : 2234, "buy" : 2236.48, "sell" : 2236.71, "symbol" : "$"},
"TWD" : {"15m" : 9034.19, "last" : 9034.19, "buy" : 9044.22, "sell" : 9045.16, "symbol" : "NT$"},
"CHF" : {"15m" : 276.39, "last" : 276.39, "buy" : 276.69, "sell" : 276.72, "symbol" : "CHF"},
"EUR" : {"15m" : 262.46, "last" : 262.46, "buy" : 262.75, "sell" : 262.78, "symbol" : ""},
"DKK" : {"15m" : 1958.92, "last" : 1958.92, "buy" : 1961.1, "sell" : 1961.3, "symbol" : "kr"},
"CLP" : {"15m" : 189160.6, "last" : 189160.6, "buy" : 189370.62, "sell" : 189390.31, "symbol" : "$"},
"CAD" : {"15m" : 375.45, "last" : 375.45, "buy" : 375.87, "sell" : 375.91, "symbol" : "$"},
"CNY" : {"15m" : 1783.67, "last" : 1783.67, "buy" : 1785.65, "sell" : 1785.83, "symbol" : "¥"},
"THB" : {"15m" : 10046.98, "last" : 10046.98, "buy" : 10058.14, "sell" : 10059.18, "symbol" : "฿"},
"AUD" : {"15m" : 394.77, "last" : 394.77, "buy" : 395.2, "sell" : 395.25, "symbol" : "$"},
"SGD" : {"15m" : 395.08, "last" : 395.08, "buy" : 395.52, "sell" : 395.56, "symbol" : "$"},
"KRW" : {"15m" : 335991.51, "last" : 335991.51, "buy" : 336364.55, "sell" : 336399.52, "symbol" : ""},
"JPY" : {"15m" : 35711.99, "last" : 35711.99, "buy" : 35751.64, "sell" : 35755.35, "symbol" : "¥"},
"PLN" : {"15m" : 1082.74, "last" : 1082.74, "buy" : 1083.94, "sell" : 1084.06, "symbol" : ""},
"GBP" : {"15m" : 185.84, "last" : 185.84, "buy" : 186.04, "sell" : 186.06, "symbol" : "£"},
"SEK" : {"15m" : 2471.02, "last" : 2471.02, "buy" : 2473.76, "sell" : 2474.02, "symbol" : "kr"},
"NZD" : {"15m" : 436.89, "last" : 436.89, "buy" : 437.37, "sell" : 437.42, "symbol" : "$"},
"BRL" : {"15m" : 944.91, "last" : 944.91, "buy" : 945.95, "sell" : 946.05, "symbol" : "R$"},
"RUB" : {"15m" : 16695.05, "last" : 16695.05, "buy" : 16713.58, "sell" : 16715.32, "symbol" : "RUB"}
}*/
/*{
"24h_avg": 281.22,
"ask": 280.12,
"bid": 279.33,
"last": 279.58,
"timestamp": "Sun, 02 Aug 2015 09:36:34 -0000",
"total_vol": 39625.8
}*/
if ( bitcoinave != 0 )
{
if ( (price= jdouble(bitcoinave,"24h_avg")) > SMALLVAL )
{
//printf("bitcoinave %f %f\n",btcusd,price);
dxblend(&btcusd,price,0.5);
}
free_json(bitcoinave);
}
if ( quandl != 0 )
free_json(quandl);
if ( coindesk != 0 )
free_json(coindesk);
if ( blockchaininfo != 0 )
{
if ( (item= jobj(blockchaininfo,"USD")) != 0 && item != 0 && (price= jdouble(item,"15m")) > SMALLVAL )
{
//printf("blockchaininfo %f %f\n",btcusd,price);
dxblend(&btcusd,price,0.5);
}
free_json(blockchaininfo);
}
if ( btcusd != 0 )
BUNDLE.btcusd = *btcusdp = btcusd;
// https://poloniex.com/public?command=returnChartData&currencyPair=BTC_BTCD&start=1405699200&end=9999999999&period=86400
// https://poloniex.com/public?command=returnTradeHistory&currencyPair=BTC_BTCD
//https://bittrex.com/api/v1.1/public/getmarkethistory?market=BTC-BTCD&count=50
/*{"success":true,"message":"","result":[{"Id":8551089,"TimeStamp":"2015-07-25T16:00:41.597","Quantity":59.60917089,"Price":0.00642371,"Total":0.38291202,"FillType":"FILL","OrderType":"BUY"},{"Id":8551088,"TimeStamp":"2015-07-25T16:00:41.597","Quantity":7.00000000,"Price":0.00639680,"Total":0.04477760,"FillType":"PARTIAL_FILL","OrderType":"BUY"},{"Id":8551087,"TimeStamp":"2015-07-25T16:00:41.597","Quantity":6.51000000,"Price":0.00639679,"Total":0.04164310,"FillType":"PARTIAL_FILL","OrderType":"BUY"},{"Id":8551086,"TimeStamp":"2015-07-25T16:00:41.597","Quantity":6.00000000,"Price":0.00633300,"Total":0.03799800,"FillType":"PARTIAL_FILL","OrderType":"BUY"},{"Id":8551085,"TimeStamp":"2015-07-25T16:00:41.593","Quantity":4.76833955,"Price":0.00623300,"Total":0.02972106,"FillType":"PARTIAL_FILL","OrderType":"BUY"},{"Id":8551084,"TimeStamp":"2015-07-25T16:00:41.593","Quantity":5.00000000,"Price":0.00620860,"Total":0.03104300,"FillType":"PARTIAL_FILL","OrderType":"BUY"},{"Id":8551083,"TimeStamp":"2015-07-25T16:00:41.593","Quantity":4.91803279,"Price":0.00620134,"Total":0.03049839,"FillType":"PARTIAL_FILL","OrderType":"BUY"},{"Id":8551082,"TimeStamp":"2015-07-25T16:00:41.593","Quantity":4.45166432,"Price":0.00619316,"Total":0.02756986,"FillType":"PARTIAL_FILL","OrderType":"BUY"},{"Id":8551081,"TimeStamp":"2015-07-25T16:00:41.59","Quantity":2.00000000,"Price":0.00619315,"Total":0.01238630,"FillType":"PARTIAL_FILL","OrderType":"BUY"},{"Id":8547525,"TimeStamp":"2015-07-25T06:20:43.69","Quantity":1.23166045,"Price":0.00623300,"Total":0.00767693,"FillType":"FILL","OrderType":"BUY"},{"Id":8547524,"TimeStamp":"2015-07-25T06:20:43.69","Quantity":5.00000000,"Price":0.00613300,"Total":0.03066500,"FillType":"PARTIAL_FILL","OrderType":"BUY"},{"Id":8547523,"TimeStamp":"2015-07-25T06:20:43.687","Quantity":10.00000000,"Price":0.00609990,"Total":0.06099900,"FillType":"PARTIAL_FILL","OrderType":"BUY"},{"Id":8547522,"TimeStamp":"2015-07-25T06:20:43.687","Quantity":0.12326502,"Price":0.00609989,"Total":0.00075190,"FillType":"PARTIAL_FILL","OrderType":"BUY"},{"Id":8547521,"TimeStamp":"2015-07-25T06:20:43.687","Quantity":3.29000000,"Price":0.00609989,"Total":0.02006863,"FillType":"PARTIAL_FILL","OrderType":"BUY"},{"Id":8547520,"TimeStamp":"2015-07-25T06:20:43.687","Quantity":5.00000000,"Price":0.00604400,"Total":0.03022000,"FillType":"PARTIAL_FILL","OrderType":"BUY"},{"Id":8547519,"TimeStamp":"2015-07-25T06:20:43.683","Quantity":12.80164947,"Price":0.00603915,"Total":0.07731108,"FillType":"PARTIAL_FILL","OrderType":"BUY"},{"Id":8547518,"TimeStamp":"2015-07-25T06:20:43.683","Quantity":10.00000000,"Price":0.00602715,"Total":0.06027150,"FillType":"PARTIAL_FILL","OrderType":"BUY"},{"Id":8547517,"TimeStamp":"2015-07-25T06:20:43.683","Quantity":4.29037397,"Price":0.00600000,"Total":0.02574224,"FillType":"PARTIAL_FILL","OrderType":"BUY"},{"Id":8547516,"TimeStamp":"2015-07-25T06:20:43.683","Quantity":77.55994092,"Price":0.00598921,"Total":0.46452277,"FillType":"PARTIAL_FILL","OrderType":"BUY"},{"Id":8547515,"TimeStamp":"2015-07-25T06:20:43.68","Quantity":0.08645064,"Price":0.00598492,"Total":0.00051740,"FillType":"PARTIAL_FILL","OrderType":"BUY"}]}
*/
// https://api.bitcoinaverage.com/ticker/global/all
/* {
"AED": {
"ask": 1063.28,
"bid": 1062.1,
"last": 1062.29,
"timestamp": "Sat, 25 Jul 2015 17:13:14 -0000",
"volume_btc": 0.0,
"volume_percent": 0.0
},*/
// http://api.bitcoincharts.com/v1/weighted_prices.json
// {"USD": {"7d": "279.79", "30d": "276.05", "24h": "288.55"}, "IDR": {"7d": "3750799.88", "30d": "3636926.02", "24h": "3860769.92"}, "ILS": {"7d": "1033.34", "30d": "1031.58", "24h": "1092.36"}, "GBP": {"7d": "179.51", "30d": "175.30", "24h": "185.74"}, "DKK": {"30d": "1758.61"}, "CAD": {"7d": "364.04", "30d": "351.27", "24h": "376.12"}, "MXN": {"30d": "4369.33"}, "XRP": {"7d": "35491.70", "30d": "29257.39", "24h": "36979.02"}, "SEK": {"7d": "2484.50", "30d": "2270.94"}, "SGD": {"7d": "381.93", "30d": "373.69", "24h": "393.94"}, "HKD": {"7d": "2167.99", "30d": "2115.77", "24h": "2232.12"}, "AUD": {"7d": "379.42", "30d": "365.85", "24h": "394.93"}, "CHF": {"30d": "250.61"}, "timestamp": 1437844509, "CNY": {"7d": "1724.99", "30d": "1702.32", "24h": "1779.48"}, "LTC": {"7d": "67.46", "30d": "51.97", "24h": "61.61"}, "NZD": {"7d": "425.01", "30d": "409.33", "24h": "437.86"}, "THB": {"30d": "8632.82"}, "EUR": {"7d": "257.32", "30d": "249.88", "24h": "263.42"}, "ARS": {"30d": "3271.98"}, "NOK": {"30d": "2227.54"}, "RUB": {"7d": "16032.32", "30d": "15600.38", "24h": "16443.39"}, "INR": {"30d": "16601.17"}, "JPY": {"7d": "34685.73", "30d": "33617.77", "24h": "35652.79"}, "CZK": {"30d": "6442.13"}, "BRL": {"7d": "946.76", "30d": "900.77", "24h": "964.09"}, "NMC": {"7d": "454.06", "30d": "370.39", "24h": "436.71"}, "PLN": {"7d": "1041.81", "30d": "1024.96", "24h": "1072.49"}, "ZAR": {"30d": "3805.55"}}
}
double blend_price(double *volp,double wtA,cJSON *jsonA,double wtB,cJSON *jsonB)
{
//A.{"ticker":{"base":"BTS","target":"CNY","price":"0.02958291","volume":"3128008.39295500","change":"0.00019513","markets":[{"market":"BTC38","price":"0.02960000","volume":3051650.682955},{"market":"Bter","price":"0.02890000","volume":76357.71}]},"timestamp":1438490881,"success":true,"error":""}
// B.{"id":"bts\/cny","price":"0.02940000","price_before_24h":"0.02990000","volume_first":"3048457.6857147217","volume_second":"90629.45859575272","volume_btc":"52.74","best_market":"btc38","latest_trade":"2015-08-02 03:57:38","coin1":"BitShares","coin2":"CNY","markets":[{"market":"btc38","price":"0.02940000","volume":"3048457.6857147217","volume_btc":"52.738317962865"},{"market":"bter","price":"0.04350000","volume":"0","volume_btc":"0"}]}
double priceA,priceB,priceB24,price,volA,volB; cJSON *obj;
priceA = priceB = priceB24= price = volA = volB = 0.;
if ( jsonA != 0 && (obj= jobj(jsonA,"ticker")) != 0 )
{
priceA = jdouble(obj,"price");
volA = jdouble(obj,"volume");
}
if ( jsonB != 0 )
{
priceB = jdouble(jsonB,"price");
priceB24 = jdouble(jsonB,"price_before_24h");
volB = jdouble(jsonB,"volume_first");
}
//printf("priceA %f volA %f, priceB %f %f volB %f\n",priceA,volA,priceB,priceB24,volB);
if ( priceB > SMALLVAL && priceB24 > SMALLVAL )
priceB = (priceB * .1) + (priceB24 * .9);
else if ( priceB < SMALLVAL )
priceB = priceB24;
if ( priceA*volA < SMALLVAL )
price = priceB;
else if ( priceB*volB < SMALLVAL )
price = priceA;
else price = (wtA * priceA) + (wtB * priceB);
*volp = (volA + volB);
return(price);
}
void _crypto_update(double cryptovols[2][8][2],struct prices777_data *dp,int32_t selector,int32_t peggyflag)
{
char *cryptonatorA = "https://www.cryptonator.com/api/full/%s-%s"; //unity-btc
char *cryptocoinchartsB = "http://api.cryptocoincharts.info/tradingPair/%s_%s"; //bts_btc
char *cryptostrs[9] = { "btc", "nxt", "unity", "eth", "ltc", "xmr", "bts", "xcp", "etc" };
int32_t iter,i,j; double btcusd,btcdbtc,cnyusd,prices[8][2],volumes[8][2];
char base[16],rel[16],url[512],*str; cJSON *jsonA,*jsonB;
if ( peggyflag != 0 )
{
cnyusd = BUNDLE.cnyusd;
btcusd = BUNDLE.btcusd;
btcdbtc = BUNDLE.btcdbtc;
//printf("update with btcusd %f btcd %f cnyusd %f cnybtc %f\n",btcusd,btcdbtc,cnyusd,cnyusd/btcusd);
if ( btcusd < SMALLVAL || btcdbtc < SMALLVAL )
{
price777_update(&btcusd,&btcdbtc);
printf("price777_update with btcusd %f btcd %f\n",btcusd,btcdbtc);
}
memset(prices,0,sizeof(prices));
memset(volumes,0,sizeof(volumes));
for (j=0; j<sizeof(cryptostrs)/sizeof(*cryptostrs); j++)
{
str = cryptostrs[j];
if ( strcmp(str,"etc") == 0 )
{
if ( prices[3][0] > SMALLVAL )
break;
i = 3;
} else i = j;
for (iter=0; iter<1; iter++)
{
if ( i == 0 && iter == 0 )
strcpy(base,"btcd"), strcpy(rel,"btc");
else strcpy(base,str), strcpy(rel,iter==0?"btc":"cny");
//if ( selector == 0 )
{
sprintf(url,cryptonatorA,base,rel);
jsonA = url_json(url);
}
//else
{
sprintf(url,cryptocoinchartsB,base,rel);
jsonB = url_json(url);
}
prices[i][iter] = blend_price(&volumes[i][iter],0.4,jsonA,0.6,jsonB);
if ( iter == 1 )
{
if ( btcusd > SMALLVAL )
{
prices[i][iter] *= cnyusd / btcusd;
volumes[i][iter] *= cnyusd / btcusd;
} else prices[i][iter] = volumes[i][iter] = 0.;
}
cryptovols[0][i][iter] = _pairaved(cryptovols[0][i][iter],prices[i][iter]);
cryptovols[1][i][iter] = _pairaved(cryptovols[1][i][iter],volumes[i][iter]);
if ( Debuglevel > 2 )
printf("(%f %f).%d:%d ",cryptovols[0][i][iter],cryptovols[1][i][iter],i,iter);
//if ( cnyusd < SMALLVAL || btcusd < SMALLVAL )
// break;
}
}
}
}
void crypto_update(int32_t peggyflag)
{
_crypto_update(BUNDLE.cryptovols,&BUNDLE.data,1,peggyflag);
while ( 1 )
{
_crypto_update(BUNDLE.cryptovols,&BUNDLE.data,1,peggyflag);
sleep(100);
}
}
void prices777_RTupdate(double cryptovols[2][8][2],double RTmetals[4],double *RTprices,struct prices777_data *dp)
{
char *cryptostrs[8] = { "btc", "nxt", "unity", "eth", "ltc", "xmr", "bts", "xcp" };
int32_t iter,i,c,baserel,basenum,relnum; double cnyusd,btcusd,btcdbtc,bid,ask,price,vol,prices[8][2],volumes[8][2];
char base[16],rel[16];
price777_update(&btcusd,&btcdbtc);
memset(prices,0,sizeof(prices));
memset(volumes,0,sizeof(volumes));
for (i=0; i<sizeof(cryptostrs)/sizeof(*cryptostrs); i++)
for (iter=0; iter<2; iter++)
prices[i][iter] = cryptovols[0][i][iter], volumes[i][iter] = cryptovols[1][i][iter];
if ( prices[0][0] > SMALLVAL )
dxblend(&btcdbtc,prices[0][0],.9);
dxblend(&dp->btcdbtc,btcdbtc,.995);
if ( BUNDLE.btcdbtc < SMALLVAL )
BUNDLE.btcdbtc = dp->btcdbtc;
if ( (cnyusd= BUNDLE.cnyusd) > SMALLVAL )
{
if ( prices[0][1] > SMALLVAL )
{
//printf("cnyusd %f, btccny %f -> btcusd %f %f\n",cnyusd,prices[0][1],prices[0][1]*cnyusd,btcusd);
btcusd = prices[0][1] * cnyusd;
if ( dp->btcusd < SMALLVAL )
dp->btcusd = btcusd;
else dxblend(&dp->btcusd,btcusd,.995);
if ( BUNDLE.btcusd < SMALLVAL )
BUNDLE.btcusd = dp->btcusd;
if ( BUNDLE.data.btcusd < SMALLVAL )
BUNDLE.data.btcusd = dp->btcusd;
printf("cnyusd %f, btccny %f -> btcusd %f %f -> %f %f %f\n",cnyusd,prices[0][1],prices[0][1]*cnyusd,btcusd,dp->btcusd,BUNDLE.btcusd,BUNDLE.data.btcusd);
}
}
for (i=1; i<sizeof(cryptostrs)/sizeof(*cryptostrs); i++)
{
if ( (vol= volumes[i][0]+volumes[i][1]) > SMALLVAL )
{
price = ((prices[i][0] * volumes[i][0]) + (prices[i][1] * volumes[i][1])) / vol;
if ( Debuglevel > 2 )
printf("%s %f v%f + %f v%f -> %f %f\n",cryptostrs[i],prices[i][0],volumes[i][0],prices[i][1],volumes[i][1],price,dp->cryptos[i]);
dxblend(&dp->cryptos[i],price,.995);
}
}
btcusd = BUNDLE.btcusd;
btcdbtc = BUNDLE.btcdbtc;
if ( Debuglevel > 2 )
printf(" update with btcusd %f btcd %f\n",btcusd,btcdbtc);
if ( btcusd < SMALLVAL || btcdbtc < SMALLVAL )
{
price777_update(&btcusd,&btcdbtc);
if ( Debuglevel > 2 )
printf(" price777_update with btcusd %f btcd %f\n",btcusd,btcdbtc);
} else BUNDLE.btcusd = btcusd, BUNDLE.btcdbtc = btcdbtc;
for (c=0; c<sizeof(CONTRACTS)/sizeof(*CONTRACTS); c++)
{
for (iter=0; iter<3; iter++)
{
switch ( iter )
{
case 0: bid = dp->tbids[c], ask = dp->tasks[c]; break;
case 1: bid = dp->fbids[c], ask = dp->fasks[c]; break;
case 2: bid = dp->ibids[c], ask = dp->iasks[c]; break;
}
if ( (price= _pairaved(bid,ask)) > SMALLVAL )
{
if ( Debuglevel > 2 )
printf("%.6f ",price);
dxblend(&RTprices[c],price,.995);
if ( 0 && (baserel= prices777_ispair(base,rel,CONTRACTS[c])) >= 0 )
{
basenum = (baserel >> 8) & 0xff, relnum = baserel & 0xff;
if ( basenum < 32 && relnum < 32 )
{
//printf("%s.%d %f <- %f\n",CONTRACTS[c],c,RTmatrix[basenum][relnum],RTprices[c]);
//dxblend(&RTmatrix[basenum][relnum],RTprices[c],.999);
}
}
if ( strcmp(CONTRACTS[c],"XAUUSD") == 0 )
dxblend(&RTmetals[0],price,.995);
}
}
}
for (i=0; i<sizeof(Yahoo_metals)/sizeof(*Yahoo_metals); i++)
if ( BUNDLE.data.metals[i] != 0 )
dxblend(&RTmetals[i],BUNDLE.data.metals[i],.995);
}
int32_t prices777_getmatrix(double *basevals,double *btcusdp,double *btcdbtcp,double Hmatrix[32][32],double *RTprices,char *contracts[],int32_t num,uint32_t timestamp)
{
int32_t i,j,c; char name[16]; double btcusd,btcdbtc;
memcpy(Hmatrix,BUNDLE.data.ecbmatrix,sizeof(BUNDLE.data.ecbmatrix));
prices777_calcmatrix(Hmatrix);
/*for (i=0; i<32; i++)
{
for (j=0; j<32; j++)
printf("%.6f ",Hmatrix[i][j]);
printf("%s\n",CURRENCIES[i]);
}*/
btcusd = BUNDLE.btcusd;
btcdbtc = BUNDLE.btcdbtc;
if ( btcusd > SMALLVAL )
dxblend(btcusdp,btcusd,.9);
if ( btcdbtc > SMALLVAL )
dxblend(btcdbtcp,btcdbtc,.9);
// char *cryptostrs[8] = { "btc", "nxt", "unity", "eth", "ltc", "xmr", "bts", "xcp" };
// "BTCUSD", "NXTBTC", "SuperNET", "ETHBTC", "LTCBTC", "XMRBTC", "BTSBTC", "XCPBTC", // BTC priced
for (i=0; i<num; i++)
{
if ( contracts[i] == 0 )
continue;
if ( i == num-1 && strcmp(contracts[i],"BTCUSD") == 0 )
{
RTprices[i] = *btcusdp;
continue;
}
else if ( i == num-2 && strcmp(contracts[i],"BTCCNY") == 0 )
{
continue;
}
else if ( i == num-3 && strcmp(contracts[i],"BTCRUB") == 0 )
{
continue;
}
else if ( i == num-4 && strcmp(contracts[i],"XAUUSD") == 0 )
{
continue;
}
if ( strcmp(contracts[i],"NXTBTC") == 0 )
RTprices[i] = BUNDLE.data.cryptos[1];
else if ( strcmp(contracts[i],"SuperNET") == 0 )
RTprices[i] = BUNDLE.data.cryptos[2];
else if ( strcmp(contracts[i],"ETHBTC") == 0 )
RTprices[i] = BUNDLE.data.cryptos[3];
else if ( strcmp(contracts[i],"LTCBTC") == 0 )
RTprices[i] = BUNDLE.data.cryptos[4];
else if ( strcmp(contracts[i],"XMRBTC") == 0 )
RTprices[i] = BUNDLE.data.cryptos[5];
else if ( strcmp(contracts[i],"BTSBTC") == 0 )
RTprices[i] = BUNDLE.data.cryptos[6];
else if ( strcmp(contracts[i],"XCPBTC") == 0 )
RTprices[i] = BUNDLE.data.cryptos[7];
else if ( i < 32 )
{
basevals[i] = Hmatrix[i][i];
if ( Debuglevel > 2 )
printf("(%s %f).%d ",CURRENCIES[i],basevals[i],i);
}
else if ( (c= prices777_contractnum(contracts[i],0)) >= 0 )
{
RTprices[i] = BUNDLE.data.RTprices[c];
//if ( is_decimalstr(contracts[i]+strlen(contracts[i])-2) != 0 )
// cprices[i] *= .0001;
}
else
{
for (j=0; j<sizeof(Yahoo_metals)/sizeof(*Yahoo_metals); j++)
{
sprintf(name,"%sUSD",Yahoo_metals[j]);
if ( contracts[i] != 0 && strcmp(name,contracts[i]) == 0 )
{
RTprices[i] = BUNDLE.data.RTmetals[j];
break;
}
}
}
if ( Debuglevel > 2 )
printf("(%f %f) i.%d num.%d %s %f\n",*btcusdp,*btcdbtcp,i,num,contracts[i],RTprices[i]);
//printf("RT.(%s %f) ",contracts[i],RTprices[i]);
}
return(BUNDLE.data.ecbdatenum);
}
int32_t prices_idle(int32_t peggyflag,int32_t idlegap)
{
static double lastupdate,lastdayupdate; static int32_t didinit; static portable_mutex_t mutex;
int32_t i,datenum; struct prices777_data *dp = &BUNDLE.tmp;
*dp = BUNDLE.data;
if ( didinit == 0 )
{
portable_mutex_init(&mutex);
prices777_init(BUNDLE.jsonstr,peggyflag);
didinit = 1;
if ( peggyflag != 0 )
{
int32_t opreturns_init(uint32_t blocknum,uint32_t blocktimestamp,char *path);
opreturns_init(0,(uint32_t)time(NULL),"peggy");
}
}
if ( peggyflag != 0 && milliseconds() > lastupdate + (1000*idlegap) )
{
lastupdate = milliseconds();
if ( milliseconds() > lastdayupdate + 60000*60 )
{
lastdayupdate = milliseconds();
if ( (datenum= ecb_matrix(dp->ecbmatrix,dp->edate)) > 0 )
{
dp->ecbdatenum = datenum;
dp->ecbyear = dp->ecbdatenum / 10000, dp->ecbmonth = (dp->ecbdatenum / 100) % 100, dp->ecbday = (dp->ecbdatenum % 100);
expand_datenum(dp->edate,datenum);
memcpy(dp->RTmatrix,dp->ecbmatrix,sizeof(dp->RTmatrix));
}
}
for (i=0; i<sizeof(Yahoo_metals)/sizeof(*Yahoo_metals); i++)
BUNDLE.data.metals[i] = prices777_yahoo(Yahoo_metals[i]);
BUNDLE.truefxidnum = prices777_truefx(dp->tmillistamps,dp->tbids,dp->tasks,dp->topens,dp->thighs,dp->tlows,BUNDLE.truefxuser,BUNDLE.truefxpass,(uint32_t)BUNDLE.truefxidnum);
prices777_fxcm(dp->flhlogmatrix,dp->flogmatrix,dp->fbids,dp->fasks,dp->fhighs,dp->flows);
prices777_instaforex(dp->ilogmatrix,dp->itimestamps,dp->ibids,dp->iasks);
double btcdbtc,btcusd;
price777_update(&btcusd,&btcdbtc);
if ( btcusd > SMALLVAL )
dxblend(&dp->btcusd,btcusd,0.99);
if ( btcdbtc > SMALLVAL )
dxblend(&dp->btcdbtc,btcdbtc,0.99);
if ( BUNDLE.data.btcusd == 0 )
BUNDLE.data.btcusd = dp->btcusd;
if ( BUNDLE.data.btcdbtc == 0 )
BUNDLE.data.btcdbtc = dp->btcdbtc;
if ( dp->ecbmatrix[USD][USD] > SMALLVAL && dp->ecbmatrix[CNY][CNY] > SMALLVAL )
BUNDLE.cnyusd = (dp->ecbmatrix[CNY][CNY] / dp->ecbmatrix[USD][USD]);
portable_mutex_lock(&mutex);
BUNDLE.data = *dp;
portable_mutex_unlock(&mutex);
//kv777_write(BUNDLE.kv,"data",5,&BUNDLE.data,sizeof(BUNDLE.data));
prices777_RTupdate(BUNDLE.cryptovols,BUNDLE.data.RTmetals,BUNDLE.data.RTprices,&BUNDLE.data);
//printf("update finished\n");
void peggy();
peggy();
didinit = 1;
}
return(0);
}
void prices777_sim(uint32_t now,int32_t numiters)
{
double btca,btcb,btcd,btc,btcdusd,basevals[MAX_CURRENCIES],btcdprices[MAX_CURRENCIES+1];
int32_t i,j,datenum,seconds; uint32_t timestamp,starttime = (uint32_t)time(NULL);
for (i=0; i<numiters; i++)
{
timestamp = now - (rand() % (3600*24*64));
btca = 1000. * prices777_splineval(&BUNDLE.splines[MAX_CURRENCIES+0],timestamp,0);
btcb = 1000. * prices777_splineval(&BUNDLE.splines[MAX_CURRENCIES+1],timestamp,0);
btc = _pairaved(btca,btcb);
btcd = .01 * prices777_splineval(&BUNDLE.splines[MAX_CURRENCIES+2],timestamp,0);
btcdusd = (btc * btcd);
datenum = OS_conv_unixtime(&seconds,timestamp);
for (j=0; j<MAX_CURRENCIES; j++)
{
basevals[j] = prices777_splineval(&BUNDLE.splines[j],timestamp,0);
btcdprices[j] = basevals[j] / (btcdusd * basevals[USD]);
}
if ( (i % 100000) == 0 )
{
printf("%d:%02d:%02d %.8f %.8f -> USD %.8f (EURUSD %.8f %.8f) ",datenum,seconds/3600,(seconds%3600)/60,btc,btcd,btcdusd,btcdprices[EUR]/btcdprices[USD],basevals[EUR]/basevals[USD]);
for (j=0; j<MAX_CURRENCIES; j++)
printf("%.8f ",btcdprices[j]);
printf("\n");
}
}
printf("sim took %ld seconds\n",(long)(time(NULL) - starttime));
}
void prices777_getlist(char *retbuf)
{
int32_t i,j; struct prices777 *prices; char pair[16],*jsonstr; cJSON *json,*array,*item;
json = cJSON_CreateObject();
array = cJSON_CreateArray();
for (i=0; i<sizeof(CURRENCIES)/sizeof(*CURRENCIES); i++)
cJSON_AddItemToArray(array,cJSON_CreateString(CURRENCIES[i]));
cJSON_AddItemToObject(json,"currency",array);
array = cJSON_CreateArray();
for (i=0; i<32; i++)
for (j=0; j<32; j++)
{
if ( i != j )
{
sprintf(pair,"%s%s",CURRENCIES[i],CURRENCIES[j]);
cJSON_AddItemToArray(array,cJSON_CreateString(pair));
}
}
cJSON_AddItemToObject(json,"pairs",array);
array = cJSON_CreateArray();
for (i=0; i<sizeof(CONTRACTS)/sizeof(*CONTRACTS); i++)
cJSON_AddItemToArray(array,cJSON_CreateString(CONTRACTS[i]));
cJSON_AddItemToObject(json,"contract",array);
array = cJSON_CreateArray();
for (i=0; i<BUNDLE.num; i++)
{
if ( (prices= BUNDLE.ptrs[i]) != 0 )
{
item = cJSON_CreateObject();
cJSON_AddItemToObject(item,prices->exchange,cJSON_CreateString(prices->contract));
cJSON_AddItemToObject(item,"base",cJSON_CreateString(prices->base));
if ( prices->rel[0] != 0 )
cJSON_AddItemToObject(item,"rel",cJSON_CreateString(prices->rel));
//printf("(%s) (%s) (%s)\n",prices->contract,prices->base,prices->rel);
cJSON_AddItemToArray(array,item);
}
}
cJSON_AddItemToObject(json,"result",cJSON_CreateString("success"));
cJSON_AddItemToObject(json,"list",array);
jsonstr = cJSON_Print(json), _stripwhite(jsonstr,' '), free_json(json);
strcpy(retbuf,jsonstr), free(jsonstr);
printf("list -> (%s)\n",retbuf);
}