From 64094392ef8232216908605be98191f57e5e62b7 Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 29 Jan 2016 01:03:24 -0300 Subject: [PATCH] exchanges API --- InstantDEX/exchanges/coinbase.c | 2 +- crypto777/OS_portable.h | 2 + crypto777/bitcoind_RPC.c | 1 - iguana/BTCD_hdrs.txt | 1772 --------- iguana/BTCD_peers.txt | 49 - iguana/BTC_hdrs.txt | 195 - iguana/BTC_peers.txt | 137 - iguana/InstantDEX/InstantDEX.c | 582 +++ iguana/InstantDEX/InstantDEX_quote.h | 223 ++ iguana/InstantDEX/exchange_trades.h | 1407 +++++++ iguana/InstantDEX/exchangeparse.h | 1208 ++++++ iguana/InstantDEX/prices777.c | 1812 +++++++++ iguana/InstantDEX/quotes.h | 880 +++++ iguana/InstantDEX/quotes777.c | 1016 +++++ iguana/InstantDEX/subatomic.h | 1496 ++++++++ iguana/InstantDEX/tradebots.h | 323 ++ iguana/InstantDEX/trades.h | 1583 ++++++++ iguana/exchanges/bitfinex.c | 262 ++ iguana/exchanges/bitstamp.c | 170 + iguana/exchanges/bittrex.c | 245 ++ iguana/exchanges/btc38.c | 321 ++ iguana/exchanges/btce.c | 216 ++ iguana/exchanges/checkbalance.c | 53 + iguana/exchanges/coinbase.c | 229 ++ iguana/exchanges/huobi.c | 184 + iguana/exchanges/lakebtc.c | 283 ++ iguana/exchanges/okcoin.c | 243 ++ iguana/exchanges/poloniex.c | 230 ++ iguana/exchanges/quadriga.c | 185 + iguana/exchanges777.h | 68 + iguana/iguana777.h | 1 + iguana/iguana_exchanges.c | 726 ++++ iguana/iguana_json.c | 20 +- iguana/iguana_peers.c | 2 +- iguana/index7778.html | 5177 -------------------------- iguana/main.c | 3 +- iguana/orderbooks.h | 3456 +++++++++++++++++ iguana/pangea_hand.c | 2 +- includes/iguana_apideclares.h | 13 + includes/iguana_apidefs.h | 7 + includes/iguana_apiundefs.h | 4 + 41 files changed, 17450 insertions(+), 7338 deletions(-) delete mode 100644 iguana/BTCD_hdrs.txt delete mode 100644 iguana/BTCD_peers.txt delete mode 100644 iguana/BTC_hdrs.txt delete mode 100644 iguana/BTC_peers.txt create mode 100755 iguana/InstantDEX/InstantDEX.c create mode 100755 iguana/InstantDEX/InstantDEX_quote.h create mode 100755 iguana/InstantDEX/exchange_trades.h create mode 100755 iguana/InstantDEX/exchangeparse.h create mode 100755 iguana/InstantDEX/prices777.c create mode 100755 iguana/InstantDEX/quotes.h create mode 100755 iguana/InstantDEX/quotes777.c create mode 100755 iguana/InstantDEX/subatomic.h create mode 100755 iguana/InstantDEX/tradebots.h create mode 100755 iguana/InstantDEX/trades.h create mode 100755 iguana/exchanges/bitfinex.c create mode 100755 iguana/exchanges/bitstamp.c create mode 100755 iguana/exchanges/bittrex.c create mode 100755 iguana/exchanges/btc38.c create mode 100755 iguana/exchanges/btce.c create mode 100755 iguana/exchanges/checkbalance.c create mode 100755 iguana/exchanges/coinbase.c create mode 100755 iguana/exchanges/huobi.c create mode 100755 iguana/exchanges/lakebtc.c create mode 100755 iguana/exchanges/okcoin.c create mode 100755 iguana/exchanges/poloniex.c create mode 100755 iguana/exchanges/quadriga.c create mode 100755 iguana/exchanges777.h create mode 100755 iguana/iguana_exchanges.c delete mode 100644 iguana/index7778.html create mode 100755 iguana/orderbooks.h diff --git a/InstantDEX/exchanges/coinbase.c b/InstantDEX/exchanges/coinbase.c index b9ac404bf..1d46e8efc 100755 --- a/InstantDEX/exchanges/coinbase.c +++ b/InstantDEX/exchanges/coinbase.c @@ -93,7 +93,7 @@ cJSON *SIGNPOST(void **cHandlep,int32_t dotrade,char **retstrp,struct exchange_i sprintf(hdr2,"CB-ACCESS-SIGN:%s",sig64); sprintf(hdr3,"CB-ACCESS-TIMESTAMP:%llu",(long long)nonce); //sprintf(hdr4,"CB-ACCESS-PASSPHRASE:%s; content-type:application/json; charset=utf-8",exchange->userid); - sprintf(hdr4,"CB-ACCESS-PASSPHRASE:%s",exchange->userid); + sprintf(hdr4,"CB-ACCESS-PASSPHRASE:%s",exchange->tradepassword); sprintf(url,"%s/%s",EXCHANGE_AUTHURL,path); if ( dotrade == 0 ) data = exchange_would_submit(payload,hdr1,hdr2,hdr3,hdr4); diff --git a/crypto777/OS_portable.h b/crypto777/OS_portable.h index 57c628c1e..d3c8bc7a7 100755 --- a/crypto777/OS_portable.h +++ b/crypto777/OS_portable.h @@ -96,6 +96,8 @@ void _init_HUFF(HUFF *hp,int32_t allocsize,void *buf); #define portable_mutex_unlock pthread_mutex_unlock #define OS_thread_create pthread_create +#define issue_curl(cmdstr) bitcoind_RPC(0,"curl",cmdstr,0,0,0) + struct allocitem { uint32_t allocsize,type; } __attribute__((packed)); struct queueitem { struct queueitem *next,*prev; uint32_t allocsize,type; } __attribute__((packed)); typedef struct queue diff --git a/crypto777/bitcoind_RPC.c b/crypto777/bitcoind_RPC.c index e64521a40..6cae9dc08 100755 --- a/crypto777/bitcoind_RPC.c +++ b/crypto777/bitcoind_RPC.c @@ -18,7 +18,6 @@ #include #include -#define issue_curl(cmdstr) bitcoind_RPC(0,"curl",cmdstr,0,0,0) // return data from the server struct return_string { diff --git a/iguana/BTCD_hdrs.txt b/iguana/BTCD_hdrs.txt deleted file mode 100644 index f455c5c1b..000000000 --- a/iguana/BTCD_hdrs.txt +++ /dev/null @@ -1,1772 +0,0 @@ -885001 -0 0000044966f40703b516c5af180582d53f783bfd319bb045e2dc3e05ea695d46 a5d211145f8e6ba0920b2893d307c5d7c207ae0800a80955299678d1706ea8ac -500 000000000680a9a697eb71155b18a5827e0889fca28afb81fcbb46469ed7877e 79f80a8f54c6762d6408347c6dd7dfd2f8b8c191077c1d7881dfc5b7ec6a408e -1000 0000000000000cf908c887020f8970b7fe952f8b81164d83a87621dfdb581d08 3356ec4296ff2f04281492b0dedbaed80edeb6dd9170b87230ff79f6b0daade7 -1500 00000000000010e39eaa987e695caed67aa0f3c33576fd2621422c7c09152ca2 e9d31ec9f5dd4dc2688791edd4cd1abc964a7f843c59b948903c3492940e459a -2000 000000000000029e318c44be8a5e1d5bc8f7823907bad160aa63fd6121dd0ba0 15e2439021c4563c7eab5b91c916a0c9c24c3fb374b49ea24a4e2aec241ab099 -2500 0000000000000b813b136f623f85155cad3069031cde918b4079e907e1a9fd58 76ef339392ae45dbfeb2c6263e4e88b4cf888264d7ce8d0361258a81061fadb6 -3000 00000000000000e5ac27d3bb729f5c8a4312f69b28c9cefbb18b8fb55ee42c87 dee1d4ef373897e52847416837485706f5c0fe29245eccb0819ea5d32f594051 -3500 000000000000123b4e50db3f3706974f7e3593c2897bb545177d5c8a5a11fd35 75c65538d4fd33e5a77d5b9e5d756587f45a7cdf55646f1cd72f2da2b7ae5772 -4000 000000000000013e3c1513a7ffd71ba89d7440fcacef6bb39a76527815a71043 6ca70d4bd86a4dabdf5312a88a99aeb874d851df717879049d8d91b464109adc -4500 00000000000006e6d70e292394dd1f4aaf1ba3ea7313ae981a0b2f38ec4b0503 e97f1c03d9e0445a00c160c648d2f4920845502e788f5c3f2a5a392544e18d0f -5000 0000000000000278ac01346559ded91fc585defc88bbaa9d7f111b199e516779 45f12a1790418c3e9000bca11394719138f398232fd62ed3c801b5eb1e9199c5 -5500 0000000000000284e3d2455f09d9613ff71c49144823f882b003ed3177c1abab 149ab9c582053c69b64d9b3c3041f04527bcd47c572d600947d0f737d675f953 -6000 0000000000000bd43190ec79e54ba203c9387abcc8c1c03c52452a44466f24b9 ab0f1f81aaf4000295bec7b21ad5c272aecf7dee60c451bcbfafb0beddabd2be -6500 000000000000029e27c331ad9865fee87dd19e5ed0e526f9974510649616cc1b 9ee7b5e21984f8e3ceaa88aba5ab2d88dda10cf28c57b826e3bc8401d0bac0cd -7000 000000000000034bfd6bd049678a41563af84a9581d1ccaeb4952c954e327918 e09213923b66de743cf8edc0389ab1b6c07c0c79a175b3e93364ed73c2efeb69 -7500 00000000000003c5a246cab977e3f339041bc95aec5cddcc3d459d3d2cd546a7 4f26360f00347667d1c2f108ad3e2b2f599a599cb77b1ba9936988664ac53d4d -8000 34d2ddf9aa94d6e02224588d3d6585028a22f05f53529a19a202f41ceb36cefc 8bc3244b74f884ae355598fe0200a7f09bfab53de1b3e122020c4e2daf08fb63 -8500 87ddea52f5073e5283ecaf0efc637da3a47986396ad30b3adec8ea2ba5f6a09b 65ae81f7094626494fe8b984141c265f689f4d6abd33a3a74eb491c31c5d02eb -9000 000000000000016845387841c3d5a584d82763471d4b84af3921ee2832715e4e 11b2851886bc2208cd41c8381ff7bd6350379f6c0224f9608450fb0da56a59d0 -9500 e64e3a10f2daca17836d2bb5868e76290da1fd3e0574da496b06182033fc70ac 5d6ac130a3a5cbbf28cf389cda08aabe9cd5bd9a4da2d0ecd19c27d9ab2320fa -10000 00000000000001634bb95749a866092348aef266f9169c3ddbcf226d4807ba09 986b59e97d259c74881bec99d68adad8e219a0fcaaff6af3fa31b0b5a89e1b33 -10500 9a98c541a5e55bcfc8eb6d887d83dc6049a33381fe0aa3f4766006c1fb066905 3dc29b2469167c07aab94fcd87c03e0bad1a99d47c3594d80b700b05190eb526 -11000 54bafbe72c3547248f553615eacb2254fefe5a4d4cdcc66a2efde3e1ad9f3354 7113b80a2fd13692c85f39cf494ba0d30285981b4829caaa92b4b748df134346 -11500 9d6f0308699be5bed63c54a2518b7a69aa2e7f5076202ec077d3d53159b291e2 32f1b2236a56fbbfac8b1a72e3e3cfe24531bdb2c38c2619828d11c1474df677 -12000 00000000000000734778db2ce455744e1a50745ff4d10ad3d787e49c9c2913ba 712f312d18d3c817c33e522dc5b7b50b9a16c0dbac13e56ce817e8b6d7f75ccd -12500 00000000000001209c8fe742d1a45c5fa9689f8622217ace049fa3864ae24321 0c4bf64e0024dde945ddad558a13bb180d931ed8d6ca79c13112a154db415794 -13000 0000000000000064fade9e75fa24d1d1974f5ca69e84e8688ef0a58b9dd2dad2 b3411ebcf6385fb575beaac292c70d4e79686d832d6138ff3b68cac8fb8e96c4 -13500 000000000000012cdd1996be2f29e14c0654b11476e254e4ba4c6829c6887ac6 054f36fdd7e83ed836fa5c6ca63ee54929fe3549b45da07a1efd1cbfca73188f -14000 00000000000000b930521b5956b17943d5dcf001b4d319ba7157bd7fee6a6fa1 80ed5287e00bf627a20e525cacd1b6ebc2077a3e2c71a400bec64eb7b80046f5 -14500 225abc3eacd079cc0949cd8d0eb8978b5bb00720da7178ef5652e70754914d88 c87e7237cadf805554ab3f259bc89eecda51149fdff0ffb29925712a218f76f8 -15000 000000000000001f08d59b246a225efd70b813c3df8e468bc9d99d7d686fedc6 2ec038bb14816230448f041cae3a9ab64f4e237a53cdb0416dff8a2e062586b5 -15500 1181e59d86d7026c523659c152db3732c69e56a04ead32a0617be36ad3f2f0ad a2511b8ee2e0158dc668e0de527e71455b7245c01f41ad66e296118715aa33a5 -16000 0000000000000015155b08a0f074b1ae3c960bb90e96549a16d0b3eb20a4353a 05409419f76edb4ecdaba62aa65195063865344c93cfa1e35bd41931201830dd -16500 91d0e76a759d19aed57d2657cea4dbe861e849b57602a4c5c69028d24f795fb5 767a41f042292ccf2acdb0b91163b18dd6b59aae25ba60a8557a01f02a5db8d9 -17000 000000000000009f949c3d1a6eb1d50cbe5a3638acc49987902526df0d4c3eee dc090785300641d04d64f572fa7d645faa11c4677d74ff356bd8d51f50c0517a -17500 00000000000000376f6a1ca86680e16d0127507a1182507e502c6cb85cb6719d 89dd74d7a8b4f5ee127e7b4aebe54f4cb2c91c79fbc3045a59e5f94227ac6b12 -18000 a02b59af01d4fc762d8a5708b22be769b7ef651afa88ecada21eec58dfd53cdd 42abadc5ef27ee4c954518ed1a1e865a3b2bff3683baad8fb35589f8953ac5e4 -18500 00000000000000dc2e6182da1a35d916b98a4778fc35c50de27a770b9f63daeb 7a44c2603b3d31b23a607a40cd63f9ce9486a7a3de507bb26f6ad7c1e0e75466 -19000 00000000000000017207a368616b26632bf68e16984c098be64d2fb064d3a2dc 190ef6e670cda631380598333765702648c55bbc0c92d68d3c2bb5f76bc546d6 -19500 00000000000000ab3d7e8810b7ca9f8b61f630ec6e596ee105cbeffe80c41d4e 5bb4af1b5c912873e90a93c0d2c998b367768f05fa8650246bce8dd4e8b5f0a8 -20000 000000000000003adb97f0d6976b906982f3272ae0d656e1c593406b05bae17c fdf85ac01a396b796ee5dfdf3c7869dd3f7eac36a61bc7a30a5c7e8a9c5dea1e -20500 dabee81d7aeb87b59d94c497ebe1552b3f5a5ee1e366ce64143e9fa426a6462b 017e99080b6064d5f8852f6cda7563f8bf299dd15370a64ac74f89f22bb42220 -21000 7b549feae0c08f58c44ece421b89b0626d15547fd1199ff172704a51476e17a3 50e176972bbd1528d333c01501e05baf97876b8a51030cc3dced40c1bfd852fe -21500 4d7df2acdfee2592ee66f6498c2b0de972ca6e0c8e2ab38eb641dfbbce8aca04 e10aafa5c02a56181cc6ed4b48ddf1a52370d95c99678bcf5fc6a106df343bd2 -22000 1f2cd2094e85ba89286a183da2b9135d94b2be2c5b3f31bafe89ab3f631c5791 b97f1ff53a6a11d6ad3b0ff270ed2bcf70500069ab5651b8466110d472a1651b -22500 e797c4b4ed2720b494a3501a32a247f7acc38f526245ff89c8f148babbbf0cdf a5b1353f344534e8a9ef6365be58040355391297cde74c723c6a5465e39f727d -23000 50b9f76effc822c9f1051b1c0ce25bba6112a31d32a055520d84ca0f1fc39b8c e12e33c6b273416adbf598ccec93ce0dd6a3fc817c6f8e4753064e9ef78e89a2 -23500 fcf644a9930ec30bb933cc37061a17d0edc29bb16a04ea4bbf8b27444d442415 d5a23580de1505a7df77130fda147aa774abfa1f16468a55b542f69bb6199019 -24000 144f4d11b3a867d17560ef3ef04362efc715c89c30082882df0692a214cdbd75 add23a1feaf6ae651d6d322142bed5998f2d3345fc767082817ca86139d2de71 -24500 8d8fa5a290cae00be37053ee99cf2ae70b37b4806b41575a09b7a948545215eb ce758bf937c83d93671078985a70493b6bc1ab33e680143c6e93c2c5aa3674b6 -25000 b5c67f326ffd5481bdd18f140c03ac34a9d467bee8116c7a559a8777c688ee18 2e618ba056f201573ae6222928d56fc3321a3b16c32681dcba8c07587ce581b5 -25500 80d41cb90ce050cb9db84205aad00db5761a465b000b8b3a74bdf57e7bc272c4 fa5e727492c4a83fe816724e80c54ef2add090d60c3fdd788c44721b67331726 -26000 de58126ac82bebb58f841f75602b4307ceafa0d9aad7271567ec69d734b3422e 3931c58b417157cbfa4e990ceb75e8f2aaef945922962b671c17fc9076be9c7c -26500 857f050c1a4a323b2f9d808bf2da8e11a9d691517cb0189ed2f7f103794bcad1 a7ea3d0c368fe526c8a1a79c9ce3b5cba52634c324271b3982c70e2ec1698800 -27000 43b14fcd1424ed78b3cf03615ba16c8fdb53c414e894a6fe555b5a0221053ca9 6719c5530a1c6579dc00a6d6bc26c59900d5437d4bef8d03fc47cc018937a52e -27500 503b22cd2997d3ff79a7857530f975798fe48a3b46bad0a38a3f83653beb8d1a e013d7f398f337d83d758e6af4eec6ecce14d080ab95f037e8c4354b1e4265b3 -28000 85e03383bd64b7cde88467bfd7973ad219d635708a69f925316e958d524c1b2a 112902560ea7fe15351297834affe49c0a8e768b587d1a8e6574ae89903d8143 -28500 57c1ce655a20e5d4639e934776edbbc5ad099c383b62c7bfc623368a2c3368a0 c3e03e5754ed76153656787b565a0143d538298277c55ac0ca79e99b0ea134ff -29000 d9963c1d22e68c2492bef7a33f34bb7bda7b326b4256104ac1ef7d6421862c5b 91dce271c5fcec2b60e9e9a7d1670f191be7f8e76d3d13e75eecbad77dce8173 -29500 43f543efd477664f84ee78bac095d5413449e552ef90204f79bb8463ecbd5e89 4e93e04161f98d745707c6c7a85bd4b223f124c6dad64aa7080dc612526329f3 -30000 23da6267be7a1511a4f9892875bd61bc1ae5d1b35063d78a7a448379db07c40d 760c525285ec0731ff71deed949476248fde392c8bb15f100af786b7d7e60642 -30500 199d170a784a96d70fd6421057653141b423cb730e577bbe490c4d9d5b31621c f836756815de2b187d68e2729bc667522ac6f00379759c5a7815c728d52fdd6b -31000 a2f6774be3decd68c4fc0d55249a61d73333358b03a5d7f48f19ff53c6eca193 a72c7c5328570231dfa7e3b7fb68ed42e4b4f9f4e05505ea4526779d279b6045 -31500 ead2b784815b474f24a12e57068086c7cd2b59051e4570eb4eff43c00079120a cdfb920e73fa2ab6278a84292a23123bc921782c7b9648c137ea3b5d936838a8 -32000 51690f90531b33b61489e34c805c7d1235708691163d0b25a9afe161b5bde918 44ba77a723c883778528e872d4cc6779c6485e4274ceb2ee7c1f219274c74297 -32500 b8f881e8f20864ef1db26eccd81bc46ce2b5dff8359ab86cc0b915bd6d1437e9 f390ac467135ddb1d88617c29db574c34ee51a4a79cf041bf7444c522229f8f5 -33000 8c8c61289e79ec3e22d294ab824743c29194740fca09ab44d460291599a33186 24bf35eb0ef662470b75fe38c332729ec8cdfa122a52be3d81a97bb9cad009d5 -33500 958755e9cf4e957d0471cfbeec0913140759fb3219aa74096c26cba2536579ae e88ae01956031b06310eb260b95a76e2e4e9b66d40df56300ecf108cb4579c4f -34000 d4effcfa7746bab24f9c3d12bf94680770ecc8405b5b0a17bfd0b33c2f4f475c 9e5f3f87097c229ec5011c8ce05cc12a81dfd166741ad2762a0f156a8d3b3928 -34500 7f971e1a0d2e94dd8cd0ccabc451fef38429ddbf2400bd45278fe000210d5f87 8b08d83e6bebcb12ae7b2b9fc1de91a0566ed33f2c40125d7810e2a97566a28a -35000 90e4d16dd67369b4b5795571fe0cfe63be8c1796ecf5870cad20798a752d92f2 619428a018aadf7a144b3981ecf018bfffa7975819a58cfc0e16f9ef0ba274e9 -35500 03aad5e354d5019e2cecb5a44c4ab79c7120543370cce9830b1d41590a59706b d94a9fa2f0ef62b409348c56bc376733e50fcab89ecd7fe711845f66c03a8409 -36000 5659c47e9c1b006ddb991b7b0163777977d04d70b4b52f4e3b87bc3aae6fba2c b1cb79822ef346bdfbcaacb59b7a289bd07b5cc02c8c6f9c9b1c5d27111c892b -36500 166c22d2278b5d4960af665a6dcb8c4718ca3c489fb12f6744a60337a6ea4a97 b55d2820c96584bb049d4f57766a2fb7b21ac2998038d1dad3c39dd553309a5d -37000 0c73b35172fd5a08dad4570ade1ae552008a801be8f2df85e52ae71957cc8bf1 66fceda7365584ca4e28a192d4716cd0bc61da166e5c6036bd2dad1ba0f034f2 -37500 e25729880903dd4f6562deb2c3e076c00d29e08e9c531518b2920b3e747ba6ce 886750b60b53c72b8d9bd1cf744d74fd3947ea62b878fd186618a46f1ae114af -38000 fd1aa8f0791fca7ab540a37b8fe5a6a23a84d0bf372ee35d6b12fe540b53f746 3bb81e40ce808ad93fd0057fe4c8c111478857f8ee143a27383a4d64f7c9cce7 -38500 73dc7035d76f11e288a04b87036996efbce8dc6233d00a1238f40ccd95a4ddc2 b8f0d99842fa481e5b0e6011ddd8abed25c9073b259e37ee7bf2f451d4ad2c92 -39000 f0e3715e1a7b82521f8d39fb490f261c5b8684008f5b52fbca7e5f7b204ddecb 2851428725cdcc924d42f907200a50ec708342cc1025ad035dbd7f84c0818340 -39500 16693e3a20a6c2d2d823b7c3020af1a20d555401ab098f94ea8a83b7a2a9af4c 400ac0ebe9428f526123f90c8bccf69a6835ad322affdfcfda314ea795e1a1b1 -40000 fbe5242823fe378d36335366cf45b3309e8fad0df3f9dd542e10eab3b7a296fb f73a533f1c917595a88ca8058bcf54b2d8e3c8cf8c46a165c84ef124fb07d15f -40500 448e82eebd5d00a7ed11123f43f8ee955790cab17cfad0fb4f1ba154b20cd1d4 f6c092a7945bdf4ce8bbb08645a349b208b054925376821f469309fcf46cb4de -41000 42e29e0fc3e8fb2c517bf4b7d24175f7467980d793bb18d4b1903fec0292d0a0 b8d88a3f3968b88b98e51232a0304506821c7c83f405515d2acf89a6a39a7048 -41500 fce90b09826a8120907462a95aef4b8dd9487efa4b0b2cb7e90a4d6d3d40e4a8 2a4319200375bf38a272bba432cb62054c4863db024e4a30c5bd20bdd569b939 -42000 f0815d389fe88bfbf5c361762efc5bd1264dd9256bf895b8dc6f39128e130154 b26d951f8be8ab9091f1e6c56a539d1d7a01b50c265ae1c025b698f3edde5b6c -42500 97171a32bd838c19f12586fb03992387b4b4c8d1342a0ddf3397e44b7c9b432a 04737e3fefb938c73100a32ccea93455aa0a564e41e608a1772ffdd2e0d10033 -43000 a1ae4df09a7e3f060a6693d9bd75af599a658f501b0a5583442aed2bd0393dff b6290ff23b70623802b15c12dfe3e19111ce081bedd2f24a0c6b4ead9d8989ba -43500 85e2d7b7fda1433ec964d4ea6cb4fa7af661d38f761877bb9b0aa0acead5e437 8dcd8aa4dd692a271a4e6efe7b8314f2fc5adc4b96bdd932e2ffe76b496f1347 -44000 7526450969b0254a66686dd28d61c10d0bffafd0bbb623d0ac71f6c45048b195 7c626106e228c853ba6d6c9d63f934e51661ebd7ecaa02d66608bc2f1da0877e -44500 313c4a7250c92bf888dbbbe977f119854876d877cd7ebad97da3e793e4167084 e1da8d161f08c6e7cbff74ccfcb80644b571747988ada991c4982625e59d1a0b -45000 9fde3334234a707dee9c6a2e3ef6069a30c0bb4293555f59ac70ec398c818e94 987db78e383fd57efd0a1b0b0b8fe38c50dbcd648da9a1eaf5d5f59d0c15235d -45500 30f5524584e0e3016ea738b1984cc7fdbac63956d6a154ac474ff28c873eaf02 2a6909db1ed2d684bae8cacedac0453a13e37ef1485760b0ef6329228a71bccd -46000 b79943e9ccbd2513710f58b3a5ac822bdcd6f390afc8258ce7fa1ea6822daf2c 1db10c590ef1fb219c3b98c707fa294e263bf95a4ad26c2c214ebb19d4236297 -46500 9680afcbae2cdf4712605c9d592ddaeb87f9e8c522c6b5f0beb219e71de389b8 75ab5e40232ac575b25c0b892af025d5405aafe1f808551e7bd33abdca9a86cc -47000 1deba95895fa7fa09760b2b6f12395e6a40dc7ed3b14e629b7d85875e6913eda e735fd2aefe57540d02327e774c7069d08a3ec5b35e6ba939b1609d98a29a245 -47500 400b71a80cf5c7a408363c4a88a6f17b9fee56830f9639bf682cca7f6a1b9ef4 179f44d13af45605ea60c9fa6e0030b5de6c274104649283e5929abda3cabd0b -48000 b62fdb21ede8c1760346b4325be6d08852ea3944fb0adea0b408742977fe122a 8ff82f9540381a20ba68681f6e5442df8852cf38b2476d0a6bc61162d6eeabf3 -48500 baf6f61655d7a53726d313806841300c1d729f7206f62a267c1b4c351b365763 fde6fd7055e1f6e03b9d327b3c502fc02bac00738ae0fb079f128e2774d0078a -49000 854ab5b99aa89fc7d03f0b2d7f8a54aa7c98b23957520ebc8f4e6305902cf2cd f39213ce4a4fb7c2de3088ffcef3712113958562638395dcfda8ff6da621a09d -49500 c964b7057db84d6b9282baff7f2f09dd72fff06dec110201904bfc3846923bdc e2c15ad8f20ec681283af4d88c56e1433c9c20ccbd11e269ea267bbc2f9ebf1d -50000 fab7500f5f0b1694a9c65a4b02e84dff228af92fa447d810200a3b14c35242cb 194fd02a69a66e9293a06d354206757e2bc23484e3e8cd80522ff71feffbdff2 -50500 ed4e556f251680672e442c00cf6a48f3a787acc589ef3e83019851808ffd05a5 b51a4252fdbf12378dae10ac1c94690365e096f786feadb8e75cbad87c8f8a99 -51000 2410005ccfce88835da97372f39ba6708e7eb10f97a4428ba2cd51e8ee87f7dc 64e4a8d5a545ffb1af7a5dc66be6ff2aa517a99c7bc5d7b2d1d1afafc1b93a84 -51500 ae13af1cc26f53deaa57482111239bd24f99814dae1e01580a1957f11aa49a63 4a0c54d391ad8bdc303e226fa1aca24cce0ba24370424396bec9917804f0bce7 -52000 163e369cecd2362ecebef4717e206124e3bd47dd40104efcbbc8610fb48dbe46 3b68edeaf66e8bf1e1b187fc0a5e0424b6cc896661e2a4f44882cb060f9815f9 -52500 c3e5334bfa7c8d5d577b1a74df2deb553a006f68b384ebd44eb7bdd7aca3a297 fa5cd9249e7b39e2aef8bb19e83e214d77a45b4c67c4504522f94baeec2241f1 -53000 3a790689d0f51fe7dd6115b7f0e5f5265a3aeb912692596d2611050a17795705 23b602a52f2e393f2cedd9c8ea0597931f6abd7b4f4f1d85f1de8d6382c03ec4 -53500 70a1da282b26b9dffe0b36a6dcdfc0c4bf218a86164adfbe7df4cc9c0b978969 f6ffbf0fc14817b41ce42831d14add2f8ec22307e5b6baaa9f07dad06c387e8c -54000 630d02d2f2a8889fe47a4c2235a60b2dfd31ca78e487860f59d24637a2032af3 901287c9cb47c082b5329f422d94e71def436bd0979e939e7def8c60f99272bd -54500 4943f865d3e75ddd060f8145558ec7f57c10d186b3bbd3d90377be4713e1fd22 26a8c618d328579faee0816d1d723736a249dda1e95647ce7775b0aae5b72854 -55000 6e96c77b0964fc2077455aaa2067110351212e2ca707fda778c963fbbddc844c 350612a0426a630a0b001ec51d875e2d1c87d20353a480539e5fddf91cb3097c -55500 cd718716c94cebd61eafac70f8562db8b48735765a8613aec79d901e0c5a05e6 234209073d425564622dfa5268e7f2af5aac71a18e2b15d23ceff1da4d876563 -56000 04002106ca4da32c5c7889c8f17369d23a35bce62a8196477c8f8e0e0dbe4efc ac25f2042536f1a588ac6747b2ff3b45de9aed063b096ea59632b3aa45441ddd -56500 6460fc580380db980f3b76e9480b2dd98f4fec5c9642b211f7258f50575522c3 12c289cc82037f732305d895742cb703eaa35a4656faf84c6f7dd9a2783cd2a9 -57000 7f1a59ac62a06df2d3d82226e03a1081fa9a8c72c5333ba485565f9215423362 5363e6896a5eac3c62543b82b6260a18b07597b5963d038e728a9508ab55b181 -57500 88bf14d568f5b9d8e88d27a92f2aa97a569f371850be3d6d1ec175fd9e1dee54 56aa31dfeccbed31839cc2399397a826f2e64a16c4fd309ba87ebb2ae7e7f695 -58000 0ab0e582e675d0ead1173cd65e71157f13841b22560251a2aace14ca86fd66f2 bb20d53b616962e78610b02a60785252e90c54d78f33a3578172cde77075a776 -58500 637d24d3f5e56f5481735d0853d74cc85c170dc95dba4eb733af11ec3ff048d4 aa8d5505be6a30af2a0292fcd19800b0744acd87634bc49ce43b0d767117a5cb -59000 2d88b4676741afa7b183502fffd15bb1580f81b4b8631844be86bacaeec0524b fe841a70acbed4f52a83b35cf30c0cd5ad38b36b21b24da1a0ead110f5e7b2fa -59500 e5b98e82ea2968293969b1da31bbb8e30dec3ab5cf10308d4a979e3264513bff 17429be3ddc868c9e3662b5aa6223340d57b7284138db428c725c8fe69e1f89d -60000 98764fcdc2a2f8a740a4a1c891ad966b44062f64195effad2ba0aa4bb9c4370b 55053a4d083f019f602ca159faef86ddf421c4c4c3bcef9f0849f45e1f8c1c44 -60500 24bdb847b0ae121363eb0d2a7ab69d672627b4d68195fee18df5ab5c076ba3ed be197241a0c377fa6982b5c24af043034024f889cd3ebe42d4a9b3fa5dd18953 -61000 54222686316d912f144e6d0bbaee1b3fa50549e9da65ffc21b04c5beb3ec6daf 6c5a388a8dd7f9d104377e1f5b2817b50f9269145da48dd0d71f48e2af8b8731 -61500 f14bee1d7d3830f8c316f448ca36fd0591371a63fb9d04596c657051ab4c2ff8 86c9232b738073c671adec011771072c92ed0616c361bcb6e9af6074d09bd6ff -62000 5903eccbe3d0442fabf30748705e88e9cd83128a0bbfbef66841f590b5011bdc 4de78ca5e16fc438337a8d5f7aefd2cbbc66790d019a1bbc5de082a79e39c303 -62500 35db59c0b059705518e07b3beab25716c9fa347a1fdf7bfa0089d011e2586419 961e208bd356ecb07f838ec1d1cba0eddd79d5e026ae350f0945cc321dec970c -63000 5fb6db58962ea9eabcc50dde4f473a0adf58eb9a409665d57cea3b2d3d2f44ea b673d848fb79ad142be92514c27dad64fbf98d26e1e4f5957376bcb2f8542288 -63500 92e31a33e15bb677aed01f2ed669a2700223a34fa7342270275561ed5b88eac7 7932d5bdbb9c2fd7f172a79a9e93f73aa3703c284afa98e7530ea4ebbb4ce7fa -64000 065c7297e545fd1739d04c6ed41da4a82a24404c7b3573bbacca0c266c4cb716 912632c93e91f5f539b2f9d6ff8b16a1817c8eca88b6d579dab56bf4d48eb31f -64500 a011434ee029b50acdd49262a91b0767a897a5dfa7f5c22dda0a32aca9ff334a 37993dc2223b292109f02e9eda7db4178f6602aae957b80eee7cf94dfdcbf020 -65000 5144e900145e481fb1e569b1b522143348a38052d35452dc7d97e2140b812e26 217530b550c589b0de7d145fc8b1059215bf5c124be7e79b5854acc200b511a0 -65500 6db49e04b2c1ed108caba28d4de98628fc786f5224b098de1636a697ddbd6e6c 5cc92190d39119982836cd5b0759902c4c61517aebaba16e6515cfca53bbcba2 -66000 559d2603be7835ec386467221e23836803606f7fcd7068f6a42ac5054e48fe88 68c9698e2684c3375d6b4d83b33155e15ff1d50aaa0fe61276a854f7c022e3c5 -66500 d724f78b706b6a58400a729586b050fcbe843a3e632376f24db6fd4cb9a44177 968a75dc8e7e9128b5e7e00b22a78fb53553102b54247bf644247546a9db85e3 -67000 8ddfa37cf395f7b4b8d6d09e29cb7f11e7d06f929d7ce7a77ced27c79011235b 9cba1d323704f1b566fe4b639737ca2f6f96ab6f9f1373d95e1d8cfef0a0a1fd -67500 2c5e2421936073eb47199fb03dc0023bf42572f507f484fd9181eb1a862e8972 4928ddef10d983dccfdbcce08743afe2a0d1238fd84bb4b6e1781ca7847d6ff7 -68000 cf49fb97e127593bcf3591390401803095f71ea86922369e573b1c6bf59ca692 accdaba238ebdebdf85fcb74a46d17e5c29a996e3f1be6147a3f6027a13c8412 -68500 eb68bd36c8212efaa20bcc2d1c17f17af6ce65b060ca7ef80dec2f44052defcf e04d8a45c474fb6ab8071cadd8fb14f5d208472089f6a22ff5c04904f7a01d55 -69000 03609399659eacd9b55c608e6f35195530a35358812bed13782f9d5df5da1ebe cf4d7449a4a7aebba820fc84f3dca2a48ada14feda094a425833d4a5aec834aa -69500 1d23b15a2484a71d270170f32918f36fb87e80cf4020f6a3e6d61907276fb3a5 2a218f285edae9995b3334352864684c66f4a919c92031ee3b24510b568f6246 -70000 5667dd2604c90cb15f49a75456b0bcc2a0098bc025592d48379f4360844b79c5 1b6966e82886048d64879d2b76663fd70689c7dee808cb42352f57af598f9bca -70500 745715d010b5ab51456342b8772a53b95ef0cd409980df39c443531f2f6c2346 a1ca05cd11e6f3d9eb2f0498b8a4743defe546c7602c3fe06642f0226cd22719 -71000 c622f3d2de9a6aa2d649f10532164082ff6ac21da796b037f2b2a210fd2910ad 3c24535ccd8328940b86980f1797d0c4e0dd0fed2ada72a0d9ce7927f4e3b040 -71500 c4350561b063c19326afb0b38b7aa70a65a928ecbe3a545f26f1dfba40d16599 7167266f09bc1b259fc6dc6ddd1c4e03514e4b4e5a985ce79cc320d80f376e9b -72000 df857691f4e2d2ad6a7de6a3fd77cd3e1ee19be220f7f92006e30c4cab62eb8a 1e962f15a4472d511bc049be123041f357376d95df56677c32ebf69640fa5459 -72500 affa0299a9d64d61176179cb14978c6dfd116b0350638b5e2633c5a73bb9e5ba b04e559b1ff6d04f2fdd2693c384bc89f05ee28f5ba8cee49cd057c575b0acf4 -73000 a50964b3523aaffcbcfd0be0a6fda32ceb87018450ad2ff81f1ba61de5fa20b7 e3301d1249deb8b1065c59ddf02c4480af9208ca0fe70f0b94f7135e3baed857 -73500 629acc1dd038725bbad7598fc49a7178771332ca4f12372248da579ee5dbbe54 8d2425646be01e20cf3554feec43cb91bdd92f0a6e8791c7f8fac4d21767b45e -74000 068954a253aa54239a0a4169f50ee7d37b0b5bdfcdfe9719ce9921a5917715eb 722bb617216427a0cbbaa037d1234bb7d6765707108aaf171cbe14e24392a8d0 -74500 e688640c22b3c55fdd29e86a159e1cb665cb0937cd6a5591730a1b5de7c04b76 4ed22bf35c9c19ccb01db47714af7f2ed0a7d2506f40a5e43b92b971edf62250 -75000 31c015b503c6830b93948a51598beefedc78d8957af82aca6ccedb2aa592de8c b75f99a073680d704089e1a77cca65d027722aee3a4fd7c1f9578b535150d5e6 -75500 3eb906d2939c3f6ad815a51421f488025326b8cbdbe28c15ef32ba410b7b8ab4 39ed4ea10fdb97d192dc03a86a397b24f6883439e7ff6e82d9e6738cb90ed5d0 -76000 d21f08b186c4d763e03ff71b1ae4e7c07a9dbd30c518242740c2c93119d8d96d 3898b748f911a413cf66daf2e319b3e72ad25ceddb77f56a7de9165484405cd1 -76500 5c8f54cbdc2f5f83621da3e57c28d8e19faca81a438cb5f4aa144a4c037a0055 979a3726654c4e3bc195da85f13e24639650c2d65c460c91ff1b377e27a3b73e -77000 e5e2e50e27fe46845384682b593999c03b4848a5912bb45d22974cccb551d125 75be98b3706894389661b6e9c20057b55cdabfa26ffd74bcaac8fc01ba273340 -77500 be8371eaee6d9fbf2c550f71e9b41d135201b8b4657b94e6660c908f239f986c 32b8f8fdb525510204119ba84666c0713d8f486328a98a130c166f36a2582523 -78000 2eff5feda9ab021f5afc380a7f931e7d52e7fe2ff3e2cf1ee7fdbde0eef82b64 65fbc737d459fa4f14f34704e11ecd9adfd51078f45626671bc698ae18d849d6 -78500 3018bc8d8b545e9ec88e936af13fee6bdf3ede83f61d2bab5f723803e53e0062 7b2380f5e4d64db1aefd218b868cc51902a54d0a0db42cefed99c7e8de87a218 -79000 b0c165f1302d8f19256dc2e278a7a5ecb99eac7c998306a50c8b4686a077356d 491242e8fb5fc40eb435f931bd11bc42428634a5b83abd1fb9f19059712b1ec5 -79500 68a1ec922af3091b3f2d59824979ab0f53a92198465ba557236cd41723deffb8 fb4a299d949b55ea78834906a69ab9022a49d8de653310369fd8ba9af477b7ce -80000 3b7489d3c34d0848f031a2325269daeacd8d00cca588b2b0155a81bf5bead1a2 9ec13567c8ceb32e9315afa4321f0a088d662f7853d492e8fea9aa0825f0c8ba -80500 a4bdbb1067263df39ae9c3fe98b7e436bfc29fb020ca4e0caedc4b92409cbabf 5d94d51295cffe3419841c9aa1afe3a281863f571789ded22dbee32e03726946 -81000 ff01efad3f1d35001246db4167727135f57b0e2603185bd8f43310d2725b4da5 41766254f9700bf8590b6bfa6993eb56e866af75377438b7b7ec4aecff1062e0 -81500 1e6d76e93daa7db4bef0b866414eb884b80193359343f7984cc4ad813f10a555 87b53a2233125cc8b28fa7fce0ed9d4030665fe83b9e63a76e545f7eaf332fd9 -82000 f77522692699eaa7adfa876193ff59d445443d55389e9110c211d4892d0e4501 a283d883a0705d2dba7c61cb45d6019a7e464aaaf297d8cb28103358c12e33db -82500 ce6f78297eeeaaae876c2528e2620ee91005af068e45c079f16523772b1ad1ab f52cb36181b62da6142382debe8325153fa672ea2a82ae0f4f1f05d3945ab944 -83000 fb926dce75fe0237ca38f35e58a77ce4ee8be04da61b16f360b029ccb889ff75 28adc102bd9b8be9013e2400e65d2d57750e995bce1b03ecdf1cee59712f359a -83500 f41912c2e881115560d9b957f91a8463c082efd4b887d3a9762fa7aa70d7dac0 aca22527fa30f5d0e0a8f2505a12fad648526bf7c7a0012b2ea02ecdf55b6fa2 -84000 04c39ca3103cde71f02315b339936f58cb04aafe9990c46326733493897f848e cacfdbf9b2ae2aeee8bfc355d807badb9cc02835889a999e93c14ea7800d54c5 -84500 5f40a8c35de9dd97ecd7244e84a895deb4fffaeadc22ed8d206d303578471ad8 e1c2dc0617f6e76b2ab84179c8bbc55c46d9732c6952beabec2d14babd7fd9c0 -85000 b181b9521ee2b12c19c5db467c39855af3e1f636a4086e1c6a728e2b45165402 8243d308e207fc44be4180ad0a63916aef3877e6278d30cb6f795d463541d26a -85500 b010687cf83e100f2d398b3927659ca342b25e443147badc9be5f13331fde93c c635b1e609f40f3bbd4aaee0df1ea6b27f18094f1d00377f69430b6507012e88 -86000 291fee34f060bf3d1c39be96f5ee8cf18c625515947c5495775924f5702abfad 47e1684b5b4942e0719228e060af33e8f13389619e91925d58f86408ea149035 -86500 bdaeabf298427c06e09a2e646e10ca3d17056bf1ba9619371327ccdb3f72c09a 4eda2aae345266db3c1d7f8e49699c30e70c8675735a83972d0dbf0db2372c24 -87000 8f8fbadad337ea15f63bc845e472d58d4c6467a516d77d08fd603ddb3b98d823 2d021df329f3c3bd4a39a5ecbae773b063f4baaf776f8ffb519b0fd4d803373b -87500 109c6f62e3aa5e0ade745ab3544f8d055d4ee1bf27d217bcaa0815f8b31118f1 1cf68acbbe94735132fe7929ae72e1fced6fc8cf569bfbc088a16c93c3e9e403 -88000 f46e00026587a254cd7a382218d9f2d61d37139d7c3c4f0ad76d35c76a2e8fd3 fc2e809bba17e3198bb92edc5999820f19a4d7135330b2f7b055252ab91f4896 -88500 a048c5a363aaf55cee60a2a4286afc8199b7bd0d57d5e039027d3db2a6cfada8 fcddf7448b220764d0452dacea67e5a91d537830349e307fdd20763143f92bc5 -89000 95e0fcbc78961eb79d44bd8e8055a26e77056036cb235779fe1ce22086a8705e 3454b0857e99663789646a938c33241ff00e4f7f853870665767bfe04ffce0bd -89500 8ed9d4f7f4c3ec8eaaa57d893a9464cafa4e2ea705756bc00c9b9719d51ee56c e836a5257dd6be6b167b7cf6c39b17a2433b07e86b2ceecc6886e57cddfa2a94 -90000 bd2cdc7f05511794992b0ce31ee8d58e428ddf12874905f102d2ca0a37adf8c8 e182353321678e537290c24a2a9c09d226ecd91044cc139038dd134ec1ef1a73 -90500 a996f4865ec304be3972056e4fa5890baaa296db692f4442c5b0b7337e75054d 98a91f31ee5cfdf960e1fcda3ff3d8d058471e2df6db7bea0e3937dd09baf06d -91000 f6cb4c4b3fe3b7365cd9e05f757498cef6da8eb0e6730f4c569bcd3700ba1d2a 91a792fa965f57abd8c8c95a37069682f68a3ad2112883779fd33fddf3cf7368 -91500 4421ef207f0a56fe208ecf3cc145cefe926784dc163500dd5018585c6bc4c0b0 2870e9bbe0c6ae16f66d6255485d6c6c5c198e16b7a721c0a027df05bcbb46d0 -92000 eb18cde79b36e5cfb7047d7ffd72374892d294d97b19965f67c264a42be981c2 77ce5943ff19145cab30c4b25f762f1e93afbb25e284388f88b4078fb934db67 -92500 2a1e0986047c363c557e0719dc464f44cb2a5530f36ead6455caf22579fa728c 3fc8941af430a2cbbe3a9e51ece9042410bce0c9eec2905109433485e8dc6eb6 -93000 759bd6b0b243739d3d6c28227f3a9eeca8afc6d341d17da49751065ff6d9027c ff40f2c094d151ad356ff66fd39eaed507a78f9d3c4ed2ccde744d600d3ee843 -93500 0c1648e1e670c38758befb41e8fc48f337f3b9c2aa8cf162c2856bfd44dfb4e6 e417032b5b7a38c5a9812822810148a15818047c2e8364ec0766a33cba25ef34 -94000 66cfc1f322a9971bc39ee18125a9464b9f82eef9c314670e51261402e50086d7 34ddac2e7b943cd760ed4863497ce0ba2a723bad5afb6f391082f1f1603c5a51 -94500 0bf23f1c069fc47b2289bf52f8462229a39ace7afa517a43a52276f5cb8a0f00 6d333049619b2fa4f612c1a6bc8bf82ab8a7db7cbedb51a258ea1bcc33b03f90 -95000 1781fded2a4d5a2ab054b04de3935c97fd5f535f0bd109496aab9abbc6564dba 18990d4e8be1e75e4e97a92e16bb4fbd805afa2d419629a5eec4d46a269438a1 -95500 ac453fe6cbfc81ed0c9b32241f121410d4caae7ab57c62ef99e08750f2d5f153 e3c4ea5da181b0fbd82e45e106a9c3dde36c28382093708d8cebbb72d001960c -96000 e464e4c5f135dcbdbe41de354730b1f633f00f458994d6ab3e7b272a5335e3b0 093f11b3784b1ef794fb06db18424f84c6a1bea0b9038666ac5eb0d36b18258d -96500 82345f602aad0d7ff796eaddddda22958f4d3c9c41fb987378947be6ee12f808 f6bb034032bc77c931558568182e10066932b5326940dfe562048d83dba4c126 -97000 eae3af1d8bfe6d1c40c118e0c78bae2bfb1800401d532b63a3c875fd3fc8a24f ea34ca2227308ab8818f085e7fefb2f140dfe9479558e6dae8c0dc049e09765d -97500 60dc3e9f055602d3673ddb11ab25d7c094057a0c71db2a327a491b3be93eb9a4 186a25fa3609da954813d575a4128ff890d571f0c003f0e6d62a6322279125a1 -98000 5124c9f250499786c2948dcf5e2be2c7c61b446be3972adbc0d65edc8ff87b0b 7f5892932cd29e78d17fda5c3d15bba0a600f1e9ec2281dbaf0fb1dc67d5e8dc -98500 6f507567f549b3b1e387f1bf80ec0fef03a9a1af73147dbbbae2134d6d1633c1 60d73750b6ce4d508dc18cc64adc9e68b6bb7ea4828f09e8fb7419b56eb652dc -99000 64999aa405a2a2e5de34a4c3547ee525b503566532d82c35839a9e74a1389ffc 20052d2448a28485dee72fe536fa8b6ffda1e8465af82491e87980c8f806c8ac -99500 3cd60a841f4913bfaf6183237ebd325b7baee3a5992f092118fa49817240a385 08f5df63fb4186638211b70120a165898891fdb195aa8a5b4e41bb0f9f0f16cc -100000 f0394d3c54a8687b6090333aa03f93f9369846e7c142653524adaa9192b37b7b a739c2cc2c59123a161c9b9864a4c834dfd5021066198f51fde3ba9348d195d5 -100500 c5ad61c2da15ed8083a3d3dfd80d226b9977dc831c11e83b75b3ed68d2af0e25 e3121bb1573ace63889a3fb9305fb95857bda6e889e9a88aa2ad4c76cc407386 -101000 27c2691b9e3e9cc2008da070c0af12d0997c895fea5c405347496c6a37570f95 d465e2fcce8e1b4bf7355b4d87445d2557336354b86db40bc924752796aca840 -101500 80c3bf7835d6a11fcaa22931aae51bbc602af4412ee8ec0e8b96c3a9c7128f16 1d7c3e519be3686c4b9f09708e225c8259c5ba6647fd78653b387539f58bdbdf -102000 52bf59cb7e10047df152f35bfb683611f084d444aac4301bd0284d3e458b6022 7c8226cd17af258fd69631ce4cfdf204dab70dcf93bfed953d6cf488d576f56e -102500 5dc7c42f2501c79ca5d610b8b69d408033bf0f7d16d036bea01e90e6c1ac9342 403edaea352b4da33ec3269ccbae23c226a39961f457e5d3f84b806e517074fe -103000 719c3b85ab62248c015de680a8fba158d0a336492668bc0b202ff9fae1b1b5e4 d90dede7a044e1b11ae429bd313e841c12e8d0303aa6626db4c953d198b0f531 -103500 fa0bc10bbd112c733022783fa67cc4ba045bf93115654e1f25e680595024ef04 e55422d2e8d2b8b6429ed85747a8ee57c549651eda0fcb2871ae5762862a86c9 -104000 e63af7f5547bf8bc2f36058a43569a30f7edd8286ce44ea561e63a3bc11ea7d4 939e2e2c30e66ae3b9077e947acda9b7dc0b9f326c55cef4e4d2e5025a0df9a0 -104500 d73f74f43bc0653041db94c60b0e68c194199041c830e4f90345c1dee78b9c23 d1b14fe1a0631af85d0da1b0376a93ed925248fb2c5bc47d4284832d40fa318b -105000 460580489a262514f5414c1fdc95ef0d8290a23bdca4af93fd226d72ca79bb11 11fedbb936fb27e227c2602d32f688f1d024a5fbc8d31823d273818ed142ae62 -105500 a461d00c1217d40b1774f631ce44e78c974be18cdefc160ec33e865b1c7805d5 24f67d2f822429d89701691d7834c58593be43e7249530a9c1dae9aa12cde4d2 -106000 70b95f002b31d55c7b523451d746df1ea1ab182f4e3d26a6a8146daa6b175f70 f59d284adbc90a549c211187c55814e85b8343c7797ade9c5f761e5b4c5855c8 -106500 5bcd8c94849d744d137dac85d734d893dea9963746e1d5adefc0852cc99c3c66 67b4fb04c0780ac951d84e6779fafa76dae5d46e84ef41cf690cd33392c6f926 -107000 aa50a7001438cb8eab4442c4635453881df972b8707150275fac0867d7254341 9e2451f91358f222b3934b24013be83c1fcc78415c12b4fab2cc5dd8a3d3c36a -107500 f83ed835545b9320da20a1b2961c285adf11dcde168619a3e7e746f93cb93cb3 e27c84ca437850f8aeb0cf3bd1a727caf91808663679f2dfca99f4c676a4cef6 -108000 d9cabd49da35be240bfaf8dc107e13fa3ead3029573f7711c51c874f09e2af83 85f41c365756daf80d25256a132c25ced262eefd77547a42a51603fb98f0fac2 -108500 e6f6bf4d75295e5dfff4f979fb12292736dfa7d4d8a7dc683f6238a4e00caf0d f294a30724f9d9ffcc244995acf528e501f6ffd0840f5ba8ecddbba1d1bbe250 -109000 154e12021e0e5198def8989a1d68326833d020409a76f980e4e41cb1662e0d47 2e486aa0080740653141a5219ef25dc79777d3976bd9fad1a7c7bddc2fae858c -109500 02a8b8fcee9f8a420ad024de30fb8f4b2db683b4f93e37d5a7936728ad1bc1a9 f9c26724d2d6e8398a66e8ac080c8aadfc5155ce4be3521b3ae5aff95fca7541 -110000 587654021f4afef0e863df85d5c48c1da57af439c890cd7c82f57112b523e567 41299bbc731c54c00252ac8506c5671a019c2f24117534a52a6dc243de19e60c -110500 1b144103a2729d255d2c79223dc4804e9ec38bbd07105eda2eda5d350933c8e0 47988c8a2b50a19d5c4cfd5c657b3bdb19848828866e762f5fe40f8ed3b0fc5d -111000 d2dfeee7017ce245109d6fd20d439a58fba318eb0853369ad740a4c7d8cb3679 89d0671f5c51cc5e682fde76759bf130bde74a8c3d0334013165cdc74df67a35 -111500 7bad9ae95d958cfdfe5f6f1ab0692c74023e9676aebf77696f0dd92f272484ee 8711ac67cfc650bcc9a9a3b170896959954dce728667035278b865e843c5f5d2 -112000 aaa6a01ee0e8be04b54950e9fc47308bea161476fd9e5f7d931a9ac7a177c6b1 cfbf8e1b380186cdd7dff5b1775e68857e0144a6cff5c699cda0df8a9b755879 -112500 856c253a4ff511cde2cd1138cc415c15fc4601a9cf20f97a40a3ed5a8e4bd28a 2418313d86bc12dd0b7ae5246d70c5c95ddc342c5f522d33a4faa38677b1cf74 -113000 d39c76ff2213efb6aaf21e1831e8dfd86e82851311214222cacd1065e5f442f5 7027dd65582113bd83834da3b8feb6f5e724156d8653689be02acecf664ed8b5 -113500 072de8c792fb777438dae0fe6605d05f84c05c478cf045595236439ed614c869 66e29b9bcaa1beaa8d901e8227510190b64b665c427147e79fbb03f4c7560df3 -114000 2727f22d9d9b83d232fb91cf7fef9923d998166a632e104da344aa5b2c33f963 afb687e99a9ef1e794a049e78417ff2b0a15bf3c0f0a01b5c04e381dfd3eced0 -114500 fda2f80a90dd787eb236d38096e1f73b7ee1b54d067c53ee62d4201004df7f96 434c6e214b4120e3df23c820dfbf7ecf3facaf2f30b55fcce4dc094d0d052ff3 -115000 f8642fb7ecc176c23e6919e2a5f9a3f69d60c1bf10329e853b94141d7eecec79 02a4953482c2887d0dc4d2980de20cf75b73ec8d81d5b3d6ca6df741a3f3fc7c -115500 96be8c04c6533cf914499dfa780622f64e3362ee67b888c3d187c7cd167c124f d160418c73e78f1f75972ff6fce579d50f936678a03b8e3e2e8eec885c8e7f97 -116000 6efc2af9311adf3ae7cefcd558b25335048a0344d0fcca48f4a8302e0c2f4e4c 5bd32d67887dbdc6482620b347a1ad8eb9c8d124ecf4e6966269a1ee537f7562 -116500 d2fca2b2bf347959eda9a08e76c269d1e00d475d90ed02ec7d5d537e542c648b 9476a9957e44fe4de208e4c707f0b6d1a2c0c0b3a32dabd912707ea86823f62f -117000 5ac65e76af1b75c9aee7eb49b22ff2fee88a1bda49287fc5dc7762b2c5b8768f d357d64072327f9db3d73ea738abdf89f5bd20ed4b56733bc9df37d200b6db39 -117500 3d7e8e1235d8f137cd5661125cc0627dcb3c18945254e9676e21f2a445ab8b9f 0f9c97626569303b76ebbd2cb960341f2297f69ae140cc84a40a83695993605f -118000 be2144efc3b4ccf0d4d3d7b66c5f6ba253d1fff069b89a69f8eb2cc4ff44fe34 9bffc6fa6a4cf35486018721652d5358be0bbeeef8b98398c9373c352cacd4be -118500 58ca03280dfb1e73dfe8ae35f67b60087586b36823e7fcdfb0509bed23c0f9d3 58ce09f4189a7f9263ee9292d7cafb880bb3676175c7553a04e25bc261ca21f8 -119000 907a0fea05eed4572602c76515bfa03d5cc79da72496d41d84afb4ce4098be07 32779d699cd1abba0d653a332f07727b9a2094a4149fb66cb11f16df7c68d34f -119500 ee7317e1516104041197ebb0bba085bb14932972d5bf4ce305a3bacb9ce17dbf 6c779c5b384b94c7649ed90936688e83762407a89643aa89f730c6c399abcade -120000 7105703f4cfd592d639e0b5bf6f2d25380a1787346f24331401eeed04f146130 2a44b6fc864aac66301c1b20def1cafb0704830fb07e2684651513a6f8a89843 -120500 1dc347ca251ff3eda0a459a85d9df212ed27b9e7521bcb8445d5a377e23da48a 3da9eaf002870bd0bc46688093150e254cbc0171abafafacb2c03f6381a532b1 -121000 7b8f755c93b69f842a1f9ab68f67e597f0fce31b94e0cfed7f3847662dd1a401 f175a7b245645b0f769638a6ceeec460e87782994586ff8be749cee06da716a4 -121500 2e5aa2e8bd0b018cc58a7d1cfc18d19903cd57882ed5ae8f2d6eedf72efab59c daa4a0635304dda991bc047ed1e075a9bfce603bd3bc1dcf93da809f82b0c5de -122000 9c662917653809b60484673f8f223f3ccc52f9288b8598b6414bef79181de9aa c8c62e402da8ff36b5833ba9327dd92a501367be811157fca1f0b80ee49a4ef2 -122500 74a15173b1a78cb7e95f220178205db14c5bb67dcc64f8a1e4feb2cb5b2a6e28 f480c746a1436fb843e7f5935f2a8eb79007857b4c110a9348d4391302537110 -123000 38b438bda7e108f97112d984725fab27d277a08b1a72affda99b79654c21e0f7 b1bfac6a48327a4005f79408df343adb7c9cb22d2b70ebf2ad79121cbbfddfde -123500 ec7a4edbed36c3d7a0eb4098e6c6bca397bf08cbc0e0b190a4cfd506df0ac656 7700c27d9c2e7a0360bfa2426fb3688bc8b3ca935de69d15b6dce9ca6b31a4fd -124000 c3d8229a44faa337d05e0b5311a5dda37b91babcf95e5a8ccefbe872af0bd2fa 793481678c778e8653890f1145e178e42effa2ea7f8e50522187ab298ec6b512 -124500 1510db798814caabdc90f2b18282456d1b1be40948ba43fdc68e2da017c2dedd ecd23539bb6699ca362d898cfd6181c49ac97b0d9031538fdc0303cc8441fe9d -125000 82460aef9d1133d30707bd416b3afc2929a388ec8d1431e92699aa625a4cc3e9 8ac7f7dd700d26de62506f88cf117282a7840236bd66aeb148cde751ee3f7dbe -125500 cf883230f6afd44caf802508a9bce39adeae83cfdaea0ca10c5eeb7e6e0f7abd 269f3d0cfa2df454579a4b7bc758970ffb853aaa7600808071ff130b994adfc8 -126000 e36d486bbf7eed518a2a1b1668b516daf85bcfb0359337042bb8c278a5826863 8ebd6563987e0969505718a915e7945f0d26213475be39a4b36ce9928d313935 -126500 41b57270dc8a7fdaef0345502f3ad6ecf8012b680714cf7723aea4c7cb03a864 e422bcde2c4b3e00c42dde121d189205de9acc58be35d92bc590a67fc11b336e -127000 34d5852f2c7ab91f6b7ba43851efe2838a874f1d47e6c41dcf413f263617c4e0 296613313aa18e97281d6dc14419528e0914d61bf8eb26f4ee08105aa358c0d2 -127500 07f471a70c1d559e6fd70d2adf4720987ac72e71d29c4bafd5f78e428aa6dc00 c32efb7a2072cf74b7124a008939f8093f7028259a69d8c9d175e0bb4910f03a -128000 063c53a0e11590d0f370d0a3c2fdb3722c1c91e0203558436fb43b16b06f572b 2cf68c71009f221feec16d73d8ec1b729b0624f854851153bf78146935b69148 -128500 32a9b0507313417fdb97dce6e15852a8a55c80690028759b577723b629ec0234 b2e0756fd80ff838386d84e8d82e2704a52c07e56c10a88fdea969948893b808 -129000 b3dc6186f79ecf8e7d4b2937ddc1ff5372684cf818665a730771a932461fa8b6 6da8856b4177dafa784a25b68c4df9c250a664cc6831c9804403cb021239d03f -129500 1f5e8b0c9c4229ece2580e76e5164e1beb86e165d959cff8d7a0a9f74660505a fc76b8f58cf2fcbf3f2821d871788cf4cfac6e52b0fb0476e96769311865d90c -130000 3052fa9be8c4f5f24f40c5cdf0a8eef8087e08f1d168dde5d1e502960183f137 8d108e91ab41a1057413efa8794611be06459dc53a8d2099457073ba932acb4c -130500 73ed2cd1c1fa06e01c3c6fa4848d31b24564e667e3871ee032a1ae04812c4383 df3d5e20f9ebc94bc84af002cdc9211efbbcabee00cd755653a0cadfe4cf77c3 -131000 f78703a391119a15b5ce6a2a2bebf2988fb164656c968f72359af65852080c1c 8fca74427f6789147cd1e233e020050d9babd0bd6f078ed53f704c6922b5ce3a -131500 e8873601a44048b85d11b25b05c225fa970d4ae14a3a30c0072bcf6459f2d828 140c8f3bdc90be5ca51e7c3179c7b8839afed4458278759a35c4a078ae8cf4e7 -132000 98752c54d7a5238387599ac3a0fe44b3ec462f88eb0c3c6414160ce79c128a14 f82ed570eb9d3c9078ccf41e675c13fcf6e73e6e5bfbc4b6b2c1e4649dbf8a0d -132500 7377043aca01beda7f7d70c6c2a9f59ecec4769cb330c231abf8439f231a6355 3a35dacdff298a95ee0fc61728b4711d99c4d1bd4806dc738c684d2632fd48fd -133000 0d70e8ae76041c02ab65bdd3b0f6a456288532d5447dab7f7e30123b28e16543 d6b3a5ad40a90d26a4b218b8b90852d49f508cde1bb2a23031f64e765d519dbe -133500 37aa235fefa6f62af6e393639361a4109369d0393d66597a3c63736fa5113a02 9c59c20c57628b250fa5757d8d2d55feec38752453f21232141f82c1be4dea63 -134000 2605e14bfe5b9a39a4d01da070c05d9bce4b6453b599a1f6f95d8a6344138edf 1b02cbaad0ab46a737dd848c3db0f111c3fdc248d472636765ede6a6c2389b74 -134500 12cb93a2b1e5ce4d9c6d2266bc6984839271c92f8ac34205dc621da8033af81b 6346ab5cc2bca05485ed517f9e494e1e35e33ab9ce011923c6713dd0bc28fe1c -135000 5d475b01fc5b6a22c775b89914c3b148431956df26fff2631111e9ee7d1ea55e 182dc60ad5a4689e655a00728594807ca659ea3e870a4c71152b220279fda836 -135500 d4b244f6df6c05a1c918ec0c80b4a230c2e40de23847a3c6a48b8706b55191a0 c0ea29271b681e460441fc515fe8af217459716e9116ebfaf9899531e55b9181 -136000 123eb5d144a44b6940cc6194be4ba041c5fd8a5ffb342b5d62d8779605d1fff9 9836476b408a143b336dab7cfcee4c07ddcbf6939fd40267f8315a7d4d576fd4 -136500 c169555d2b59eaf45046d5c3832203dd5109c6e3018504de66fd99242b41d5ad 0884992c307a5b98b026f9885b6c81082aaa18a12ddd0b302fc5e358e313c810 -137000 123d022b5482871c55b3638324b5713e225c6e36ab4f83120d883ddf3c0fbbf0 024aa453462e49f50c55c36736542e4129f56cc81956b74f7c77e90b0e6796cb -137500 3dbdb568d735e6c47c5fb8f459bc448693566ee30140da275f786fffb244901b c0e599ed4901402951a3663d225047e94861817b0a412b01e4c770c9719cfe53 -138000 9dcdb63588c3f9d43ce67bb6da88a144e98b3340eed60478d67941bc1f3e48b0 0c04f84ec720ccb4908774fb474149dc069c8420a53e89e9007dea32d90e380e -138500 918f3566304f92ee937b50939e5224bcefce1b61503b8cf5c75cddd293115037 345d16e0d5aa525aeef890c1cd118edb3d1e6bf784e9445aad720dadc3408667 -139000 5a5cd26abe8d7b66b82dc847fe582d00c1aedf51bb747cda126f35d177df3780 b11a4c12939538a057f35a15f561da8ad09ce4ec33a1b6b965e6c35d7f6da935 -139500 883ccc866e98513c10d46ce62ffc4b2f52914f9d3c77835ea88b2d772647098b ae7d18414cffeb5073a788005a70e1e80b3c04abc1726101177509d0872ef2a7 -140000 0d53fc7a730aab5b7751832647af30f6ae6de5f66a26aec228c9642132460c09 d157b0bf7301f4c28143ea0266a95c92a05a3499dac2ab929d57ab75b2be499f -140500 b67b7cad6c800acd1fa41cad0e075a544368d679d03d620f5cee45cd966b61ee eec57bbe03beb832a99ab0bc6b77817e6bc459e365367b09fbcb905f3edfa85e -141000 68756fe78e60cc7191d62c387eeccd0030ea6a67d4b1fb6667c068c5dbe20d53 113007738fdc702b03dc17993f916d40e24e88d12a95726aef18156355990d7a -141500 12aa3f916704a9120c99c22977c22b16bfb670c9e9d2807e0cadc444c9e8d02b e7dc3dcc436c770ba20dcbc3f4f762b7ab343fdb180e867b3f3db34f8b279871 -142000 629495f161c45d033130f52a4df5e06cf5f705842039b89c3d499aa658ce5a6d 865d4be2b339178a44d8d9ac4a53abc6b4f710b723583053f23b73c0dabd77b0 -142500 941a5dbf034317971407a4743fe1c5cf11ae87be184fe4e7749e2d32632deed5 d8d4c2edb8362a39b9ef8b2693e1b4ed597a9b315e60e424e26797ac5266f353 -143000 b8ac8abfe7b81372299d2a8be307e13786a5aeb4c3a671c8ae45d32f4bba9281 8d7e1ac28129b56b0ee93dc931e54293f181d3aa253e844d1807d47b31193f56 -143500 610bc499b94eb7e00d1aae8388937087aa421bfa9cfa70baf798b8f97e1b23d6 e990d00ff71509c232b43bde64c749bb1fe597e52e40116893e02937c7943b1d -144000 58ab7580eef5d40c0ec3d7ac52425ad5afcbccac834192fe71ec5a1d15cd4ed7 d9194f449db3d58a1784cdda50ca32d4212d43a12e85c6ad9f8b77687ca04a6f -144500 9a49c8d5f6b072b617ff80d4b70116bf3db461f9fdf283009cd9e9b2c2df0925 a2921c9b5ac78ceb49666c487d217ec303b1f5347d6902baca9b8e3779774c5f -145000 29f1fe68b8289b62a4eaabaec5abe811c61b6f2220dd15f04bf3d2ed3f98ba02 8d3672fa9d6c4767e8d3819f09a9bfdeb98a6f35b83f01faf1f7b85c6871118a -145500 677d2c090d3beb31d1e611e42801e75fd3e2004e10ba8ef1cbbad5e2b17eb02d 93a4cedb34458ef8b90ee740a6b19364f5ba6c0096a16142929987d2386358f6 -146000 b85efd80a2171505e8e2a83feb7f7d12e3793fa4ed2999d7b6148a1673e574e7 c76311a2cba2713e1e7706f71e22abd117ec5c45d7463bd7cf9baa7734468c79 -146500 f1dec5d905557b23d644829ceb4f9de311a05ea717740e9103d155157e4d1354 3764ee8b0d6ae8dc762a3b43d012eea45e1e5c1008e90403ba84549502c3b62d -147000 1e59d25367fe453ea1e39d7f0c870f14bc37e99ae2899a6f0e67dc8ca110804e 238df05f6e2a851137fb165117f2feb458487307ae95d0683bc85fa748cea31c -147500 4547d35c4821dd671dd3d4d99fce894d455c083985eeaff26531187f54349bd4 13f4a0105947e707604293a632917b8b93caeb00c02a28668a9559de36e5822e -148000 f50a828d973baaefd78a069efcbc42389c7a9d0e17cf4476d6bff763d3b219a7 7d057f6f26c87ead3d5a3bd63b23ad81ba5a9a84258b46921f27f07919be82cc -148500 219d8ce760106e41d5b6cb72360801884950e795cb80c5cb75a4cbee7c9884cc 66abe4202adfd1c91b092dc15dcd702b0e383c2a9a87dad84efc20f2391d6024 -149000 e13e98351891f9940b40210188016098d67d555ee60922bd710d234393583886 2751b92f77148b0b55b15c1e1939f566749d8bd28b70f9fa9445d5c66b116a4c -149500 bd0986d58541fe55bc5615de06174615007bb0a4e9b7d52a6e1de27660ff5e1c 075df9893a744f62bc60e850104f6ad60764b8098a18f89eba4418789bbb7c6b -150000 b0a52b599b482e9e081373c2d0c12adae59742c92c3feb16f2b56a536389c566 2b66e1c89afb06043357c8a702e15f37c6cebfe2c3ac2e2994b387b111852c2c -150500 348a90e69dee425ca95455f04bb8e0a9a5e8e4c9efc06e8358e90069f33cbd87 6296399a3fc3e48c09ff1bfda646b6f19277f2c2562c8cac5c850d691b2c2110 -151000 c2fc138fb4f13487c8f0ba65b1843cbcbfef598d66205495ce12eded834ed5d6 6b3d49e0f596367b951b6939dae4629d81758a560d8bbee402b4258fe3896e18 -151500 f22af8f0a616af674ee4e07e5821c6ae1ba54d431200daaf39362d203283af2e 8c445485555c915933539ad6c8ec776b65480a6b6100cc2f2355af041d37ae9c -152000 ffb05330a4e59f90c081b821c1cc26def98eaade28aa6fa36688c9c9ec2a0ea4 7c94c4bbaec72efc42d8c00f50f777d09fd0bf0c71475a31183bc391038e4fa1 -152500 b7c7e8aa6953c0ad15cc9b003dea50f9f8bc08d8c8ffcbb287918a9e570affbd 16591b434c6436280873b7b1d81157359b67969455cab02fcbf7ed9dec87e64b -153000 fef11d21d57c34ca41af06608c09e6d0a1623e6970123e654a81959089913630 0683353ede70fecca1f5f072916105b0fe941d24b2744dced890e2d4cc114356 -153500 0decdb908b6c897fd269156ef088ea6c5c76ad98cae97cdab6b9958fa458c4f1 458fa9b12274e81b31d551966d7992d6304bd3486a76d9e484af250b4d725e83 -154000 8e921a4716e55e2c03536ace904f1b76f2e1c1f44eb1efc293e819619fc64a6f 9f3faf97a3d07baee0cab898c7e2c16e1e75cb08b8593b30897f9290e7564464 -154500 b2ab747c57f1e073712e5c7c63d14e427e4c5aecb70c749d686ae6740eaccdd0 5b6d69da753ccb8fc0e7cc323bc544e272b607f0fcd7ecd3afc27fa454bb13c1 -155000 4a27f6a366c137b5b0d9a7864ad6ae3aa2aa4f92fd96afad203f9750743d1b25 5618bbb8a52a4a6523d7b79f9da38af51c38ec0b250918f9fe13df1f5ca4cded -155500 44de83681d8bcc4a775141039552a3bc94ae7150ba6cccb0eb51d12f67cfd3db 526775b79eb1e6f88bf7b11c21c21cd3de6b70c591b146f75dd6f7dfb25d8258 -156000 fd67b25d5f2f9e33e0717ef2eb6f7a8b61c0e369d1bb27d363c2fffec6934c6f 069fcfe28f96738efe2241bd5c46e5f9dc2568399dedf97a3b222e7db1f8d479 -156500 e4ccbec221374ecbbed5f7515a62ab145566ca98f91fca6e9e9e5faa5a302e1f 0138154cbb27aeafb8785898175459b8fad1a50e5526745da4f3e3fce73906ea -157000 7931d577b76d43c21d638b392ce9e89deb30440d5965bdeeff5ddca528b23f8e 2b3023999ab4fa8af216fc6fcd1b74a6d9b91805c25286b3a9b5c21d111bd929 -157500 5a785cae6668099aa3bba0aced796a2efd3f32357d5cda07964c38bbb8547f11 92fa0afcea0018aa72753e44978b29517c44b86583a7e7293bf41d0fc52adc33 -158000 215585110369813d5c23324bba75c2fba77a3cbbb8074822747d1d5f7a54459e c2bcfd99aadb46819152e678172eca6ea41d068cb9c3644effd3da1d90fdb6d9 -158500 33ea7e9a89e3e620f7622a67f945e6a84caab88f8df84416920e34611183a012 fe4a8ca54ee30957c1c4ff378addca94aa3c2faa44d6dff2c90aa740c94f322f -159000 5dac31f23e99492315f0ec0395c5913a197ecc6bfa5a1f1c38fcbbce10f5b2b1 3f33701f476adc2de539a516353507c2319ee322415cbe2d2a81d25579320df7 -159500 e49f3c6d819ba98b65a07f3e2b4cbd4ed74f8f352ddcc5b29cf715870ffc96b6 8d4baf5eb4e709a1749ffab123eae1c16c84c08c2b10c1bf35b904214b55622d -160000 4ffcbf8641b4b794fe4e304f3e33f8b252b45c99d647e26c174830811d5214f4 d9feccb9318af01dda19ac1b834e8aba8f1a31b7e3c0c874c2340e5f963099f5 -160500 940e235e254ce7e8c7884b846860faa5a7f8fe08fd7d05bedf60a178b294bbc2 4c96d0c1b2293677ff55acaca052f84941b801d35426f5f6fdd0985a772e140b -161000 49a2fe7b8f78e83709f195d11f092cd5bf6756dfbea8b61f6ad4acca38e0f433 c61985a4419ef741b3255effd2490b3959d9a37b9fa458a01e314acf2cd110c5 -161500 adf7a049b0055137358e82ff4cd0b223d4f1e65a99cd9427eb8892e9b3956546 f2ea625ab6cfbd295435c3e70fc60ca04f444e88a9951351519c27066044094c -162000 78eb9152a6249d26cfb9acccd3be7692835f61a70f9c4dbca7dbce97e8eaef29 92bb404d3deec9249fdb8e8b0c11e1e6ffccdce4f6b76e49185e0e0aa6480b30 -162500 f0016f65cfe29b53a443c3117392b631edda432fb508e67f537158d939bd24f9 7da855957173b1caef3a5be9882b88d6be2feb3860bc528822ac203df9480ef7 -163000 16310f334b323b1c422388a77287e590286b436eb1d54c99a7dce533febad9d1 50b8d182a094d5709040d1f8be2ed7aff41c50d3dfb49b6474ed04c7563a2afc -163500 54529c58d723c981aa51c3bf7202246d09e30d6bcc22b28929b2bc80b970a46f 81722de9f999145ae10c5a72cb03be616a2c631f6239f01243836ceaadb219d8 -164000 135d6c860f9cd670d82153e8e37e5202b6b1632cc35280c0210587f4cb4d8f49 c5bf964eb82fb51d1f5a4507bc2c9d658ae2f868cd517674ee1d81266971aef7 -164500 08495f35f925470863e7dfb79ec17bd61029899bad972ca0e5bdb0512a0ad908 8901ac98fdcdd833938280eb495214ec81269d8ee99e0c10886b9184b0aa9d26 -165000 5178c8e3106c700a225efb2d7453be3a94616e980fae5a532c0a9fd103aeaaab a71b7ee462788bdcf6b6945da2a2b426770bb4e31c7063db4b9c80f82ca88af7 -165500 3d1e48c8657aa62207f24888630361eb85ea3f8225e65deab240e5a242fcc463 b16e47a7ad5a208fe467efb2f7a2aba78cccc41dbcdfde571ded9b033b2c660b -166000 2a5df181ba84755d4893b8af164abc28ba9d67f0fbf70a9fe44f78202c19e78d 6382ac5c3033076f67f758d9d4a66006b6c67983e46eb4488b8482e5d020cc7f -166500 f33bbe1188c265e4f52649d90a9c853742c89348276119166d9dfb5b0a1c1d1c bc724795f0704caf13beea8188647ee2d0d8c05593cff788541d1f694f02e7df -167000 278a49c7367096b101da81aeed3a9b3763b9087446e3f3eb7d279bbb180ccd1a c90bba777861cff1db1ef3cd40e240a74bdbeaa23e2d4716dff0700608431547 -167500 de103832de75b420ee01b8eb238c7e5ab2fc2895848f1fb934bc0979af54ee3d 5263039373a72cea915df57bc9369aa15e7dd2ca6c3b6df27938d5240ef4cd8f -168000 c347ff8a9e0c4297f74db5943de2edcda14652f1e707b0d789878424b0f50555 fd732e674ea0cc59454e599365d9526a135a67ee82a1e54460f90b934957f9cf -168500 7c4bd55cdd16268ac7da91c44a5c204519aad6dc79a173d65227995d8f480ca4 66e715d9afc7e37855c6f1436bb3344b440a7db44fe5163f2674b542a3a8affe -169000 8d8295fb630e487b21d46f82e5e0bb95d667635b1c0cde080e9965ea021f0d3d 32309e6dc4e7812fe36a3e9f14079eb2f9a04dd910965a631f76fb23f29f2c5c -169500 3ff4f89571d4b7f8e2b25a761e2b03dbe82d9d2acc565c8f06f8e61b7b84a48a d71ea82c1b352917a9a60feeb3ea40f35447c58909a0832d17451458c4a0a079 -170000 e4612c319a4c8cda00c8853428e0c57c4c688d9c7ed0ebe3adb4ea410066230a 2428df1325dedaad3c6c2e18ba57184348603cb4e5d4fad961d9f66a33e8d4c5 -170500 38f6d4c55c456c85b59d965db3386f3bebc9f3ffc101703667c9ada2c6f110fd 7fec7fc3f24c1f7e635e06427d949e9244c3383ae8a1cbe5ff92c20318d1b303 -171000 fa2d2abf42e47345b9b06ab4f0dbcb6d818815b383959b5b0f69a207e755ae18 6943c6e99feadbcc5f22d2000b715e609874953a2f6b06ab18c6f6fe0d9ead08 -171500 b269e08b7b8fcfaacc4cb1cdc39bea13237265f03eeea6df488039715959d60d f978606a7a355e240373d149a0bf3b2a80d735371506f6d83a7eaf2a05f6a300 -172000 c1ff70cb404b9a3f97513e00fe8d713ffc5a1ea49b29be1480dfd3b0e4410d1b f2d46aa05b23a697e347a4260c9d14b51e08af5108bf22123b820a54c73c3fe0 -172500 6af8406f49ba05570e46ebbea295e07ff856de60f7f7a85f29ccdf0483deb414 2bfa8eaf8be3fde78ec35b8bc4ec1274cd089732617255d9b1450f676d359631 -173000 4187e88e79ee333c661955addb9fd1ff4853bccda1c1f73585fbc4b866d46ffc 2c561a6112ac2531467818ef79bda7fd294cc2d1aca8d700ffaa8ca3c7e2cabb -173500 979cd0755a559b4298c4e1af1ca1ed389c152f6800718aee777431e3b84b2975 817578adb3539145804a17166425c07a798bedb2637e8e6567e77406da8cbab2 -174000 84e476b10a846c1f76cd25ee8721aa8098a3a794f56a5a6e2fa8ea08dd7de954 7e3015ed948fc061ef3955ff4d18f5c9f2ccd86794be959d5e51e604c4ba315f -174500 daef6a8cec458daee2a97f145d74867790d12697f424e390fa5ea96c0edc5889 8edfed33a6db9e18b19b49a451c2278d0df8c17b86a5be2703336ad41ddecdb7 -175000 3f6c5c68d024c26235bb054fe0e892b4172a50c900ff7e36a061b17bb4adb44c f36837bd4b44bb99bc4a99acdc71611e6bbfef26095aad173d5b6c2847cf5cfe -175500 2a25fd32974c49ec621f4256e89f3c1569734a675bfde35fe0ec4572459a99ce 0de2de8ab8f49f684a4ed93762fad169165b9f29306fddcce37a10b3e0f324b6 -176000 ca43896b57242e50c5e1b0904b12b7008d63f30810c9d1728929a45a051b1c28 0c0a240dbb5b8d9c5303c2e401b1a9be3eb940a2ccdbd40482b18ebd9d16fdc2 -176500 01bd824255da4562af0cfe656645a2e644bedd67f5c4c2266e9d706d724f77c3 c1c8c3eefcd2a0dd893ec58a59d9b4b9fca2456b4ebfa118caf122316ec1758d -177000 1931b94a1d1731ee2fb2b959098279a73f2938815dabb1689c98ca64ca265eb3 9ecec3dcc0f626eff5310a338ac6ec36e52cde0e31dd2668510985504dec6b76 -177500 d5e641f50d45b9d3c2f81c255fab7812b79d778bfbf3acc3a905255009efabb7 780102c55e6488511505df92213d370484505fcc63e36844adb4e55e28b11891 -178000 41dc7c791cea13b0c22c556ecf0b9c43bcabfe110cda05fdffc9a213d07878bd f502dfc4f8e1e754fb19789de0195d3f76515af97df6f6a4dff9af35e9e64cc2 -178500 86fd0e05f7c975edd10fa04040fcfc06aa5988f25a24dc475468023fb5ba60d5 9a9d5b0da31bb391cfadb78b79de03e6d2f9356b6e8f2a6b6f3561718607666b -179000 9f87f2c50cac2bf6596533b242692ac06dd59688c85711dd3075556a42b5a51f 62c5b9a2f74642239aa89a9468c1959af35f4218d16ae1c0e22879ce5aea14fb -179500 2802d26be7d5a8dfa0e84d507569ab54eb2815addf1363e844143d4d1949aae3 04a66a42a874e8a94de4b35e0fe5b2415e2806089e62b0ce867206a3bbeec923 -180000 fc0f88ce08e8dfefa8774c7b9e101f82f4c7928aac246233b5d97b178ea1e8c8 d2cb3429b3bb7ca9c4bdbffed735f779979900ec989687ff9563819b3f340a40 -180500 55068efb221561b62da4c6cd3933963165b99679274f0a18b57e12a0f59c02bc f4a3a53f8756a0f1ab9f0dde456df65f68b487f452e35119a395990224589672 -181000 87c0badaa9ad1ee338a1e0bee51f0e5d95eeb69b608604b687e1b75cfe28b1fc 55c6a1f3d35e1ba2c56261370b991094f37b2e0c94c585c83c91ceb0e66b4205 -181500 0223e4ac4db7cb7aca8c5dbcccf4dd6d67c261e158579465c830d00f0b2065a4 1523b5a7b17c5f0a487b27b05911b0b023b7b70c1e93a676178193e10dee764d -182000 3bd580fcde83b72980a98de1bd2bc33f5d2e5260a45b2025f8993ff148006fc8 b5867c690edbe8ebe6938bc93774d516dc0de5a71a28b48539e4029162825354 -182500 d5ed6e8efecd96800b30644154dbaef8704783309362f9cdba26c757fcad2d70 f64f64d8652b12527197f54411334ba0ba66f2515e4c99281a075d1df597c8b3 -183000 e926c6476da9f0d3fd84aec136e029881901667ff07d80ecd1e6e6e4a1e78979 e74160bd9ff069b6511c0602a1c72fc61dddb22899f805cd9c2c0be184848033 -183500 5bde7c982564b58b9d46d8208922b3ae8cd1d50f2f68c7a4a8d71e636b66181f 00d016a3247ef22887c0909dc0a7370c62bb2601b09425bfbcd93f782e1466a1 -184000 f1cecf410b8d9f5cecd6bf19ddb1c7157cdc5c42e110a42596620d9b54216dbb ca3d938eed902785feee39efcc9a60f26ba5a53ef969f174ffc7f44dbe544bfc -184500 89d6e5e381ea4c429428a773caa457945d6e5986e77830699d64ca84b6b7cfde 30e5fef97c937baabf267183b5f8bc9de88eb72b00c204abf6db1962ad1e1f0b -185000 d55dfc02a7dc5e64f615b9821e7738cc3f4b1cea50e291834b3d950457c0befa 3976b8fa6d5486bb07e4f6a5a63f200089781bc8c347f858bcd2d4a8eb4ebc7b -185500 b74792db4244be3b16341cd6bb1af5c7a9b71df58b812691901a59e2e6889f8b 4523193666a8f6eab2f73949efa94fd98d9ac8821ffec1c8069abfb1dca83b0f -186000 673e42a71dc7428d516a2bd892f5bba9740deb4a8e7100afbb0db70de4432d4b 54bb7fcf882d25f7e4cc19b41bd13e44d70c04d31a6b4e2ddc388b6ebc0b1818 -186500 ac9d112147478ad6096daea4f3b9b76912367605cfb6ac68a5951478787d84a5 7e112c5297f3521039d52a994be89b1dc3b6387b4be5398d7673542df3db0945 -187000 b06838fe81d8bc39304fd98dc9f24ebdc0e6a05a363713e028382d77334c2afe 53c32d4af24bd19d1dda8c23186b6cbad5cfbaa6ee169666de3b028473f3d388 -187500 c3f730a1d3977c557401a7ba920f22b768e9e89924a07598af8f6dc0930a4585 a83e748dec264dcc6494d6ef7c63025e554aea410915c25db93249088c287442 -188000 4a74ac7ebe38798b80ff54f21a428c40915895bc44a528bd8e4ac3b9f378def9 847a11b8eb71e0b5dd698b277fbcbbfae9c54e55477320396a602a26b1f73d8d -188500 59891ac998632472cdca935fa4a3819fc676d23702621f0c41d6d38fb9e354a0 4393d0b0d5af19f6c123777762a186fd30666e8498fd76468c3cf928b4e6fe1a -189000 7c43d2b882946af37b0d1b1e0b3c08a8c55e83b9d93e0d3c10ecd3ac7a49c1c9 0a5758bf838434644aedcccdb7905d4bcbd576745f82e53ef74c9539b9c95cd0 -189500 4913cd6821bb3900bb012df98da308582c7f99c8907d1dcbde5caeeb04ba1abe 83dd01f4f3544a1254fb7b6c1fd8654a10b4ed99581b1058c79ff2a3a08b3ab7 -190000 825d6842d16dafb7b6d3fff172fd176916478e6a14c50efca5e2b6990f7c2299 0d7f3744d4e18d9132d3bf7e94b9325900ad8a574c6a48b04e6594f2ed07083c -190500 b7dbfde08c23efe184956485d0c19d62325d121b493560ebb0d45321b1832b38 227eab03ea5949234a281ae85657bb5fa39b271fa2218e294c4dade8273639eb -191000 e61629b5f59b130b4e6fbe4d3aa8027d13aafd890ac3a16b1ffeb1d3f590bc5e 7736329d7fc7d226fbce139fd58d1b21a41381b442fd62f1d03bc53b5580f906 -191500 06e8304e59c8f386db5f89bbbf524959e5674c1f560121ee65e04b5902833f98 5e099e60aa5f56a39831962822390e897947b435b4b84cc2f45a1e98319aeac3 -192000 7a94bca1896611bedd44c28323897ac0b065d2832d36000b51da6d8da42ba38e 640f07390bf420c0f65d0b59112d66b148df416f2a139f961bee379df0928bd7 -192500 23a1270346e2cd8b1439b2357aa6d9967285d727963656385edad740cd66922c fe551350fefafd463b3d5f47a53ab239b346bebeaca875c6c7a87d42ba976bf2 -193000 5c7ee526691d558d00b30f649c4f77ca4c595742f23e389ead78633f8ce2dd35 68a041f99854b2ea4ae5bec9b030b48ef9edb3aa89a144bad9c7e744b234d409 -193500 d03957be53c5a92ade2f6caa1e1999c3dfb567084580cfc618fc7bbc6758fc1a e218bdc4ec703cc01b2ec52b860b2bc0ad51b90087088c9cc0e58736d625de91 -194000 d50b3435b1f5fe763970370fe9fba1f0a5af9e9a9abe295e1e61d8832b43ffe0 6f3878f181e0dadfd1dafc8b2e75c73c6ae0fbf97a6bd1894b20aa93139cfd80 -194500 43f28b5c1af708ef1725ae8b0e4542dc6c6f33585455e6763038d93b37992cf5 6792e3e7d2ee64a48ec47e9fb86823aa726ac49948e3843d43ef80995a4ba7e3 -195000 27deca29e0f720fa505c64794b7904c2f15e2b2bdd539f6066bdbfa8b9cb16ae 53d423505456177cb9e6e39879e51b1a473abc363a6df7025d6c523f71fe10aa -195500 4996255d3fc243ca9b29ed6f5e7cb2799330bcf2c11e42ce9a82c017fa4dc47d 1ee2de24a628d83a4a9b796d5f3c6c65d0327202191554d0362ceb1418904a26 -196000 c3861c14add9fd9665a1751e1bee488a13e0156bbd37013e3e6a8da54da26550 4da431d08df43f875267b70903b275831281c28902749fefd4bbe544989a910a -196500 9e85e9ce7c9f969af748556cb124ec97c581e6ed8367c4c44e8b9b12d5495ea9 14f7254f9bf3d122eadff425ddb06f86c16c4a4954bcadb5e99ba6ea78f8f0f1 -197000 387b990115d39fb36240de77081a933eb7d4f8ae20cd72f0dcc162c496717a4e 69c3b4cee6ad5d2d315e2b133a716b8640b170a0f5ea53269343bf4455a886f9 -197500 0db48271823bfbbb62c8d9bb68a0ff7f46724dd251ceb8244253418b3089060e 0c2cf4682db25fe743e7e2781ecedaa243dda4d9944edd9d1aec7a9e93b831df -198000 c65104e71ac22bf228691460ed6036046fb091eed1059ce756e1056bf149148b 3c3f1f86ad2cd5cea8a979c55d01fe3dfcd5d6ec6fe485c3461d65604ad4adc0 -198500 30e8c038e2a43c5ddc9e0f3a030070380cbb09e577ed7d783b83651df9ad5015 dd0bd23d500ed9eb599249629cf07236244c001e0517c93dbe6debe262e7f4ee -199000 4b4e61aa4eec7a39dd94aae2c114994fe32185c72050d3908b7fc0860d41458e 0443985e3352c7ec9e83fc34187460671679f71a3eff263956dfdb306f4e518b -199500 09e62ab674ae8526370e0059097c80cbf382fa098e67d4a1175bada96d5d87a1 b78d27bf65267b4e1e7298efed4270582f8c9e26d53af59d73250d4862ca4968 -200000 cd9a04e20b651dcc4518ae71ff5b0c8bc2ed5c6eb3d5fd2196b1e636987c3a95 6160d970d27a8f799d74d3e01630761bd655268486a9107be28b128fbbc9dbe6 -200500 03609721a5de60ab9175d5cf5b9dc444f8c9d420b94814be90e39e4d5411f33a f1625e3d9d93f152c9e351928677f1e8cbca9c6812473c759de6216321fbfe53 -201000 f1be5c8c40f967dc2f1448f38a7e7e6a47c6d7e6ae9eae150762642394644f19 562f88889f723e4c4d2a7b0f8b0eed383db6aa34c8e094f88238526206af125a -201500 668f7b1463226ffe529002e0dd28b813c68396ed381a5725d166691660a0383c 0077ebac17ba34e5d77c492ce62473602d1010d21a99380380dcf52f1a6a3318 -202000 60ea6173bbe62b24b704cfe2b6e1d1995dc8854d618fb0e42e0c712110b70e50 aa3b08fccaff9887aed03778827f73871a658dfae6ad99b7521142cdf8e86dd0 -202500 6de298a7a2fa7ce5bba344237129f982b1071969df56c15d0ca2c0fa39f9c1c7 dedfea5340d820409423688ebf7c236cbead8e502dcb39af7686681b1f4cdea2 -203000 0e117900e8f0bc91b0279b83445b8d9cebb374dd81c84a52f0b3e6b94c880e1c 74c1495fb1f720209dadc85404e75bde143a59c7d21ecac61204734dacf63545 -203500 ee347878394b9da8a6c11dcad54882196eb1a6acd7e323154167e764d57f00b5 6ef1bef22de744dcac118ba398ca60424a713140fbb76fe0555f1e89369458b1 -204000 a687e4d0cdb3eb142d1acaed94b80625e8d9a9d472545ed1dec3c5e966db98b7 728306e941f0ebde00511bfc3a30e50cbf283e1850ad4145f2697671f14c5775 -204500 c813ad2efcaa352e786ef9dc912e133bb1f32fe408a54c114152223fa3c4e96a fefab4b9604535559292b1b31c4996dd815f25a8ac474cf8bc31d0c176aba97b -205000 b67beac20c8c3dc2e07c7d88d8bd4922b8803da3a5cbaec8c8b0a6601314df69 88197fef17e17da657552b7cc5ea2e09377fc466d37dbc22ff8a948509057d63 -205500 0937f7527f96ec479765e3be263f25130d7898056813dfdc67f3f95f4923f2c8 716b95c3c62dce9b236cba23dfd9dd3fcc68cd41cbe9d13d6f8349503fdc3827 -206000 aaa70022052f41b2195c68a4c77c11b78e1a8136f03477d310a57ffdcdf835d2 dd9991c1a086391127322eec9667bc193908aa869a012b36f0968270c8c679a0 -206500 7724e797f7f8e157fe2292c5a76a018278bd7bb95924932df289d975c4191c6d dbe2029b6398ed4f32b906956006915345255bfac82ddcd79e44848574c50d36 -207000 3d779550ba9dcc4e29106cfbd2efd9b22340432345c0df139ab31eac25a45226 cbe3c2dd884e9ed7a1dae427c3d475a8c9f3c8803d0f3507398b92a6cf5ddb96 -207500 5484677fb6f857f8009fe0e371280b61ba15d0a5fac08bad41392dec1f38c85a 649c2c9faebadeb93551828d590b757b444b6a54b40298519e5aa8505fd81009 -208000 cf31a458b286a4f77890e65d02cc506bb0454be9f373a1685f2f6b2b91a76207 22e9abf8f61d55f7fd7b85e0efa3d8a0f6579f43020b19cbe921a79d0122000d -208500 4fd3fc158e9219659c7ceea1c4f02bb89563c7524e9b8e9f158b61bc82c52881 4a0ec89610a1cbe8193dc195991742ac08583b9c86f9d24a5b63241f8da4b476 -209000 d54f4d0b5a8ce4ee97d0ef4cb455ac54b93b0092e177f1532e6513052439e9fd 59a0a1d9ca71393c4e4271d8d1ea63d8f0fa6e8388c610fe4bfe8362dc0fb231 -209500 14e2bf16398fc52492652cc0ef3fd516eaffaf2cc3b7f89e37f3bce63d1117de d9a9a12a655ef80cc830f766200a05617bb235555e7cea98818bf103a3a6c1ab -210000 4e035fb68e9d78b953e76e14a90355fa127db686af2bed4bdb301fc3223c322a f6916044d1b6a16eb726cbd05a2e900f5b9f828625c850cccb699327c22037ba -210500 e9ad24df7fe871c7a87de17e0c091b99a332b47903d8d39da2a18ccafe02dc1f f2cb48175161b22cf3369f59e67941f77675c6109590ad622a4bc476364043a4 -211000 21fc2c297b7bb7c088668fa502215ac26b2ded973796765acc4feaf2bff112a9 e21b83547b49382c15c8fdb2929711d49eb8693d08c0738813df68c359fa2442 -211500 a83b2da994898b752271b844f26d88d300646e04c4e89786f24fb4c7397ce6fd 4d8d8b7364ca603e61da4d09bc9c0b1dbc2373e65f5db2297828aec6395b5991 -212000 ab0f9dd7169c2b902f4762fce10983fe94e3c349353e189a510781244d66b77a 3ba1a0d61a8b8a750cebf79f5c00362bf3c909f11725bc9e9762f21de08a7945 -212500 b1fb4ee2f329a5664e6be5c85834dd79452b1f89551d599a70852bf49daec183 d9143da167a6553a85f452745577ee6ef19fd21565b09ed5fa6cdc00a0f01a49 -213000 dc4c87ea7c60026a65104a0d8a04e5540e3952df79a62e59deebfef6ae235e81 8da8a14d3971436306dba00351d265f0bd06b1f59005f94336aea44880498b5d -213500 2466c2e233db8e30bce3d5ba87f694c3095fd391b6c38c2edf907a4f97d498eb c3f5734faaf87bcaa9be69122a144ad1f26009d8fce1f859a17c2fd4bc0c2c0c -214000 fa84d9bd1c6575cabfcec73e1834d129821b6a94d7814d15d038239cbc4a568e bd1413d32f7719df41ee9caf406a30c8b97e2f875efe7c9ab2fc56555136b5d5 -214500 556dbda0caa051476bf896fab40e8854a166c7bc416d5f3121fe1d312369dd0c 4e5d7dafa56fbb04283e8c41e18697dac7beddc742d098bfb87d4df1fe90679a -215000 b7ccb76ed29ea49301f630ca5e9cf200ba7a9388156304636814ba6a6b417265 8392386752e5ac61b9856b95e9c833b57fbbc5717e93f63e3944676202df04e0 -215500 a56a071a789afd22ee4a9e4abcebd695a26ff824a895f5291ab639336d609bcf 6dcf6a9b561236f8f627cd567d937ca4d7e6e9df72d466fcbcb505af9bf1ab11 -216000 0e1a9b2d055f2e7b637d9fdeb778c040967a8a2fbe0a38ee57bce4e8f4bb0a51 c5532c221b5cba08f4ca281a247e98d28654b934c8595e57873232111c347ecd -216500 9890c0ab7b427bfa46ae90fda04503f1b17a2493c7b36f12fccf0dc010d3f9da 24ba34ff5619c38e4dc516e815af584f4c5ae6518a57918aedb59403a3b356de -217000 b282a7dbf2dfcfa4a46938422e557404ddcdf11509053fae49f5add5dd101d8c 645bf6456c36a43bef5c217fd00b1e457ae136d52396e504db5ed9a97e406594 -217500 9539ac7cca0ca0524060e3fb6ee956d28ba115c7ae3f54d5927492d0a43eb49d 21f680a60447675216989ea718c68c63361fab5615c683a7f047960d50ff8873 -218000 dd15ae9a3a001651303c757cdfa162b252b9aea2d1c4fcac645cfbc1d7dcbd7f 78cd6e280ca819c264e6447e6cb93c616f0bd03547259a0f23ae38234e907dbd -218500 6455bdb4441ac37e8f0d04b645fc033010698430944a873c2c097f7c0d3a02bf 466f4eda729538e0604472f6c00c4f7398a28c9e59c89602716f611ed8731edc -219000 a8944486d2a12285430d1764ccfa03bfed013dbff38ff5fada97148b883db9f3 5e8d4e1d9d6b8bcfdb3ca94ef5d0f8c75b9620b7bb5f360d8172e1becad9353e -219500 adad89636c4dbae0dc680326d95d5a2bec6ffe7baf704f26889730681328b3e8 d17aeaafa2e7a17d6aaabe48e88ffc53a8e61bca58de2e844fade3461f4931e1 -220000 69fc4cb8e3103151a20add15fcd55a9ee3c1f2cf78ed3bf9ddcd0692b78c2a71 25cbfeac28f67981d5d011357c01ad82e097c0d09e77f0746fb11a93329c6958 -220500 fb7731f8712f081c1e9f446217bc1882d62d3db40bbe2711a25654e2e74c6cb0 796240f85e38b57a751b19d648938d9f8f66cc8cd2e8611635832cec8d25179c -221000 488df413aeead90e34c182fe75cd71227be759865df577cc6a4508cda9f13213 bce1bde7cca72a43d9d80b03ea33c845799313914905c7800f7672654821a7a5 -221500 84d958c341c484ca8e85984cbdf5ea436fc1564c95baac52ec00e9f03d5dda3c c493d1eeb83f8dad5c17eec83e69277fc98e519c639d3c892faee2d6f80a5fe7 -222000 24f8be00386b9a38f5507e77e72cea34598910fb8aeb57c5d7fd5b8b082b1d16 77d77f3bc606ba0a8ac17dacf2d6d794bf655c58709a5e6affb1c2238149fe94 -222500 c9db027d5a71c17a32dfd7694775edd913f829900532a36cc673168de4b41cd1 c98ee6b634235506cd78e47c3c51ff7f20e2da5be5bc51c9269e0585a77f344a -223000 2491331dde706d72557719b2d51300a41185e0a231600a748cadf6d76cb97be2 f464bf83372078d78b37b0aab9e98a697eb07bca9eb62d65919635d9a62c29f6 -223500 757897eb0ef5db6fac3a16b4167e73ac300fdf2126d175ddbfab527fe72e5cc6 8033074e1db6b73e123b62aebd8983887d50385f70770bec207b628e9c945425 -224000 b07c519e796e7ca9ecf620e6437128ea8762b00f16ffb3f2ee2abd5973fc3b21 eb8135fbce4a5f3d73713eb67416be84d02239e85bf87dccd22763075438c693 -224500 4a873566e5cb9ef793cee37c09f7bc11668091934776eaf0cc5254cf8f565ebc e0b9c689e95ff5d675aaafc9916f010b7e5b9a13b201686d4a600c5516a8e263 -225000 b4b671d3954ba70856a978c8c173096a9db7ba168c8815730cb445ed0b921f7c b16288a5f727839ad38a64139741eba8f93f33035d294365e841e714927ce5d6 -225500 17279999d391f86406797119b105c9f5f6a02678f7c3d34d9f272c73dd77faf8 d555247b00f10b1b9825a09d2692d22129b967e1ff244d1a60a756e7b2d9cefe -226000 94d997cdf120719be0ea6a4eb198704a18baebdf13f65e28e51b49df7de1d861 d3d5f6655db1fa41b2f916399ed5f36246ad98025f6943480fe15e43b0a8a034 -226500 dd41f722e300bee85cd30450c9fd08c3d4102b1095f88617c10b100556c5da49 f43f89d4fabd9330fee3336ad9bf701601c33aad3abdd56eb6c164c21da1ff10 -227000 a0e48510962ea5a5f18c8d413b48688843e5cb36b8b74b5e61bf357b43334ec3 0fcdb763c6a77599a872c5baa6fd1ddd761889eca1c53e882b616dbe40de391b -227500 7f5337c81192ee64e2e1fd4da832f60ba2d89b0336e8e169423dd403d6f76a7d fdebb66099af9283e9c026e1e9a112a66af6e3bb0f657ef78392a9dad4768963 -228000 a8779b9ce01000a531f400c46d8930c487ad00315f0ec4ee8acfcbbd02ec9e7a e9b6fdc4d73e7910e18d95bf096bd5becac7b96a9989d60e564f1ac2480b1fcd -228500 074c0079bec868361a58eae22d107577538fcfcd531bd3b0516becef48d25083 b0bb15325aa285bc0890e24b0892efb113246e6d785554e59022c0917ee4c35f -229000 27c38d7adc92ec6c3b2e5c16ddea6cc06d25cf138ebd45a935953a357143cc68 f916d1f8fef52c7532988bb984eea0f136d7c777fdbab72ca0011b4535c91e46 -229500 1010ad9db0dbaf647e510b73feb8352b927c1170dd09dfa15fa0f5b9735852fb 7a7b2eb60a9dab15faf8e37370dfcbb6684a67faaf7ec1f50980694c26dc558f -230000 e84c9aa480b0a7900f557d49afdc6273171bfea6e6adee45c3c2c7408c7a172b 1f03b2bfbe709d7b411679979aaaf2eccfbf14b2a08aecb7139b191691acf77b -230500 1cab5352d167b21bf28c9b3b0f8cc821eda60b32ce9f2f77de5737edbf28bcda 8867625cb142e048d056cfcfe5627fb7ac7a20a83de0a9fc008bd4951ed7def7 -231000 a7e7ae0369d5839690ba5cd0f83167cf68e6dc9c5604feddeb986b17cd35ae76 4f7deab8e1ace7033b726836f01863f33677e4ecf1f8a488fb19b99630fd2176 -231500 3bf6451daa832303c2242f195ad2ee1a205ca168fe132087ff899461f29dadfd 6b87a643ce4a5cdee1f45ea3ee7fcb9b5df8452209970de76513c846c73ae7aa -232000 6e1ae43ba56524a6e2bda4d769f8ec8e99620690baed8d8d1764c3a42509af81 eff179dfdb3a490f2038514a8ca3c65a1ce73c266f808378d767c60d1a8f9b16 -232500 95589eb200430bba2e6660842109cfceef9a90889ab8eef7091685dd052037d7 2b8b93e3ab1fd3b12368ba3dcb7b087d84528932cd4fef51ae863dc40718df55 -233000 edef1536377488c20d7836daea81dc7b542347febfdb3b7f0e89ace9a9a2f980 ef9ee2dc8e6eece115a4fa188288ac21117d58bf45921924db619655394ef4d5 -233500 7cef0816722fc26a5a131003a9df2d08cfb005d752a7211cf52c6c27acb735ae dc9115037b26543076cef7cfaa03c2839378b0cfcb8b164f883f2f73cfa95b11 -234000 da363a034d807c2ec1aab013d8695631a0d24c50c34dc0db04286a1a53fd58ad ef5a49fea7936d6c151fb533277c19b7e2bb3e88e9351cec946bdce22c5ae5b6 -234500 e35fd8c71da099b9f3f1d6017c9b799b6f150e553ef827f83f84b4d62ef723cc b469f833b3d307d9f12fdfcb7a9777aff2c37a2ccf713d2239275f39ccdac37a -235000 903c98a140b5e8ce72a2571fc17c585544c4076e6d2b2efa8c58b635adcef6db 5d048227793f68e79facf5538ee5980089562490688dd1f929fbfd459edc3263 -235500 1e0c48356729ddb9196f9bc8cfff295e2205283e468534eb127eac2a8503612f 152dff3242d0914c503c8ecdb376d1cec2426abc09cc99907b1f43b31dc197b3 -236000 48c76115fb5c845fb7e9b8d9bcbe2270755b054db11cd6ad6c2ad89152607576 1420e404d7b541a053200034e94f9bdadd705dbfb57532c2a454b9b17c36cee9 -236500 76dbcbc51593c2ced3dad33d42a9f8c522f01a21383b227b0e6511c76363d782 f432ef854ed6a03b4809d3ecd8a46def940a0d251d09484ef1b6bcc3271b0f17 -237000 8c821cb30e183a3f5a3b28bff8b16d1606566e3836a2eb0d47f6c02af8d3f324 b4bd12526051dd6ba2a2d616a95212c8ab4d6adc18ac21822a57738eb8284e2f -237500 ed4f21e0bf654339e17083701448309eff81e272b89e00fdabff166cdf812bbd 9d03191f41bf9d7bfe65b5cea79e55f32c57765ed5909e11ef961fa56f3f69fa -238000 5af7f4d9b69ce00a56f5c7d89de2ffb0df0ae23520ff218ab2330ce4817ee326 509f60bae30c0cb7666f7baf33fedb510f3364abccfd0881671650caceca4cf6 -238500 e95df9d3b7bae4323a4562627b9926d2a3f4c152e93513f0b57d83ec88ad8868 9d0e160a8f87e36e9fc815538b27d8636daf94ae5c8701d323995054446ade18 -239000 17dd8f7338c85dbdbaf0d87bfa224d5fc13e58aa465cda17eed21ec1e5a13051 61604321167ce51b0c2043524749d385b40cf729814d88e0394149298e1d612b -239500 d10a85ecd99d5fa8df9df4aaae9ff7b6360bf0f6c541fa6e1c8d743ba350d1b9 085caebd6ae46fd58b66481d21579720316fca78552121f9252ff8fd5019257a -240000 dd21b880d234b770079e0478bddfc53646feba611a1858a82be2d68a5f70b5cd d0bdb4e68e287851256fe8cd8518ab06b2f8bdc30984ef27feb96cbf2625bd81 -240500 4bb3da166c854ac97920a04fff729b2da619b130b3b257fba10f5be47354faed b7081936dea5f45ae555b58ad83d42234183f80123236a1474f1df92b289dbb3 -241000 cad2acf8c8a9802e5c162170b2cb7112447b1b5bdf3184dfb6ffca5d5ca066f4 50a13b720476b0d72efe8fedb30d6c24265a0cef374e1de14df89e3488fd3930 -241500 f89869f168fee009c6b743da990e96a296823c795da2fbece16346aff95cc0d1 f1e24d47abbd5056f7d3fd322a882ef885585d877ebe23b86787fd8bfda5c03b -242000 8cd2957d89f5937f87ecdc188f5ad6b275768752b873f36348fffde02bfcc4bc 9e37495c487f19227aa0b4312458907ff749f668a3cd386d46318281e03497f2 -242500 4d84991c165bcd35c6f24e4124e5b93678214af88c683ba82419330162070a43 dbc9324659ca8a138b7f72edddffa009859cbdfe03dd397da0d897b40eb97efc -243000 99f2ae7beed98478d52ce8a3e8106262d777e9220d54159cd29173f823002468 f1af12a5aa6ba842b39e357a45bcdcf93c9f718992cc160e1849c693211642cd -243500 84b668ed1334a0f60f2b7cccd9a1bd05b758fcc1d3b6de13314b60b1ce8dd69c a02d27be36d8ff1a07ad35d80e1b2340c042bbfeb7ba7c0f4289eeb8b66ae117 -244000 58ccb25106990e5eef0f7118707b96402f853599ec51917347012350230701ce 989a5646dc6e9f91b27d9d3f3eee07de2267b5b62ca8c2e0faed6883f1d04e18 -244500 60b50cdbc1be5d94c144f682c62cada4668154d94b909100baa392bd914fabfd 15fe02c7705d1c3860305d80ae479410c94dbe8ed03f942dde09d3a3094163c5 -245000 538eb0feb39a02cb69f673a6707d23f80be40a922ef8fb43ddb1782d8bca83e3 ca4b24d390ad10642d096a14bcf8fd51d7135681c9a750a80144b107ea02ce1a -245500 8e7a40c1deab5dedd03f960399dd0a59ae92ed849f0288ed447307112a4679c4 fe223451b524113b6d13c696681af1a1004e5be0fcd14dba4edf5d43f1b52894 -246000 e5410e4186cb320449ee28882d9f32cd3eeb79104f807651b8dfa0164ebbef82 0a4203ec776383111ff8f9ff697c72bd8fe1203d55242790a9cd42086b2f6013 -246500 0c2a1c0920dffa7e8a582bb47b121ac02167b2015deacd3cc2a4151419dd8dde 1df603f77f223501d3036d16d2201004c712f86aed58cd0b3d89b32fdd1b2032 -247000 def0d291743461c8680127c4393f912663ea3e8105026bc76c315de3f7471a17 830d9dfbf53d41d49c1a28631361db55fee2284001c16395ed3046f9a9278212 -247500 41c85aad59b4ed9baa25743ed3b2205550292eb7e5e4dac974f0839053d0df75 dbeb22eb94053b3bda3520ea239bf64c51d046da08951074dabeb73b06cce009 -248000 e34f803c19b9214d128703d584947a348459dcb0191cfd0a3928447747b7e3cf e58a6b50690ab0de2e1d7e5eaac39e60495e7f15c0e494797c49ff0a83e80d6f -248500 779f30864bc7a0eff2ff65a65af9ef49ed7125f708e923cff6a7a88d661c1688 34ac76a53fca6d0daada5f7f12e339fddf5d654bc1ebe03267716822cbbd0514 -249000 46d582e130542ed696e49a52224757fbadbf61037d15182cbaee9d6895261d72 7487aaf55ca988670dec71cb5386b80d8975446ba57feecaf64b3cc9c52a18e2 -249500 87fdc18e9972ab01bd0f1c0314fe017d5b825b2a802da4da2be0c495e8a6c2fe 364509f6a5c984e616212b9a328735397515d8392c612f774a55e8013b80f868 -250000 f345e75ffd358b61924b0bf3fcf99156f97c1479a0b31c53713c219a38846b5f 156b414c9c8d5782e5ff3c541bae9a14641338757b351f8cd7340d91ffe7c8ba -250500 111446c3129d174c80978898f17b8c14c485a4c92396a8c2b15c76d7da4e4ee3 67bc454190eebae6062bcfbd41b10f18161d777d0c7f1547d9c922fbe59301e3 -251000 a1d9e94171306fd7e28559cfdfc8be43a89ce142208f0b4a4319177bd6e1821c bb9e6ac2b06ece214228cab806b96fafd12d7fab5899ad4b8f6c57764c04b65a -251500 011ed051ea80d7aa8c5631cc3f6c808582b7bae9533a47a1e9336280e244a66d 5ab6d307a8215f078406e4ef5256e86f30683732743e4e102fca988e3e9bf157 -252000 0f60353af5fa6f614467ac0b793c0cbfb723b48353e45a163384288db9039860 977d7256cf493f632575935a40240e3cbc08e8b82b9cb78666fdf4e17a80748f -252500 856aa75176f71b2613ce0655d8bbefc03739a2ea066d1a396f608d596de9214e 6edcec572883a3e3e60b10a312a59c1e4486a0c4a73f5726b7b3cd1fa5ad8a8c -253000 135cd797ea002f028f372b545ba294120d92fc0368996f3f0a4a2c3aff5e2178 f6f35b4573ebff09a1d86085a7c5ad8f5154bc67cf6f1b821780ce3f39d845c7 -253500 7e62b3ed039f164bd4b37eeacc05736f7160fbd8ab2a0ed7c8789817ba43f47d 92fe7b5cfff4d6c5fa17c317ba47417e2841e65a9a985499f3ed0ebccb05993a -254000 413a5fd20a447bae48dd74c04912c73ced49cb866c96a65aa447164084dc3723 dbdf24cc5fe71f376465115ace1ebbfdb9382c6a47ffeca175f7b1d71d077109 -254500 dae6ea70719a1798ef4cd7eea67fb84482f58695bbf68106fb1ffca714532549 aa0bf86ce61e6a6801a133340c93e099d26f06c45ea6a7d0303866d59720cd45 -255000 48686fa37b3f22077cadd219544c1d55015b613ec8c5a4c367b0e32a1d93f114 8419590a10c931fc7b06e4f0c9cd66add2783839c03872569a4d84100fd3ec7f -255500 3480ad9060e55cf444b9f63adf976cc48c8e68e9c5d9f2e173d30ee5e21f8e55 22d1784cfffac5b2f3587152e60a93c18c3ba34d5872ac90a1bc249b98aa17ab -256000 773459b90dc0d860e1caf2eeb99f85410a17adcd86b9c7a91e282d7375f69b87 dfe7baf5a19c7d41d0be344f1c0648ae6a720b5c9b50d1a1755908da38ca28bb -256500 5c5a4002c3f5675ed11fbe0d1640a0cf72150462b9f38f2b6fefa04e2d47e57f 504eb85fa2d5bd399b16262f3ed52330fd25eff4396ce7ce96604c58c835314d -257000 f957080ceb81d1ff1a57fac8d99d89f92332198d332b82ed19f116bb2e4bb232 2aa6db9a7e207b621656e249da6a29182bb6e77489137f185c4adc4b43c2063b -257500 124667d3ac4e97b204a238e688229f21aac351bceaee670bc86b048aa25a326f 0806775e04bc4c3536af5ee7c404d2d53e780775da20c269b0c52258be37dad0 -258000 281275e81b624913ab150bb6061bfc3d065c3b8e876c1c84c933d1340342804c f2a8c5a57fa4b177d510bd095fcdf765e7b4c08d8ded22f12c07e3fe85011df8 -258500 99b3f45ea656e722d919f59a89e1ef97e171f1422ef68fe6ea17e84496369d31 4b30ebda14fbb69dc80d6219066b66d8716e2235595125113444f28e2e0e3ee0 -259000 a3c8b1010cff2df85b748d06b4070653855a780fa89c1fea1df8af1b99e1f71f 611c731a6c76c22ace3e93b064a4f73f2debf5f63d270a9a3a59a7a46544d6ba -259500 6f80b9fc49fe6de69d6ca2ec1a783fb006b73c7e2fc0caac427088dc31d0b527 d9ddfb40c125b781b7780845a78f6c90c2b887b8c28a0a930ccd6ce7020bfd3a -260000 d3f3a0df265b13c30fd6d529da8a8628c98144abee10ac66feb2d98972e52f54 31ada4b62db504d84fed898117105427ae16309d45de494c4a266316f8225d25 -260500 10c9f1214c1a77cf5d4097d05a4ecc043d8db4dc9ed855892763104094e4a1f7 273762c7e60334efe73f1325072dd8829130ace31287493f4028fa9c22c98619 -261000 bed3ea15e53cd2a4b2f8d515efa665b1552ac7bcdd575048efb6bafa8b3d0f0d 3fe66c2acc1cef4355c4ae83ecb34597060c44da2aa73f0a51618f4f6956a8e1 -261500 0e9b83d06669715a10a70adbd0a89d58a56a853be8c6b4e6fbd3894fb865c224 992896ed5c5c7c262850a9d3f7b10ab729de8fc572190e0c08745ca9aa2a5433 -262000 61022120589859e23c0c4fa1f2650329f44feda0823bd30d597be34ed030c86a eec28d8aa336511816f17eb3cbff661e6fb35bdd9cc7a63e9ce830e7dc1261bf -262500 957872933b3a7c22e527930d65220a77ebf04077130f18703f4d9eb8384edac4 e267fc444b94c0c3e8312c063746af1e93887e4f9affb11d03d5728885b63cc6 -263000 e06e647a254beaeea41f7d2cf9d88531c5193df8a75d4f1d8df403e1c2a24309 5aa9aa86564cd18ec3e2dca55315b46958ed92e4ed8710e33ecf3da9b051107f -263500 152388327d812eedfbbaf6f841061eb28be5ed87dc9453402355d8d06c64011a 23552aaa4ce81d4ada113f198ba4c848defa3870f8093576be677c2e3c92c149 -264000 ce414cd76a86b1af60c778ff9e5b04c31464198d303c9f1d53126cfa930e706a 2a3acad69f31b7b30208aab2b1bd15695cfaca2d8aa20bb2751afcb5755ac0c6 -264500 d259e8637b4b48b373b6a1a7afcd89b1056e2adda59b819654f393e63ad2653b 31bbff6e4910bae42fb446c184efe8191dac8d6a86156568daa369230b5198d3 -265000 ead49b3a388fe07616d1a8e8c391d50dffa01899a7444df60d4d2c40fd8afaca 9fa60617a2f080f521628ef3d754f1706c464fb43a8282bd07ce2ed26994be5d -265500 6bacbbb516631a7922e9a988fcc5e102d6f58601085f09511601f4672a3fe316 4a5b61cce54e08360b9b2e338f39f45ae427b2cc49034fb0f1e71948a7eb92be -266000 b6993a4fddf6404fe544fddf2df238c999366b43e7a335b81b4524f9aed32999 91407232bbaf55fa658262dd6269b1ec6c620eefab326e556434fa1d0d64cd95 -266500 a22adcd41d7ee4df6deb8633f53d381e9826dfbc7709e68b7b1ad5d71e8898f6 314feaaf908e8a8046ab6eba7cbe3c97aa478b2ad93c39aee7df9f5a72955db4 -267000 d270af2ee0a98e7e407e39d50cf4cd22005faa34480d638e7a6b7c10b8d59e4f 024ad7c62e3a9ab757d4905bba29fccf5ef435e4471fbed49ef50f6f9bd1075b -267500 1fa94c5777a0fb5f2c0b89389d3b537d5d6465bfd432810fc173dfed7a666c36 b4e5805d093717d9c5d8766b1ccbf2791eb10118c9fb51898f0c49273c3ace31 -268000 ef3af0dbba05b3633b87348bfa9492b90d0c500f8427c2f83e485ddb4e326b7f ea130ea23e47338355b0336648892d7c09251bcc9df307a7f587d7a425d2a741 -268500 f7d6e8a528849da7d14e07869feea84c406697ae7a16ccac0ef890aac5fcf4eb 489c417d04b8a41f630bca15696e7a05ce36d4d216c04b1a6560db25e03e3cdd -269000 0237cc909ecc6a560183034f478c44d9f9fc96d5a0369b89d5f9510676274123 e84c666b3a8122ccb250bef7b603c2afde722fd985aa36be484e76368f13f10c -269500 d342e101fa8308700ee1a663fd05b05da014141725d0b3655a3f0fb15da83771 93daf70fc7af5e7fb37d973246c434cc834a37a1fc69fb522f9ea5b82ed2bb2d -270000 83e4f6c8831be3fa7b6b6a0aa13805ae107ebe64f496be123a4ed9711cd69065 ef10852638bcb24c4341161935a116bf5b764ed34380ee55243a35c938fef7fe -270500 557c88f51ceba0d2dcf7bffe8ee8cb308f8fb2f14998db8b6c23764d00d756eb ed1e1382a827b3dbee6c583053acc263ef365697a9325d3ab3bb60f80621b66f -271000 8cf965660be26838d4edfc4ee6c9e3f700c5074a0537edf09d19fa8b25f9297f f717dc6ecf1404858433dea8353cae36a181baec3c8ab3fb0c8eaf17e76f2f46 -271500 940439c29f8259ebd1f7a7a76f9cb7c34981795365d06cef15b272ceafddb513 e013f425e7b9e0c919d3a8a6e584fda18d798f64cd32003c79d1b9acffe92f8b -272000 6aa33a0d087f0a56f911acfa99469611ce6a9fc336e2ef2ede07c854c0ac34aa 34612581d8665965d653cd9736459b2708141168a297c9eda4c73e64ee4b3511 -272500 e165b1f323ea11ebff46a9365e5c15c736a639c87e0e7866a790c212398fab51 6e2b03ecf9ce016d375afd28e4895a3905c5e79e64a451f4b5863d6f8ad37c15 -273000 7e8e42c625a39262e7cd8ba81d6042788c5685fb7e1925556bb81d87f23fc9fc 60337941f27f0191f55253642397b4141c09a3796a2e8c972154c90847a04adc -273500 50d2fab64d92e6bd34396a65ea083c254392b73b806c9c23d10a64fa2046ef63 def5f3f2d73ebc5c90d4a3e5e8100e51e3144b63d3de0fed9a6393ba3138f62b -274000 86afbaf7b386a0a5ca9199f42849ba58e03c52c3e14e4796be5a47bca65c3e56 9fa018f6e78596557adb6a6294c3ed8c02e5b07835258d38d00714b662cb88ad -274500 f4a2f13cdd599a02991bab088d21e7d28d907caab124755cda5b5da1a0ac3514 27a84bde9f23b95957a07f3950a238602bd158eb9fc3d8b7ba88884425fa2eca -275000 a655f397a1362429e51239e663aca0a3582f4a984001c6093e48c4e0a2e05941 c3a045ee8c5239615793c006587052cce7d63cc81c2ecb2af75e67f3c53a8ab2 -275500 b3b6e311d0f5bd738f2502c2684af690e0f71c2a4c55afd5661d069e604ef3fa 0690d029ffaee874f0407d12906116c79bba67f9b8378a31334b25483daadf3f -276000 f24a85fcd91ad6a82056c8a76c2d3d5d04070ffd7d9b84a94ad0d6b8acc0c187 5c21716aa2a15d63d306717b47e86748fb203faeb1c6b19d63a5349176e9fa06 -276500 787f090210f18af487a5a4f9f284f1d3314fafddfdee64723d3237f55d7597b7 3fafdf028ccf9b4ccc043ab7159a37ec9740b5cb34847a6ef427e117ed86f206 -277000 b431470e16022c9e3e58e772bc8db6482f309cfb72a197a773b67ee7ffcdb756 894962f8fdc8091b4f15d60a3ea4de232e7921227ec9092e4674338c6d0907d0 -277500 d4f3d44e493b537d6f5a6e63e315dcf5031240fbe6b6ac65a76eb8c35f5db13d fed8c64ebc096321c5b99ff1d5d424c213c3e75d13375645f37dc5aa807eb57d -278000 4f76c78fc8d544c1e8a0d0429f7dac32c9f0857f906944503c80f58d809d25a4 eeb4b5d853e4a976e994c9e129bad662bd03d8f2c7e78fe68bdbd47c28480ba2 -278500 494b9880d486e1151d466eb73004b3f226ea90b6127a4aef1b3a90edffd4d0ca d9b63101013dfd8dac4895a0d5ece4c62702aad7cdb81a6b186e530df840996f -279000 8722865896dd4d2351ef4e4def382a2e622b1e46ad54b3940a16f5073bb1d844 2ee3816538cef7b1d029887af7e39d60cc1e336036fdbf089439f38cf13ebcef -279500 3423afaedb970d2a590a0f3e023906bef4110f1389bdf54e2c4620c36b72a3ef 3e7446b32ace025408872375b1f3111075f305cc83f615ff2c6133e49ac96d88 -280000 9cb8d7f3caee172f2a7b8b8c2bab3fd01326468f8b5932bb88921e06167a0e31 468c01acf084fd4986b21d1c0e1defef6a874a01b0ec21be66098d53fc4244c7 -280500 6cdf47d170a6a5e57f6a9cfef7f2239d4f15a61d5c37f5b44a72188aeabd541a dc58435982155aaba2de5c124a9f441a90a575c9cda3f071fc9c4a3c9db61c8c -281000 3228123dd268365939c7fd5d9ea6a151b6a95825ee1a49b9fbf3ab9f3ea45508 9320e6e8aef527e622e610ab13eddcf82598b3f2b744f6e90727ebbad920c080 -281500 a35ba852d6be87b2a614ceece176b04152feb39a95e52e641e7da7c1fcfd220a 547cc277e5a3fe410e5265d8622bf0ce0f722c39c23b3274458f7f99e68f0ef0 -282000 2533068b9c436719d1eadc4bd7e3e805ebd949d57e75cf5e0b17321d109a9a10 1ee93f862e7504974feb14b488a590aa9221ebf331beae0786bebbc013278457 -282500 47262c1b2c424270254ebc4ad32694e51ff4c09d8c8da9e944b17ca3bc734e1b f940a70f96d1369af5b0318ee86f9902bd122036ace273643a8aa0ae7878764a -283000 bbaa0da5024d6e74becb1d0d62b2aa4a8ce1c3bcfe27c587d3c89b581f22b893 b8f67f07d3e46ae0436cdbe91a4eac1ffd8a8de111cab322c4895423393be210 -283500 008c22a6e8d0b46e6c785736f6098de9ac43d5d1964b2103ab383498623a53d1 77b3fa5d6f930d2da8b1171725e9f6e7ac340b88637955083de8a55a0d129b70 -284000 6273a37ce3e5fe2c58d6b1bbc1f31822f9e1f78e434d62c9aedf2c6c18faddb7 0e5422505c2be9b93d74f39ddb43b8f2a6cebccdad41d3e631e56a5c075622ea -284500 6dd5efb7d0636ca3212a14ec60bdb9940d355e75c4c3890958c2120c4e0e92e0 8adad9dc3bad71a55635afc41505883ae38fe99f3c96f021137e049a1b829a55 -285000 7d49941cc51ef16e04919b3dc5c5ec87b62e98267f173202167ee9a359d8a5b8 d947bdd3999caf548887208f2049fe528335634f5762d6882d4075dbbc6c6b1a -285500 c06cb12bcc248f8a0c2e764e2c160d85ca356ba7235faa143eecf42f7ac2f7b8 7ef16bd0db693d3ebd90f3e9152a8cc1c420a3c57dbb6bf02a86cfb3b1d19dd9 -286000 45583c3f15ca70ada0a0c38923bf9a7c63a82d7be1a05dd2d3d098fa6040b522 d497cde577489bcf9ea8e08eec093ae16e80f5c58ea09344c27bf55b98fe3fd9 -286500 94f13e245e46c93614627914bf086bde72751bbc3f88b35877d73bc28bd4a7b7 83245d666cc2a32058839f630baf72c0d96977e7aa4fc400f58e75f2f9ecf78f -287000 eda15ec5157413f65856008baef31e5d124c511a95716b1f6b7364f5e3b5e75a 5ac1908f2739c718feb04686b434dfa4e7ddfd5213d9977137354ecfdf5eca28 -287500 9f7a944ae0a5d2caa33f72042e674d47334445b2f47ac89da38e29357301a060 b7fca600d7445e8470e57c18e2eadaf73aae7abe888acdfba5d458197ecc1e6e -288000 0853047a1ac1adb0d95427898e88464c078405fa22ec5def178eb5de7ad31e02 a3369699142afb6a7da295ca36953c883d67a31d3096d158486b578a6a585fae -288500 eab408ff9eb88ad56e302df11a2513c1dd7873311632911cfdfce5ad4f814066 4f39359784cfd3619082b590cfdef0d6978434ad01885e66ea50f2d96abb2674 -289000 1eacafb1bff01bc0489b29ebc39bf137d040e6641170ce3dd89ff6ba59abf97e c8d5fe21e49f66adbcfa0c7d71ddbd5bfd2210554315f1142656f3802fb9de86 -289500 887dd7480f6c7ac0983d66c8af20fde72fd415dc9341eb28e1c017cc0ca046fc 64cc676cdff6225d910a798088789b311dd78932e090292f289b965e35812bfa -290000 d537cc92d4d860c7d1e74c77d63543d1ee28bfccfb33a3798b8fe4ee6aad5fae b1422ca72d6adfc0c8ac92b75dd68b19615bf27ce351c07dc461e4a483a01d36 -290500 1f72a0f641f0e7c0a14ae8aa3a90a93130a302bc82616e7df2eac6cc893f8826 7cfd6bdf925165f98609e9ac990d9c91cb484a1b0c4f26181f519180b2cd0ad1 -291000 045c570b2414764749905e61329694b5feda76d2656dc07c208e0f163e8d8be6 ff11ec49560b7c1264cc610daaf95d5bb7f581edf89568fefcc83bbef13b5835 -291500 fd55aa9e9dcba1752e4c20055a1c9b6ac46a21a3a932f059ee574f49b721f507 3575b8d9556832ef3d4d929787f0ffcb147cb349499026edc50e4be282b15863 -292000 37273300cca125ee3ecca17ef0b26cc7880ad9b6caf876a4eb5f248743433519 9e2e93489d99a34477c9e7e60d7a971b7e7a14f2b1d1af1d797d95c945c26d08 -292500 c6d6356e96458404221b2fde26482fa42559dfd1caab1b600f045d8f6a2302cc 5fd0c22eecda0a4ec51190a6356fcedb96e3d4662a03d1c231575dca131b801c -293000 d3cadc149d4b135ec11e9b97cd25d6e1caac6560b16c0d53a798fdc191519682 e8fb2e323adbb30a6ac4a40239c68d2377e9c8fc2094901d694e0957b9815cb0 -293500 a0ebf3b0b17cd3dfce121b5a4466c2a60a9ce0169c79aa070efbab912bc0bdd0 c9da3ed914a818f8973e44fc8a4d450e68d775dac064b9baed30d71db09323e2 -294000 492dad282770f45e70bc4cccb1ff2d69568a4d761395515f41d53d0d703db481 7c090581b9e3e74b2ae80d821555b83a563442f01ec32994b87b8794c8a94dfe -294500 8923473c7806f6175ad2be0cc98c4066e69dd2acf8e7f965fdcefadbcdcbc930 689e66a64c3f66de762b38b5cb0593b6c0f076c84a04823cb1f927f5d6601c12 -295000 3d5870c04b03d0cfb60c9d47169b81aa5c669fcbfffc602ae51b930391d06f7a 34ef893941a5215eccb47786b0d108e5150cee56d691cd6d54280afa5ce5e85a -295500 96c1ad430e0ca606b9da9929ea3e6644ba7d42c02371abd5d1a1ae099654192b 8e03c6f39a7dc904f768bb459ba01c623791992208f124c37bc679e61a49fbe5 -296000 6407e9c420afe4be97d10102c8cfc0d7f5ebaac40f6d5e678cac8144f007fff0 d19593e2ea6bc1c13a6a3269bc9d7c6ff918f0a01dcc61daac670b37d2d80347 -296500 1f8d31ccc299f2c5b05e93383d8926862fbc09ca5b01085b3a1dd82d5d495d8b 31fe78d77df28d71d73858589dd74fd5362642fafc9c8d29ba137126bfc0fbc3 -297000 9cfe512e43f2cd52ff58f90464a04f076dfd0d12d59cdeb100818f109a9003e4 5e47ee43df09cc31576cd9b0440c619a16298d39ab9264f639b5b9c86f8af572 -297500 95a02da1b06b1593ea08b020b4bafdc67f5e176dde40de7a1feda249571e53ac 43777410c9686e5c56891eb7eb0c37f2110b339e5eefb75da0bb28b78f3072c9 -298000 0d802cbe03a4b85c23624a03bb35290b461d8d9dcffa128de936649b7007f622 b5b3a839917d03e52ba179edc51c12fe47a6dd9a5c57d678299387299219d164 -298500 7e4e639258fe47ffca25a4b7bc7b908cdff41c7e1a737abfd45fdea1ba62ec12 a8c88f6180fdb40fc4524197c5eb32ab9bfda23b88c4eda4a422994710030d1c -299000 d2980e238042ab1ee113dedd25dd97fde37f474e6ea666efc83ad169c7ac4cb6 5f89ed52f8866c340657985291ef23e18eb47e0631407dadde650801b632c010 -299500 a3f56b859e1362c88c4ff21ad8cf5c799c2ae565f46f15bcbd275e7cb0fbef1d 2a189688c70b29e449f6b3bc93fe61d4b2eef5af756039f90fd745b47bd74403 -300000 5a2452a4745eaa9cd3c1c42b7e4482193c4f7c3324ef185a4d0a403d2002c0a2 0276aa15dc1d6f0d96dde0520e357fb5ca4d8469115a894dd76e4a34d79b792d -300500 d02571cc76f7cdccf536b836770aa02a0d238cde89f23f767fde8e62e2648735 25fc046b62a57b71347be8c33dbe9d201af1efecf98e973b35294f32b745fe25 -301000 b8ef5fe2861b8750589ed344c9d8edc7ebb9630dac0ec507ce09bdd532af32b3 bdd32f8faa1bebe0c4d250a309d8e983c5444f63b8748eef76470b980c2542c1 -301500 573f412e4b6a3a7cd2506df938810bee7029b9af102e096e83861eb3b29647a4 e8fb5de4c13ef24efd099f7808c0952e287aa23d51a96d37ca919c3fe08b9685 -302000 18b4cdc5a75c82496545009007b5f488aaef67892f6886bb36ec2526f02a5501 c8898b9f003e3a651e963ce212412e35d3d825ad2170cbd1cc56bcb1f7a0c4e4 -302500 ca57a75391cd670c7e1ed0fde565c1c15d67ac4fadddf92549874fefc3a51c74 08a7221ce567158af54cd9ebb89e6cde68430c185f6ae18f1c4d7001970f0dad -303000 e6dcb8971d8b0e379173bec442b5e465d02e700b30a79598de9be17a5497cb89 41c38012157119f65a5404f0e62a7656673f033eb64e8cf4275bc81aa4d88805 -303500 e737b5b4805e4740cc8c50d60ce3769621294b1d20ea8b1bd3f3757c2a37e1b9 b5aba92d8014d56fa32993c21c908b42330c6ca382631f57162cc63aa1b842a9 -304000 9e5aa8da5821d8594bd9ed376f69dc851e5a7e0b4cdd755c6394f0eaf76d0e9d 225f9b063c89eac0ee1e3136e644cba4f65fbb475fc5a0e2c1fb66270f6f13fe -304500 45a43ebbca6f1cd31a03e301398c2e9e9d15f1bf91db745a7417b4d8f25ac394 4246e0afd88d5225b8ed8642d8337681f42952d0df01a71aa94d268790755cf5 -305000 153be3e755e4953c3810e08165407725c11fbf92665616c708bd3b824e973cfd aa39085be20fd4450a1a03bab45c09f669a0a50d84219505b7077c0bccdde28d -305500 c488fbfd55f3fc873ca49d57111f71aaf5a42c4bbdd720c0d96a5dc66eeb6736 546e53c9ec8cab56e41df87aa26122e2cab4077646b800b63134a712a1e3d543 -306000 83982570d251358e02e1b359a0d95b96b9f64f3736dd823654d47da633d48708 6a861e2b1c87c8002bf0794ea718b6be98b4d77ffa95a22a3decf18aa985bb25 -306500 96485ddc1d2d81f38a752fcf1ed3d7b734197c472e8ccfb0eb4ce3101a473394 068dc5f5f5064a475c7c84960a192433e9bf18098d581f0877066c60ff0a8861 -307000 0d209df0e3d2879d8a0f356f7d4041d6e0825ed0b33011d5c8db9bb1ec0c7d42 1f41650a79db8f7bfe188f47b7f1bb293ad4f178ad4cbea99d8f87876b68ce91 -307500 aad6c7f578667b9527223b8e4785e9a6739169528d9b0bb741119f224e0125a3 d56e00856dd907339c3959733761bf3d2ed206bdad2bbf9d49e8ce6cec4be663 -308000 1a02c273d30fd2bdfd3c0391715a78f6223c944db913c846927b8a20289ea527 232e616645960a14c845a721665ccbffe5a70408ac38dc2f9d53e306c40287e6 -308500 b5f04f2fd81500e1f7d817b94c566b97c38cddb21041bc5ad38757a1d11c3a74 5596842f2ec00ea253eb5a0a5565d21e871a511caf4a40f7e559d089ac67ae08 -309000 ec31bf5b86d611359ba7818f0926b3314c13e7fc6be4771e78aa66c65f308e1b 19be4c08d59662682dcf27d7cea164915e94d1ff761f8321d6302d7de2bafdc4 -309500 a40c3dc8a06147b339366c16bc1a21d4841ffffb9721f952276c35f6ebb0fc67 161fbd3c4ba1d443606832471979959ac0281462f897801dfc9e4a48d03df741 -310000 10eeededb4d54ad661d257fe3ee8b383d88ea175da4eca06cb0d2afd91d705aa 82535ab42a3a4494e51e508dcf04f233df0ee6869b14f12c2eeb3de7d0d9bfb0 -310500 5937e9322a0b8b1886bdd639f3fdea48392c3a1f3ce5c729f4300307b30a9858 463320d4b753e3deae3eaba1c7c0c81de49d883a7205d34efc6f933287bec340 -311000 106bcfeebd4f8d313bc06f691e30560fc6d5fd4e8eb2d3aa6e5e553d5d7d6769 efd1663f7e472207765e064537779ac8b52090326f6afcfbaccbcf0dd5c7cb49 -311500 81c0cd746d76874a8add01868bcc5465d7ff0a28ef2ba742b75c6c89986ca3cd 1e89778081b0b13e825bf16daf61ee16669826b50efc794cf871ea170399ca1f -312000 bdcec2a9a093b8c5e6a3f712c866bf78e720862b26918e7387d511de18af59e0 96fb2b8bdf01cf8b391a87158b880f38acdf15a6f761abe2cfbcbee83478566c -312500 a9716ae91f6c1577726c38cc4fddf8a39f1bac41cd1d9b5605e52184e573d6c5 4fae3413451a71a5f1e4ad71341035c582aa1aa721ded95eaabd734137ddfce8 -313000 cfa985aff09b9e7f22b17a600cbc428dc8e2dbb9c2b22420050ed8dd4597963a fc3335bb9389d77b4323758d39d7391d4896b94ad440a66b178b9366492fc79c -313500 959ad500e00153dcd9d8b6a8cf1190c799f69d3c5f6dfdff026a5d78ca5d0c5b 711b49060d7eee4f08a198fd3fbb3c611915c64cb12c8152210e9c4ffbbe9c0f -314000 ab6a7acb2629ccba949934209d7dc9cd895eacddcd7143dcd7eda19604ebe05c 3faeb9f09e3a75ed2247e4e6352c5744e091f5f44792ad20000721198a075c79 -314500 d9527af7b2e46e049c738a9d40f7720d8ac2e8e94b847cb8884d922ed004f543 03476229cf97cd0f2813169fab1ac07b9648a4dd86ea864feead69fa34dc498d -315000 626c5f923088c9093b00b846a1ee92657bae30a36370f679804743d1decf948b d51b5ca87ce3888f7299e3f2c0ab7f3e28afeef234f63337553c972f6e688be2 -315500 2446c74456b4b4b216b760d567abed176c12c2f474459d6be711490190904e07 23a8dd7d4d710ef6a23aada5e4fb960bcaff7873416c6b9904e1cf61c2abb0d9 -316000 32e55b2ff3cae917e3248bfdf7ebf79cdeb323cacb54348bfdd0b1f411c92186 ed4b4d67a3f55e5e3247f48d32ff231d24ef6970f8223e255c2870aa2ddfc92e -316500 634fd61f515e6ab677e142e73668fe41e462f25351383262b369e1a622bb9784 0f6cfcbdc1408b6bc3cf64c897fb67126affe7e82ac682707d90894d0c6768ed -317000 1a8b1bfb7cf59f0ea1d7141f2859a289b1cc0cc312836f5754121000a5a08dae 189e9b6ec139450bdf78eb6e37a63c60a13551e1b9d0ab737051cd5dc29dc445 -317500 d2d2e1c03ca763382245658d9e13d60db1c11199930c6edffa504cea704e9cb4 5ecf2ae923e1b0ad4bb52dda4d3c5b6ab31dae5a1152f40688992ac56cf7c1e7 -318000 14c481ed71e0265d9971041215ffa9d80bd9ae3d8a20bdd514b3cb15e6d820bb b83d25bc14861317c60d2a38c2cebc995004a3164e49dc4109d195ce719165a3 -318500 fb1bdbe68f6fa03555a52cc7c70086b585d1585bad7e7f36bd7849b20bd62d7f 56c93b2ec1e226511dc23b53e7c6992905a4c4875ee9146558712faf39024595 -319000 3d520676419671efd72eb59b19a912dd30419f5d50f9dcdc3faa15797e8b78ee f0cb1c494644102763b745ed186810fd2fd2443abbf4c8ef02dd42e20e344e35 -319500 e6f93385e77b36b8bd02e95a7be1daf93e43c2c15df61ad7a53cdf76581c93e7 8679904d6abde60c2f8b0628024a00f1357357852ea5e0085a8557cd55a3d5b5 -320000 edbd0041bf7c7fe4378c089724a0dc3d91bcff7efae1aa5a5e9b1d914d9f4255 83d2528f44d5537305cd76560b0fe1da24549b295e84a37ebc9f7e442f59a2d6 -320500 fe6af92a7429dc15ded665d91c0280feddee060e7a12cea78ab54f591a2a97c8 3840d83015f1c9053f2a74305ec9aaa4ab9c8fca66c62b71c898c0d8e40f94a4 -321000 09fbf5bf7f04579822b0643da9de72f9ffb4e3b086334876dd7ebd4a0b1e5456 3d01cbb877ed01843faf98fb687aedfdd63b6eef204d7a08e5177e93b6315237 -321500 79143aebef47a364850164688450127d503fb0b5fbbf6b3ff422a655973699da b65e2511ade0cf401a38d1089a5ee4a0747e003fdc2c29cd48e47b288d776801 -322000 03aa6946623b9252193d58e6dd00bf586ad4f57dc8fa04dee924b5c15d08d8ba 378b057486d0bcb43313d5206b5e08eeb06be740ceb84456f5cf8549e46157c6 -322500 cf8971a02d54a830b3729fb8f1d1c283135b1a7e30d5cfffb4462a2472467d66 233e6d4bb154d5d3fb1739a4e90a258f0910ceab33eaad183fd2108d8ed464d5 -323000 8d6c05ddfebc0476b7ea506c6edd8b1e7a1f04f46d3d44c404936fd8c8c97089 c8e2bb9126149c636285107b6b51a2ea4dfae6a9362ea82e9a01fc5b62317e13 -323500 f92d520784eb12d8ae3c11ad1803d5dd95a497c0084c88784702a5acce66ae41 81e2f522cc756b27794e1472df684a598aa925938ee87027d455dada0d2835e4 -324000 4d33cb6af695638f89500645f741981a2b96eb2b6f1361cf4915e9df14639412 0d5d58a71b6fb721127f551a4744091aaafc4740ce74e1e094783488946bf46b -324500 9cd5a93ac51080a0a3dfa6e7612adebfd307a7c2ea510d033368490c6d25b7be daf9a838f7b869ca77d3d1fbfa8631bd99aaf46967802148dc7e44fd261a530e -325000 ea1bd97d2e59f6bddba189466ffe1e7be63f5574f110d5b87ec3e0294b2bfe5e c4d8725f512f352599b2a7506b3c52e78012eded7fa5f6bfd99058046342b2a6 -325500 df8156f044118b84c3e2482e346c5639a19b2f1583944286cb9550931c3ca0f2 4310bc5bfec110e5da8fe1dc798b18d1b1453895c70554fb4d52dd7d6d7d813e -326000 d46ca9a4ec0e9126c9b570d00f7b47a005d51f25d9fcbf0c4ca71a29a5f255e6 426c81fa951ff0ceab76207fe576bad3be2279d802d5b95b45881c73827a1241 -326500 603728e060b7c7cfa603aebb548a3362364f3ebd83b07742458a412777ba9259 16fea467df6f746c0a430e00b12d568c7103829328a2bc9b57fcb55c74a66bb5 -327000 6913cd3da36dbaf5c6d407da68f46bcdabeb504269ea70c0cdc219590355796e 745d85006082600149a72c38c32e2d378917153b7c8dbade476f6ba32726c893 -327500 b6538b2705612808867fe5d1da0fb00b6257c3a4314d327b0c6403facc8c06fe bf9d4d5ad9f15c14615c36f8cc7ae29defe64971c5824f95aa535c1bba7083e9 -328000 ff013ae3b0bf04df355f954637c6ca2510479c51180977a99af805bcc8c2d63a fad93d54a8cd267fd2e63abf1da6b26f2f9bc1febac401d4731af0103b31fc6e -328500 ab64d04f26e2164824afa50c1b5592c172469531a20f35a38181993a087a5cfb 24d35a5eb7accd3545888e4c525742d90b01981447d1c2969ca744181e4d6b70 -329000 79384d9bb22811755a4bad2ca7d238243ad975b956019cca645144215ead0547 295fe151911572801c0d4e1ee4e753852edbf6078d7bd798dc5e2da10692e7a8 -329500 1839ba9cdb5db971f72defa707c006ef6ebeb93dfff2bf36ce873acd327531f9 a930915c8a7d58ab4774dffb87fa36a6f9b513b466bd73e5c96965f85ec3300c -330000 829b9c203a0c146c2794aa0ac22bc71033ddd15a68959064526afc2722febf94 e09093eed9d282fce0825778bd7d2c9415fa5b9adcfd2263e7137537d861d29b -330500 740e9f27889b06a301e355ef7dee62cf10dcda17d4023c157c55327420b308f3 a298a8255a0b30782c5d968988514e0437f4cb34a0a2f7df8475a18809007d1e -331000 e2a4cc3a53ac8a24ac52f6fc574d0e9fed0d240710de0694ed5656abfbcbec46 74e67ad885d1f874c4ae7453085f29d254c684ebc71eca3af50f3278c9e1c266 -331500 afdc42adb73a6717f48e35b3b51bb13dc6233645b8a4805723dd771062dfcbdd a3988534eac8b2c3f5d557d1277440783c624597b8b922df33b6fa38b824fc33 -332000 4812ec71190df534e5d8d4965492cabc3606e51c11e4f9181c470a779926dd7b 3d1fb3699e9f859472fd032915cab01de53232e123b1e4c93db2871f7c2aff6b -332500 50ae97dd398c25069522d5eb3b45a2332fd045f6be4d615c7d36c7ccf54c6c18 0bb46697d721417a2217fb4e632513d2ff82f34287bbdd732b9e2f893ac10df3 -333000 fdd8f58aece53dd4f24881f1007cbd0ed25d9f3c62f356a00dc92aa68a13539a e0ed76c2c22a2e784c8a689e1032cf00b65a2702f2b3f025c78e2d1e5190070c -333500 5ea2791919a4000f9e363e277b7522fd9ebc9c06ee5fd9dc15e4ca8984a2d8d2 69d3bcbe827a926dca144c589eaa175f16b6e523b487773b93fee7b45a5a60c1 -334000 cac1a3b80353133e863014d138b408202c77a5759cfc5642546416d73f66ed84 9005b02c03c93c41c6c78357f4323a3234bf12db1eaf36e81c1077a324f7a07e -334500 50861ba6d952e1f0fe4dac891ff4339ac5fb7094205767f2d6233941d2821c10 f77408c3140c620c63f8bedefb370397dab67077b4168c628d787d5b22419aa4 -335000 594b37798c188fab76d6d65c058115b58757893ec32173b45bfc618e8c857fa8 fe50dd76cb7dbe52cc6a9f6c25a3497dc5e4d141e59ce1bafed04367fb155b3f -335500 69b0bd40b74e7fd15be354b734717bf197f1800bec85120b26ca21ea5ac0255c 58cf057f1edd07227964239e7d220b4a6bae95793694841f7a06479c5e5f7420 -336000 71631092dff7d8d09d44bbf35c187c7cb5521c7a5eddb1422f790e52107b6797 e3bbb2e549a6c857855772ad5317902ce52231c464fa78a107811c8381629a49 -336500 ec3497d60fb7d85cfb349bd96712903aaf8a86e6d746f8187a54a1aa5b7b3d51 dc276fdf1858b7a7600213f9b06d4377dc53ef54e112efc864006d28c6cba3ff -337000 70b67fe1ffc39b65d7c3834439efd501fcb9e5d31202322a878be2cb78f741ff b91daa38e81b0b79bbd48c50f9d5ef92cd965e729b075e10b270e29effadcc3f -337500 c5df2f17757c5cf77fc421904662468bf003326049de85bec43003d97a5fc47d 29d4cbe540e3ac54271d12308edae379b59365521ee2f09a6585a82a046d7550 -338000 60ba652d7ad31c96015323efbe454694c5ec72dd732c8f4578ec2f5d072afbf2 2e3a1bbd3ea4e0f318830e43b20d53162ab6b6fbd2191524725965c549360550 -338500 c898aa2617812d17eaa3f8ee142c3018fe2807862ba6d06f309b3344e7d799ad 6bdee06900bdd6c83f8fd8538d75af113af8893ff99cf9a25de6842d3f0d9889 -339000 e0d97756042e78b1c14495a68291e5033c39c56f37a48adaccaf350b12f59202 913f62e783258b88638a7c42b2f403328b683f8c657520ab723ce2196af69666 -339500 1dbe406aeef28cf78b7d43eed5fcdd8c9d7d6d11363cb7e595d7bc1d1899140c 8cee4f37f98fc3da1826dbb96aa525a49fb1fa6db5b2bd64dd3bbd4fb7d6c238 -340000 99ed171ddc0aafa8a5b6f9e5890822c34f6ddf4bf63f1488afde10526c74c8b2 ffe05de29a9901370e815a782c7478c3075f8444ff473b20ff5a2ab311a63022 -340500 92da105d515c1952ffbdcb5f5b99acaa565500d8f4b6e45aa093b61ae53fb7e0 852c42d37d42f8d2c740e57b8e9e769e72445f57c8fc9d1f91e62f029d7d985d -341000 da401dfe258750911b7264ccee0de1b53bd7b90f63d73f46ad5d5914203b59f6 84e7b57cabd661c1cfb68407595a6a9607e0dcaf68f74dce2f8487b1f43a6ac4 -341500 ada69a2ac0977672d08682d195934176caaa7de0baae2f3a32b1391ebf550eb0 cc1d077aae6a1c18f60c874525182f8cc211cfd0a851381773cd0166c108a43c -342000 ff83fa02f1e15e52a1e6ab3f8690bd9c4bcc7f3adf77dda003c6871283b695ac 5983b9dee33342727befc15d5982f9ce987ccee38fef71c34c482c92e062308b -342500 cfcf80f28aefa27c6f09f71080e4af7bfb33f94d1c47e80633187f80a806c6cc 08f62f928db36fa7757f30edd40f93c20dc43c65c693ca5de4c87467d40377a1 -343000 55e1b51f72f048231b675c90224571930a59146003b4ddd3e883bcbe4c8c2685 1f6c53f636480ebaac6569f100e804de9a604dc1bca0a626004ba9852f2fb546 -343500 3d1f67b0a5d905f15f3fe5a7a07aba456ce3ce41422a3bd94f92fd19ce7960e4 4201088ace85294f87bf646209d2e9cea09ac2587654d57c8105b016ed3adac4 -344000 1e718e4e82839b50bb5409297dc94bd783264f1bd3da639f2e4b5444c6765025 c2e0bdb2e293d2940f99295b59d2fd9b57a02632605bc66e4ed69de4e26c4afa -344500 aee9558284286ee6de93a1456fd3cf6c81ff542b4c1eac2c7694b869742572e4 56b70751d01bc1925f288a0af1223f309b7bac54e1cde463ccc9667ea50c9ddf -345000 852cae52d99ea4f4f299f1b5f4a7629ab0d32f8693f503cf74a1f0a31a9a80e2 a627a26363ae216baf1774585d1159977d378f34b54119670620bb82cc9784d1 -345500 09a3e1f7d56b1662f10470c2497e662495b62065364f40dfefdf8d34f5939fce e4d96a1576f516b5303b60dcdded21cb4e3f382f4e7c4b10399ea4b6fc37670d -346000 3dc0fc157c00c40ca92c8125e818f8b5c6163761b0c6955a88eb48498b1d6a45 6f60e0950cb6f6ad48e5b56e9e94a680ac85109ea90ff94df6ccb58adc44d3a2 -346500 bd5552ed2748d686ed3540c52ec7a0f97b839254c953074357fc019667d69188 d1707671c71c75edd986ed69fa0d8462f1d7aaea3e0b5cf519972cd3ce7d73a2 -347000 68b383fb101b4ad08a4ab58777b9f3e34c69143bc3872785c281b155de8769f1 0105724a536021bd7c8fbf2ca7e433c247009c97aa48a8688dc7c9af88018688 -347500 af3af4870dfdc980d2bc5c946e773806957c2f5d98200d5e9ace72e4301d0ef9 20b564b903b75c62b5c7bdb911c753fa67a547a47d47e5a60a0a4790362adb49 -348000 e72024ff3d0ee72f4f78b7e63ade7a7ea037da43bfa9deab400f6739fde391c5 c0ed8b08b6b7d50bf86069b1e8f6c7c36435817114e27745be63db96b5f716bb -348500 1d9d9ad6a6b1a8d5392aa6d35a7472fbf80535ee334a043025cc3637d9894db9 101e9ff2c05137c25a2a270055264bfdcc81b290826d968ca94de4038f791790 -349000 bf0cadc56a8359bb703738a06f7a31b305fe7433989e7e4094f379511e27a19e 2a2cfebba2b09215327049cba461b4c56cf54cf31a0d3c6f8b21a637e6a4db5a -349500 78065cd5e2af5a3a4e838289be5d1460605048c1cf2fd1ef9ba8c88619631e91 aac94ac665bc7ba954323a07216ac1669f19bcae1541459f41534d8058dfd3b5 -350000 937db7a154c0d4c5043fe8bdaa0969670f132252a6c6bf8f7ed5858ee11c97de 8c276300614c430a75552e0cca7d83834ce7bccd7ea1d592012300ac2bc5bc66 -350500 6ebacc5b6fe9ff0e34d64a047981fd170f1b13d40139073e6e65da9a617fbd18 f181abacd6038099f96854c2c0ac8f7d19504609f36dd0aa085af150f21ef930 -351000 156a0053ebf2ee2e68a7ef337edc14044503653188c60669ec924fde43c21ea5 dd728a51d7f9e8f04e74e2116698305470591a6e7937b2c4b714193843eeb584 -351500 5cea6cb5b1b96a2641bcd705ae86c40ce7a8572ff4d6815d7531ebdbca13b958 fd4148c5b36775f35873746e962941ed43d95db28ef21734f4351f1d8a69d012 -352000 43dc3dcb74fcab2f5e90992eedd8a7719f7b7c7658b2086583ef881092f88aa1 eac1623de8acd8fd497f9da85f85614f5cd02c69aac6044f24a3685957009f58 -352500 6b895134f53c26c0b24e9909472962abb3dba5f8b8ab65693ff8e45b3b77e566 aa1abff115fc49dbd6847ba4779ee7c514dfdbe3895e7bc3105b74d0fcf1f4e4 -353000 7785e099822d5b6bac5c707ea57d5d2cabeb52e1e2d82619c8bc2051b486767c afcd99c877d144c3253dacf018ca36e61e95761e44f993e0a4cee0854a7030c4 -353500 c0790882442b7ad61aec5a64faa355a8486f8112f9a691208f38e9bc96230492 f7888632b88cc7800d381774153c34626ff63d859ce489286d9fe904403e9ec0 -354000 de0551272a32e89def017385ba1833443c4e2ec02196c33739deb8bac6cdaf25 78038315c2d8c142ae67a01dfb98009847380ad96cbf6cf700af8693f6260caa -354500 c2e4b7243560cd6e4511d175e2c3fe98df223524124f44faabfc252f57d503d7 1d0fc9a93c812ad30f81462a5ce1fb62d74f14a1672e69dee3a3b797fde53270 -355000 1a11051121727fbe8bf80391ee403566e3b0dce4ac611b37a516c7e3432aa231 f363b96bad7663c981865cd98aa36aa2cadf8b4a623a030e3c7e8a58dea81992 -355500 c877ee5b39b2a7ea9723e1c90b2e307f861e42275c826ecf5b6c84f97c120385 d7cc21f18f45fcba316afb516f70ae028723a709a1a0ad2994579078aec10ddd -356000 4226d4f7d74316c4f9baf33868b492a72f2a2deabe02b5568ef40606641862be a364b4408c45633b64ca685f42f4be377a4b730fd762f28e0015e2ae6e23b0e8 -356500 f0014d06574914b9215379d2b187dcca46081a5fa27d6a32a38efd382a9e945f 853c10ad51f992a4bf0c46c8471046641edaa972c537c8a92b32cc79ff80b445 -357000 1c78c05a5a6c50b6d0372745b8a3f0ccbd6c4878e5fe2227c81bf36cbe31fede 118150dac00bdc45c95b36d35a57c63379205cabc42f8da5d8cac3f8198df0aa -357500 44900087fce8f2c01a87a2ab15befccc1d9b9e702b17c0184cda90876a07fc86 621888deca43a1398ce69ef2cb1ea7523e563dd552e173c3af45eb3f00667df0 -358000 40d642581118288429f0b72a73930470989ff443944b7215edbddf7ad8596d31 819138d682f96c5be33a73fb51c7b698f347c76086d468a3cec421b5ded9bdef -358500 39f707f88dda6ce8bc39c64bdad9d1fe29f98b517080ed55466a8a221ee19bcc 30d012c4929eb3131b7f50c34986d7e1337b46ce6ae7065a0613ba6ad336d2dc -359000 8a04b19b8f068b14a987511d635cdc70ea66e37b63a5c3750bbf9bb2881439ce 7d053e5b5d919b21a1ca21dcb5d31126f519c76f8c0d2816555816496229c970 -359500 15293eeb7f425f8f041248d3cb15cbedf19eb921389a4425b8a14a30d9f6f08a 5b47bc2a1eaaf8b83461d28c535cb1b6b376826c9b554df7498216cbfbd5e76b -360000 37577d18f84202e74e17eb9fd38e760dd94096b4623917c8fbe4eb8c1fe727b8 985b64f248199de5acb5f6dd54aadfe6b2eec0580ac17701e1a6590b46830cab -360500 2db2b88ab382de78f62fb710454fbe0a9e07dc7c09ba76ef26bf72e4768b8cfd a1f4e7d6f52f1fcc610793c0822a6c9a40e0224deb7e56495d34ead537fe2fb5 -361000 3891670905fc1e7ca588a4b72a30c57749cb7c9c2ed47907ed3a69c7339caef6 164eecf5a84889a1ce42accb7ffcae55c4bf598b13720c34eb403fc849dc5801 -361500 ebe6b83861d092f8eff3579515524a45568c743e7df656feb775c45981251891 ba453dda58aa37da9c4babea1597815a99cc4bfc9aec16fc3f8ba1d85a031574 -362000 8524397d4612f5acd6fe921ca9de4e9338e2f74221d4d1755c3682fdbb2bdada d9de4ba457b0d1ae37a2dcb9c8d921acf206e96673d45346ff85de620fc08334 -362500 244d8c96246dd1772efa9b6dedf90ed9933f9a1fef43a5a61fb9d59e9e19645d fbd24f0a05dad2f8048794e8f0c48aef1d9419e28e125ead88eb1127bef72ed8 -363000 2d0854b709d2c4fd84c1d66a736c4148a3b1001fb083f1acb38aa34416063487 eaaf97d25a09d024b71fb1dbe1935a8cf34bf0d30736df8e9a7b6fcd4fcd63c7 -363500 eb76872dee58ba1a3285a93cf5b257a12a903f9f628828bde4dd320ce44ea11e 2145d5e2136393a6d205af57d6544782db4c701b6a5b3f14a90528f30cded69b -364000 043d7b87efe77f8f2d34833a08544e15838bd8b8e1bcd902d8b1ba9dc30285f9 71ad76919b65882a929954ac642c401dd8f298faebf7208aa01301815df4f32a -364500 10b77b07108cd3c1b5166e51eae74df84f39313508e8093af4fb5a5c8db99c8f 9738d20593ba72b8e0f80a8c960f343846b639d3b5f3ac623ab7d7d0258e8c61 -365000 a88f0052b9b490639e238ed8d2bdae3ac573c598eebc036fecfbe8d0d651cb62 806193a3ff83178e6847129340bc66f087903dc85e8d45d50a3843511625fe4d -365500 07674af4f751c8a09011204107b77df887eb0989580ab710bc28f86e1724b972 a59376d69d1fd2b3601728c2eb2f3f935177f5abec94f9b441a6734b8c9dd57a -366000 e7f0e9b3671c1fd8ac289879d42ff60cb2decb8c9fb8095152e444d183d33d55 f04e0f59196d771ea62c59ac3882474ecd053519d37899e2ce9bb2d1a779b3d1 -366500 28fe13630301f2809e429288503e7a341a536de22c078ba11f5056400837d18d a3a2aa196a595a7effa0e8a3ddf8197fa3837c1a55a392f456bbe2745442d844 -367000 066c5da3bfb95638c9b0c37cf99fe28f31cc4852082933305b1561f8b289ebe2 4d69dc379574aebfb8c507bc6791adee838a066e7de10e2e5d633faa6aaf7927 -367500 ee383e75691d5d76bd0d84fb2edb77a9f3e453fe14e3a0840524d4966eb3bfc7 addae0433c1a0e30adaa6bc21dc08c4c37c7ad6d12109458cc8b9c3deb4fa80c -368000 7718d30ae93a53584971a1aae7c71b99f17332702adfa3ba93ac53faa3131bb3 00d48572249cc7eb9929065f4d8e5a4268b69c425ab521e974066c7a15ba96eb -368500 49160ed17423768caebf15a07b978b51b9a50f88cb934cfcb2ca335db599b313 252c55080a47e986faa7b8e8321239a25b25d5109f3b60cdd66c2d7086c32bed -369000 2a35afabeb4c08f7e0fc8564b016b65792e64b6beba78e5d7c0641af63530170 08264c57b5533fcc49b365920cb2d8b698be6d412ee0693e4d78d847530eecc2 -369500 003a85d64df7bbbe1692464040b072934789d092d6f866338b0e9427e823a83e 7084540c646571d0af1e383b6753e92aec196cf20c88bd913e074ff05dd63502 -370000 434d40143a0e8d8fe2e00984effc5579bd3661fdf33dbd93cca7fd72351dfafc bef78b640aacd4fd8598056dd42dfd6557355ba44f18fa9aba104eba4bad9738 -370500 02cf8d2c1db6faf3e7755a2b3d144a4936dcd9f34214f1c8aa826465cc3918e5 24b38a6971f48836c71e37abbeeff129d21fe5975302103ec2af62a337c33afd -371000 2534f9c4ca46fe2df863db301dea97a3bfc6e5a3645f4080d221e9fc214efc8b 24faf019a5e3c38e1e9c941869b93a6c5bb2b2e3e3c754c37d83bfe009f78c20 -371500 1c3ab21bf75be98963553462f21fc369e7503fb8699d9f6e1f635a952c55db42 8dba0c68d6c580055ce406b81e3262b9c7057ba8cbb8b221130766e667c878a9 -372000 b7d862d978a007b9e4afa1f2f0650bb20c0298b8bbce1666d58b009c07014bed f070560c4db4d96f47694e25dc96746634b3b1f172ae1efc8435b29ab083697f -372500 aa2c34e6c03803e0edee9675926dba87db1bed0c89e605dc40c2213a330e53cf dbad4244855f790740309f5f7e49755213bec4d672cef6491758cba12b5571e6 -373000 c03556ea141010a523c44868eca127684b01e83f0a76090906728aa34e599931 b2d61cc71ab0b18171db2117a6d535128c25e68031c3c44c059c7c7965d05c53 -373500 b61ce82c38d812c1e72a830b062bd3854701409fed42cb8cf89d9c83a68aa4a2 3cb1ca2e543310ff8d22cba4bfa2973e264837d2a4a5052cfccde4de4a4a477b -374000 0a2b671cf0c4e82c857482fd9eae13f8212fabc508c3f6137fd3004038d2fb7f fe35de23fa234b6dae59ea82cfeac3259eef5f8d8878aece906a9e71121ed71a -374500 31b2c402de5e4f0911f5d14b927f38483fec9234b0ef67efa026a3648ffd12a0 63c1e30437b3fd68e0529230da7123339e9b8d2079576d68221897e443be0e3e -375000 1673933d5b2d1584e3c923b45bacbae604b308007ff19e25999f5a1d89afb040 cdf2c192e290686651e7f63bbadc54d0d8f7b1d2f7208a097807de32159451c2 -375500 6b35b7e04b2d788de6e2cc8909ab7fc5470b385905dc0e7b7b8524ff57d7d7d3 ce795b401b8cc3db0def999633c2835436348b032919c9123e1481800aaac88e -376000 9a2ec84dae6c1b6dd358c57205e0858d987b68bc1e029cae1b8239ee5ac181c0 d576e0d718d3f594ef61eb7be25e4083d1ead1201fe8eaabad00c63938144f85 -376500 bca044a02b4bd78ddd32eb668c603f16f14daaf04cf3541d019d3421868a14d6 9abdb75f5d7bccf402e2e02a07b5e6d5205822c4ff20ff5531d29d4a8cae5d4b -377000 1b4b732e1f4b18b744aa40196b7bc5d3e1074fee1beb4efc674e38f16deea7e9 04755ac05c88590c66be5b72ea85735df901ee644ea1f35772b82bf18c2eed13 -377500 a51b1aadb6f280e7c23ad430b8c59c8067f0b8dc10a0be61666d1da71bcfadda d8eb0789d6088438ddd828d02844a644a2102dcda7614b262daf994437be74e1 -378000 82f6ad88db9e44f44c837c7a117802a6bc4379ba9141c4faeb9e7731bec60f35 8c48f7630228d3c0322986552aa96929eba1314f8c62baeb801b95cd3cf400f1 -378500 c2fbdc981504762cd306473faab285e108b27bff83a84a1460bf513839d9ee93 37a18476810b603df1cb7efbad84e3b49a24676073397977eda35fb559e7dca7 -379000 5866ea5d40e02e5c73a1828d3c3bc5ffe23f9702292ba595560908f66b23366b ffd0dffc4b8703364b9885055b427f2bea2336714ad4c5fe567e1efbc8fb7b62 -379500 2519dfa5eccc5f59b59c89bf35ecf2aa0f5f8b43ccb098622def88dda5177b36 56df546c0e7bc87f0ca01ee62f0d0939810749cd5fe68fa4848f6f302052ccc0 -380000 7bfff4292f5f17bc71f6763e2257fa585c6d56470390648079609d8116988255 e5c4c441e3a8f0b5f55bb8f5ad18a9bf4bf04719a558e2b954109e5c47cb9896 -380500 386869e1fc8e3f7d6aa8bf28caac3d5a344330e974a42704885aea3cb459e179 279bf20f5fc0c66f97256a42cecb4597dfbee3eda52cc03c01239d2be7ce0e0f -381000 86cf8da3f13d65311d707cbdc932a563a44fc12e1c43de337583bc0d113a5a03 733b60f69120d3ba845a388871c75cec4b4e2479ffe31d83c0bfe980133460a0 -381500 3ddcf06f6b302ddea992508dc99ce57c1a7922d05a89decd38668c974c0d3d41 145aa998b1e691947f9e9c1f9d7bce235dd64fb3101664f2c310b59479a49954 -382000 5cbf96c1818addd8739c3b0a928605824a71eeae2cff1f520e644096662c6d95 0282ec673961b684b9c2c43f17dc47d7a1c4128a19b4dde559103986abf4ca50 -382500 01447f3299aee987ac9c9294682b89f9643f28bf18123ce8114b3ffdb6a03c5e 8a0e1f6c67098b89b81bb0769c520cb50a87299fff5497a87486417b43efb9f7 -383000 d5efe4b385b101b754b2b30f6f99c2bf3736e9fd0e5a06d0b5ed3064e7641852 245a1712512d17bf19156fd5288ebf706e85ba49278ed03c2d506364e7002e08 -383500 5b88888d1abb320e7d295c00a15bd74041ab35850fa768a8786d2e0cfff0948e adbbab8c600e751c331a054924b778213bef9b5a5e23f3d9ca8c9e3b877d8b30 -384000 def1f25883b2060a7b02f078b184a1fb50ebc9b9ee8190971a6315386382328a 31cf28e8a9ff6242a0e4c9b2ba30c018acdf9279b8326185516851a41a15535f -384500 a08467964a472ee61fb3ed6b622acbcec35b4903251cb99324f14f2b9bba7545 720e5881cab3613d6baeb94449d6695102a1e508f1b456ab03d2fdcc32486ebc -385000 d460b85b1ac270fad347a02c19917b9f38ce22c01d8b88e90d0baf63f011b117 b207a874a45789d7b09e0948eafcef8b76c9184aa370a508a4bafdf9d26ebe29 -385500 abe63c027a3d085071de60832600c63e46d78d244315facbee6f0f3fdbb02912 7d911e4630c29d4daf24ef749a17d8b7276c4c9c3f6194c6b0176b4b5f9271c9 -386000 656989d4c67537591081d194c31766bbd9fe449159aa2d3037afa3fab0f74a82 bb24425f9ada80398f6b1e4505b1f6eb372966389f0805b22f2e2d8607aaa38e -386500 2c055ea6793d46b622e43db2f1d25e05558f77edab26f4b1b200bd5aba514747 17499e0c656152df6a2d6096c5dbc50eadc4f19ed4919a04aa3a5c06668f3acf -387000 b25736d7898a4555b0e257ee1e4cc0a96c1275378dcdc0056234846010c29101 15a65bf7b60e7729a9c9a12883b882eeae58af6b07aa9e1e4b7eab5775de2154 -387500 623ea15901831a8ece8d44b5da072e281b237a693fc3524b523f658fc4ab621c adcaaf4a4184c1719060e828a12933ceaf54184d50afa75118d16df5a67aa578 -388000 91bbcc4c97dbbca8f88c68abad1a68e91c79f337a0bb7e14180bc2ce92eac137 21bc2be4b2c59b991ac29c2266fc1cafdfe59da48e957f3105f8d45fe2284c41 -388500 8b9552c05fef1a291df8a1b47d92229429ba2aa1c3453c274bdbf8d3c7c4fc92 f146203b047b7ecb750434bc317aaa95adc82c1fad15f35b22b879325ba38958 -389000 8e938a51863daea6ed977f9068092e5764c7dc9bb2491ac10291921725be7ef6 ccf2ce60dd83f9dfae647c30e824864a5c208ed5c8837420f30cbbc7caa3638d -389500 7505772f28c062e4751b5653080ccdf943181e5f0419069bc20ee6255c2cdd2d a4080018717b150e0384c0cae9a6500dac7779a57565cad365483cf79ea99a4a -390000 6f4b50c04bbd5aed6b57f287a0e6d90a11ea1571dd3635ca9b6ca6ef541cbdd8 b408a6d6415251b4b6ab6db5ae815ee07d0dfc8a8e9ac22c44470916d7d57ef9 -390500 b8caebe933d7dc40b9648b530bc042f1f93f4a1bf6e1530164682a1397dc1aef 192645f2fce9e3b4a7398c935db6ecbe5b79d25d8557fc5ee13d1a5c95fe790f -391000 0e6e6686e469e5fe43fe99fdfb377dc48f85d7892b9aa70e1ca46fcba1fbc940 face758288797482e69de640daa24de10d7a35e17e3b575fe147d73666fd0b75 -391500 fd1e752770b8e555108d7e32c8f6c7e1f9b8dfcb20502babe4cd541910a03b68 89601e3e196aa20964f326b166a74f7a601174815ac89bd1c385a464cee7a54d -392000 529453ab5db3938d1195a3ef84c286e8103c42b7b1b25362898674a66a48ed5e 892462e851252b9a2ee03c507d1acae80ea67d360514a4c5770d7ce0dd3e1f54 -392500 e3a3fd9781e171e256dbee0afe8373a2be01930182de5bcdf501db3a73a70952 945a626198abde6c92ee9304cec95937cb148057692f8a6c5080e0ae930be61d -393000 01db0c4add701bc81282082aacd1fa1ed032967c1ce44c88a46f22f09a00af6f 7b2b867b0ac1dc90aa91e0b88722f474b7d78a3322ba125ce36d0ac755b2c3f9 -393500 c045647644b0d7daac826a34e5f7cdb1f55a4cb4cb5500c16ba4791a8f46433b 8985e0f86f19a7a72fbe581cab68588d1882b9a4b1c236836aa1e559612692ca -394000 7336f022ef425203978336336066daf7f85850fd1ca5ce2be57119543211b7d6 6f1a7d270bd2cd756c02d24aed1e33fb78042efa052bc7e710cf37a60110bffb -394500 2791b8c33b59179365cb1f1e97a71a0ed8c4f9dcf98105ca35275dbfde1b8213 8b5c24c27b2fe79353caa4f2d7548591db269b31c1c53b5e7664a47ff1646a33 -395000 b68a97351f28549882241171a79cb58a1ae92d93a30e7524f3580dfa69bd70b1 a2d0161bea0620be17038a96a9c21a7c5ef08df89362f1e82ce8de29187735bd -395500 f674116f1af73caf4c6d464f99d55c1152f7529c15b0d28a12f35abc1553f91e 32fd584340a63818498504c5fabc21fdf3feb2a4529a6b5af5d9ad67f3679b20 -396000 ded515c3d960dfe073403b321aae9d66a1dbe4a9565caed08c9314e8f1b1d2df 134fcfe75781458a3899ad3330c143de491b74c09c98b8e95c16f79cac282828 -396500 b6745b3e2a46f458eca58083625f3eeab22ca3256087a45aa6457cdbe9999aa6 4124109f22fdfc42c1343feb20ed8a93ba55cd7f65ac34146c3f5caeee272d94 -397000 c79ef7c45f179c76254995bf3c810a62636c40d7283658c3d35f167f9b4289f7 a6fe1a5721abe2a12fce95bc5f5e12a4185596ce991d6af28ad2cb2972305637 -397500 d36dcc0090a5585951004c7f9dd645a5a2daff1d97b796f2dba60c78a89d5a14 a89cd3b2d93dcf17cdcb0f7badfe7af1077f916d6ad5329adfc38a6e1d25cb5c -398000 2b97743e109f78d910532ee0f342b1c491ae74badc58085ba2a7b9029f9fab5f 7ab0985407419f861b725834b5643d2666cbf5aaef6aa6eb94dc9e35c0f630cc -398500 4df2d83b00fd22751d5fc8b22743c9831701408cb9b788d86bf081c666e389fc 9c545b4c3cac0e1d1f9fecd92ba0f7c61ac3e8a28a8c973ff6026fdcd90c4a43 -399000 6a00c77818429d3ed4b9bd5211a3cca69cf68c9a99a89f9e1f9e5301c08afb03 44e27a5f4e4c32f6698257f5cd63ecf165cf4941a94f7473f3995b1a3a6bfd82 -399500 a6e49cf1def602b4915fbc2b208490f5a84c8a93366582f77ecf5575119e6cab 5100ff78853bcfc8606b12c5c335c772964323d7486d55af0fe315c05715875f -400000 641c6a53eaa3c9b94e924327e70830770397343d7927eb713609f14448ea6228 4252f178c0c42e28cce9ef5c0c40f08bc03e3b631a393de6eeff90e7b4d26d38 -400500 73e034517c9649420d36a641130bf16b8634fd3b2568e58198508e65def1fa37 a13f2b06f4b1b3daff6c10571f25318c3ec8e9f2d42c59f4f19369bcbff62da4 -401000 b249ae5082bc1eb852ce420a2361be80dd17228fd17c709761d0f52e81e8478f 679e41c907f1e82c438671466ce285437ba23fa2c845d8c07b43af0829692b69 -401500 ae40fda2bd776861208459ccc6f1d205b769de518dd00aec84f87811e006098c 2cb9da6c40cfc83129da322498da46fbb48f7509d66d7e5ad53b6ccf2723ab83 -402000 53a37e92887f0f1305b937538e060a4626675b361a28d8ac3cd88ce7c16adede d8bd6aadcc2b327c5d2ebe73f48ff2df81310be0b9c194cde8fa5aca004874d9 -402500 54008c3fb34d324191f2e8790f68e097dab91c9933bb83566e2039abd876818a cd1605e18479c4a48bc76ea463608f2c2475d5b3d603bf9ba7555194f6a77d73 -403000 7ccb2c59698108c6ada2be19fe72a1be124c9650abbad735cdcd1b07fb5888c8 208d179f6a09f352c3ce8c445468340beac166c28398132d642afa58cbb06fbd -403500 4307fac30841a99cdb606d9828cd6a920da0155afbea4e5ec770d2e82da4a850 b6304f7d096028bb882b39de8ab14f625d2ae63e4c597d34fddbaed7c2b9f526 -404000 b7845240f6d8ee0cc32e37d8682c587dbc52d07eef8c1b1fa38f73428b73afa4 326e6eaf313513e4a52cfbdbb0106538065a4ed8fdf3d0e7eb6e00ba46037af1 -404500 73ba4ce92e212342e14471f4d85581e85c402a55671db59282110671ede03341 b2af723149653ceffb01cae05de8860e28208128f215e3bd8bc65c7f2d03de41 -405000 3b3d4f18a6a63daf34505404d27dd936531654047b1dc9d1b1f864c33f7ed996 b6287250e883b8c416c65541fbd8cdb01e7d76f989f3fe3e2c31b762d9c3269a -405500 74fe48ee491e1f7e881a9a5918f1848dbd129b08720f0c9f2dac17dd413454f4 d57fd78c8080fb6739f260c4117e08c2214bd1afa6c4244bc16fdfd04804fa76 -406000 81c002e0fe1d6089bc83dc43cd9d616138fb16db20f8ff9dcb039a2bf54bdbd8 7e37f0088205c718348f6f13211a98b16ad8808ed51c824050c1c3793562197c -406500 20aa6245826270b507ea3aa44b5360d608e2d52b20109dc81a63181f9727dcfc 2d722a96f3605f68e844eaa0d3629408e9e20e8d5d095d33c435ea2427420a9a -407000 51c75ef8115644c138fc20ce9af7b771731a1efd11231c881096fdaf59591660 11b150fec2d433d57eee04489446c967a692ccdd64fb6c90f95b150f6d5ccaa9 -407500 6f24e1c00195775eda44acca48e654190b2a9cb22f2dfca41410ce90a067af16 8b49f54e99a2096f0ab8dcf8f22fe21db789b9bad29e43edd3566f5eb7045b5b -408000 ce3c90abbc8da7ea5c5df3c25ad6fd3a7fda496b1e0f696195bda3e6dbe7919f a5a21a4cbf89271969f43d9c808706c6cdb624daf4e5250d6690d40bfef2e78f -408500 ff9b888f601e151a141d92abe7007d40203e6cdbf107740c78a4c1c715608626 3a6e13fefffab34b8bc11418f83163112c871b7483b6cebaac9f9397b5894976 -409000 7f3914a988816ad71eeabeaa91e918ab92df56753de139ce9170256ea433c610 39c9ca62d51e871cec9c9724f12841ded9e81d1b684ba9bbbd118c4d79675e3d -409500 e3fa8435841942ec88357b1e3e0c33702412a83b07c68589319064dfdffaaf81 beda309cb0d0295f165e7ff4168eeb205c921f202c3c9524960152b7ddfa00d4 -410000 3ae6fd96e35b4a84bd063aaf72cb8ce5eda797e213dfa856008516a88039a94d 58e69a89912f506e6f4ed9e89229f9d81113cdaeb5bbd120ca273136117dc82c -410500 eb2bc9bd04d8c2c4ccfc4096116e390bd407e98f0d81b2a7a1f096ce0e86336b 3a87b4d2e3e1c6c5171edf685bfbd0694f293987197b33680dfd338e3ecb4b98 -411000 a57f32043fdbc1b8eabab9e66fdbb7f40066ea9e92d3b1055e7867faa4b73187 afaf24d67374beb37bf9b1c1f0e231ba901b91abae33f81367d55bdf78e1cf2f -411500 ea48060ae79a850a73fb9da920ff9d38245420ff20fd71ee09f5e1411c53f60d 248238d9ddd8abfa0b502311f3e2b21f3e5c5b75719915069a209beb7a1be710 -412000 aa2691852758d5a285217fe3a9bd1c2d29a6d337a0e350abd60809cecfe3207a 5a3ac34a9dfcdc2b17eb45244fccf0fb4e9a843dec6c6f76355c1a81b16f90f0 -412500 5a0807ca910611b9dc9992060c41491071f17f9b4f71b8934e8fba9cbdf95a69 a904ce16e3399f6e8eca3201ccc7fe5b15344c4bf306f1e63da4ab019e0d9582 -413000 6b93d17d702eef90b2795ba888ba49dd4d0d1545784e5d508bab8f3f3700be79 20028cf3dfdf9af6de78fd6ec4f174f46a617f2d3204ba22c3b487d3cc135be5 -413500 1bf2cd60f8c697785716c23db0c3588c42528d3acd6a8427311ad176e9bd3d71 b6e7e1e76a68c20f6909cdcab53f6e820bfbe896cf25a7e435a52ec6c2c3bb85 -414000 ca3778a71094657cab8c697bb6d36930a875d3c76fba72194abcd69fa5c17703 02c6d73c2091a860215de5aa0741c1396c9fb5334dad2786f1f483add87f1ce0 -414500 97f6a6e7e49a245ff3e2acf4c2882ec0173994a21c619f7a384adb93804bfea7 79845ca1a36820aada03e8c46de2dd19dacd64131d91ea5c102bb90df653cf6e -415000 e68357575afa23d47a2a7fd4077e14d22e51b786c8866042263c42ce2f6fdda4 4cf1d285f03ccf0ef31333c8b6ba0142b54791b826f29ed619266270c725b070 -415500 f975006a0b269a3c5e89fea165ec1821ab21dadd0e95d2f372428339a09b9476 a2e3b1b7b2cedaaf531168cf85aea230e8a27131f3643f15269cd8b7fb55387d -416000 27ac3cca7b525e4bced3bf89072f6df21ab97f85317dd242d9698a9f695b3d29 65b7175c50d753059f0955541a646bb523b47f1fa35f5d3d86ffec0077e5e6ec -416500 c3947b6b74b100c5bfd70c7cf1baf822871046f3ebddf211f20ac0ad00660851 ee1d3925d350a9da5ee86bd63c792406dc6a1c70fc0d286dda655687a0b83b57 -417000 cdd42386e134f3cbe56a5b6ff14b08dc50a1a02b70278f20a6982517868c7613 2f7eb3c08a36c3d1ffd90dafc4ce917e3b44fe62e8f545e581af01a2fec59891 -417500 758c5ed9fa53f6a940eb15078bfc3300f68a45174ad55b6d754de04344db5dc6 9d180ee51efbd082e027e34d85c9002b72233e99014924f3b56955f3dc2ba17e -418000 de38ce06e6f7c0509fb958124422fc1e0711c318d7fd1a0fbadae47352ec0eeb 128c492324c57e30449629f7a9d475ccff48d077ccb61dcc5b7f91d013d89337 -418500 52335906771b9b38787ad4381361b609d5eda9864ca2a7d2d22125faecbbf76e 192a8939e510e4b270a3cdcaf4d5ae7379dd0a20e4addae21c2115d0bcad0d18 -419000 d7718cb6a671d3e323e7f8c85b013f8f46dd89353a6f77672806cbddd9887379 ccdffea8a7310aadb5f103ae277ad075b9daa876c08f3bc4e13ca1fe85a400c2 -419500 311eb00a753d20b8c4c073eca48fbf44066e4c97dead7b0224ea65d24dae43e2 5d4d46ec84c96ba390f8d1ab5cd82fad5d412133341c4ec204f36a47462a1633 -420000 02abe9181281799d247884c1887745c6aa80f60a1ceb12693d328015d28b5a84 c5713fdc696198d00a681a1602a8703b724c13362bf059dee081747db8c31908 -420500 f24e5019cfcf1f0612785511437fb2eb94b0a44ae6207ff537b07113a6deaa5a 4c49208f8e5513b0dd1940c861175e2bf7bba04d6373e734cdac63237fc24f1a -421000 0ebae57f2319ea062c101095eb8c2cde71bb38b0df36fccd23fe6d5e40f968bc 7c50e4dcbe642218c07f3bc8df56974ea197f1107b9b523cc8d984f1903c944c -421500 3a65fa88661cc79145ba391c18d2eb928842a9ee2642c757b3731ef399323e13 2dee8bda6a09ea7ab0349f743da33dee3614c069af8977377a94bd87d072f131 -422000 030b699998f98d4b331ef746f96eda057e7a454f98765a0b695d16fd3e7aa44f 9b2c25f8a003bba7778aa66ea405ca0a7d1b4d1a44ab35c28124d0d147a731cd -422500 44dd126ceb8b88b2d3d942246ec2ff298ff07890fc75156510de8dfa22c121a6 fa987f8cf06191b45925bee07fa035ab558e651c1b94d1d518524db426449e5d -423000 93bc08b4a0ce5ef57f63ee483936125540dffca3d9d6aa1a24ca2f69df2e2100 a02f084ecd89f843bf976fcc5f5c3d7b9a5c2b5f549c12b896f4985f3fb18f82 -423500 4a09df19634b6b11e40263176de979e2aa0b3aca1a95825c3ad7eac2a84bad86 1a2acd078f11b82d5bfc43a088c8ad652ac993c2478fc2469859ee4885da2ef9 -424000 bad4fea158757021f14bfa735be04d0514bc3632f96600b1e4d632efc33c6238 ea4dcf8ad8122d652811cb25f7277c96380f8f3b1c839f63d8085d1aa69f5f89 -424500 bc5a6d616947f853ed4f4d9737fa063959d32b8acdd92b11e27dd47b435b38b7 80e414f560811279931e8906a37b79d64836df3f560e19ad9a9940a2e282ce47 -425000 5b30049913f1ad030235ecd4deb6fc86120b8206e5269d39e56e6c5f1bdef8e8 40b7b38eead88896d0993db8806af19167c6c2dcaf989e571a90cc689568e9a4 -425500 1c8c6b6e080abbbd1aae24639ad147ce9dcfb2836be1a4d5520ebfb3a9af61f1 c6e3bb5149886a4050a284990303b89355967d534894ec988b9b9be1f451edcb -426000 9a644de2cda849b362daeec3da5cc28e71652c6a2bbf37151d8ec938e728f2b3 a38d8a78768bea93a802d40ee5d92753afeae17ec5c625515512f4284d56eb1d -426500 4b3cba7009b8a7e4fca74996822c10f661db865afde3ccf0335607d549db29ea 91b61ada9596f861c6ae77dcb3f1da3ea0f39dd623b58910ffbacb800448a8ca -427000 6c5ce8cfc2031e16ddbc1da1b7854aa2b45d1e3a69f2fb73bb14d74a34c702ca ab6ed27075246d24cad1577e05b7c23f081c1be76318508cc5f08aa692ebad22 -427500 8156e4220e867b6f1f988b354b5a96ad98b7f7e83774dc658aef3cb7113d274b f8874e6dca4d1a2e74d442999c6f47bb74a49892a0d9a1894c81fb7d1c350f40 -428000 8dbc7ef6a382825ff9af8347d23569898d687ffd3743285297278cd90e3cdb13 21978c24fad677e5014f13ed54d547eb96722526cb52969673292324cb188b79 -428500 cd56d45be8fc1eef02a601ff132566ef3537c7a69f67f2d8ca6de2fbcff16bf7 f0b9826043f778014106dd4bc0e5429d0f217fce16e401a42ed252b1d2ea6551 -429000 4aec842c5e392ec18423fe3735e8f9c84203ef54f2b3dc837100e42fba29dd61 5e2a8cf8c42f6cbdcd136ecb5386e02eb993ab5314fd3410354159cb6497943c -429500 24d33bfe6e7a8694630a848958175d99c8c5a5fc092437ca95edb5e8f1aaee5c dc92e71cbf3286ffc80dd237cc7cf5ed769de81324291bb80548a79b6a12e354 -430000 64e5cb5e05477470b8068e35326c7e6779e4cbb740cdab675f60a3048e15fc25 c622476e2285d634a82c4720d0a864b11332b9e00c3379f7001f28608c1c4817 -430500 c7938907c4845919f2ec22dd7ff432e7e3e2429e65118a11ae5f2fdc1f5d9ba4 5b34e827fefc85f603439e3367c5bcbb63d94aef7f5389c54e10bf41c1149d09 -431000 a1f4642fec301e246762ea675616ba729278569d221b83e0fee38459ebb157a0 449b183170ba71bd90a2cf58cf0fa0a61ae8d86fe32075dd4b9e80c0a3d8f365 -431500 012e1de4c57ac640cce243e1577db4193427c285579d43614463815932e6f227 c5e13378fdc635b4f2d4dc61ee5d1c0ed7f60850a9de87de8307c9e7e494cbdf -432000 e530822bbe70b043e108e5101b6a684e9b1d5c47a8d0b2e5ace12e44810097f4 211321ba33cbfd213efb8e3df7e7ea774ea25fb24c82cb757e568b756472ee12 -432500 c40c2a8915c595ad827fc5097518aaeedb71832cfdc7f3336789fd6ec0fe4231 37b6a9e80f2b789d61060f97f6f7b8ce019ff788339de54fccb2101c184b810c -433000 c471b86324fb2df461084f3b3f91364c8e4e54b9c592457044805c9c0b1b1ff0 c3cac09940b2a846d2798df91b2e697dff55fcac233473d159da02f5d2a8865d -433500 7c83482c8fd9e4c57aa0dd75563c991933b314f3f18c7cc821204bc41d4c76d3 4d6ebbf09ef39066a45d9157273466fc6e1b08f246396ad00ca6a533a4d08da5 -434000 7d3607cb242e5daa146bb817da979a8874bbbb9abdffa2cfecc546bef9a2cd26 7bbd1335b9852ee4cb13b1d7285dc11f9c2867fbe267cc4b6c1b1a3dd6a15803 -434500 0534c7881cc8c3745dcac6942291cfab024520de1159d3cd1cd6fd853a52e1c2 b08a60d232a23a137cb4808f3636128335ccd3dd10fdcf766ae5c20b64d8a926 -435000 264a1cbeeed20cb538b71b99c8da4874af707bdf7591cc37e8f2780ed8fda372 f226d8a6d56c761d1f9ebb8f5b06414d1339c17889767ce48317564edbfb337b -435500 410932e8557a564a226ac672c5578f75653ed84c4669f64b6bc29fabcdd90586 a5c68267fd466a48ec4473ff1c904efa8eeed2124b7e4bab8bbf83ee876dc375 -436000 c153195fdfcf3938a5dd5ebb0d5dd0ec59692a8decf1184083679c46569b537a 5d8daaa7bff2de12b5d9b428e84e5ba25ef9001e45ab728ec74d6a22c61b269b -436500 5e3b108e26916d2507a40bc30211948a0bcff8ce4b40117ade096cb5f94d22c4 16754de8c6290ed9a3e8769b8a03375448921fdf847c7f1ed6d627e614b8f6ea -437000 06ad60451a13eb38ac6f9abd2375d50afa00d4d8c5dc1c2806bb5a05727ba523 4960cb8d1571d7c0aaf33b659c0721fb84bdda17daad04f0cc169dfe1a22ee28 -437500 2f14aaa3e58a32d5a3f17562b3ccbf8edc8bd17193a9a09af65052be99225a2b 8709492c2ef726d995e4a2092a2d062a849450a00582ccf51fd7ce3905ffd2c6 -438000 87d16a339b0ffda31c75b16f3fc8f7c45d0c67ed9de0bb27027524661b1f91a7 c21254cce7d2b9df55ce98218ab9d20d9d2afc3a450ad1f3931e9c7802de8f35 -438500 b84fb753cd672d1622e7384382069066410f1c27763902b5ee2c919ba3f20bce 075834fbe8e33fb3add9426e52ca900f7db370b85651ae10ac5079aae540153a -439000 cebe0aac7f629f59ee1b2928d8ce4340b247c0c619e3ff53b369375bfa71abaa 7e5fe6db2171c4040cf71a4bbc598983a4892689b7b8da5e3cd161ed7696a410 -439500 7a70cbc08418eb8b711aa13b0a49ca6cdf063a443a0aace6b8f78aa0c9bdc3d5 c7107988cc60c6c66c2c9fce42c97303bfbe3d3db9ebb17da8416d0b1a918e44 -440000 7649654fe753d823dc09f3ccd2157d9e9849e534962d5ec32f5a71775ba31fff 3670ea77b7e5a8750d63d8d846cc2e676e69539125ca1a3f66c1d1573e47ede3 -440500 9ad49b33c96384a916c19e0b7fceecc324d33aaa8fc45b5e48c661aec09c880e e594489948d159bafb11b9a4151a89280c37b8f5665d6d209766ccda296346a1 -441000 2a3a6ecf5d7defaaee82b14d7073402109769a5a8c940d6ee1fd35f23303bf95 e8520de1202a192e8f8bc825b528d2fd8805efb774b18c4ab2f3dd153063a0dc -441500 72fbb24c48304e9daaec1801004fcd4bb4b6c0c511932821a6d875bf4c9e6bc9 13850c1041b5b257adf6f51551051abcdcf13bf6d674e075c0ea32028011acc5 -442000 d8d9a1091bf2e48609bde3ea3140ec19cfb7a2a14735474c6f9ef6105c46c8f6 8879f9476a6a342e58cb8ba5e4e40a9ff6ed0b605f3cd9b4bd9e6cf5dd2dfff1 -442500 78782ee99be29090c13682ee644a47f85f410c5a24c1976dc047f3249dc1e0e4 b4fd6ca7a0b0a77143c457285ecc982da5b9639a5659c03ba88315432e4881dc -443000 a5d7115bce13dbdf436226400b23c30de09f68f6a5137cba50de278effa35891 cfcc7a433eb789185f88cd600fb249d26b8c945d5e5a5d7e978ae3c1c1118a10 -443500 f73cd58af88e5cc893f5a5981888e792f6a15cc06093c14e0ed91110778f0312 22b5b27df320f33c1856dd087c8537e5837c0686ccb436961189989d593b318b -444000 7c497c96ad4740eb68993e26ae3127c6c9e10b8625f9e759131574b87cd722a3 e5405706b778afbf261e0b4ec0a7fdca861baa26ec3a65f5e970769a8497ac1d -444500 cd52d7101a166f4dea73875c0fa5c494db3419bc3f63d539e57c8e853e96cc6f c874b6d14b66ae740907a7ef12eb55dc0983a4a9ad00b27885902a11c72d8009 -445000 30283438585b2c4d3409d61110cc5d400b0abc0cb8e8b65b9fd8619e54dc387a 3664d9de72ce8aebeaf5f1e844e44f5b3362d0faa80415de24c2cf5fdce153a0 -445500 a4496d3bd4aea3dbe7cf7d2d5a3f0850f5c01b04662dfd38d3dbe6736251e91f 8cfad175dbdfb208dc40cdc2f03d0ebcbd9f3b12847f6d069fac33a5c1ba5173 -446000 7cff0564cc670e8a69315b18b0ee229269682bb0286b5e4b3db25f02ce0c4d2c b5c22f647055dc1204b243da18d999adebc56060e52f1f0c4d35450a9e941c68 -446500 201cc692970eec864c92e5e7af036192a9562a62d2723204366bdbfdb0741fa4 f3abf2331a35c83fb86e4484026fbc40266f5551bc90551b90be2d26b3771e3d -447000 c06f8dfebb81f0cb3f19109f662a7dcaa4a023f1fbf735ed81fdd6bf9fa95023 0799398c8a29c71de6027c446de153b17b1bb364570328bf5aea872fa246ca98 -447500 05185f624dab270906ae111fb2c43e838b70a78e0420e84fcc94bfe4fc911dbe f73e1007bb6e28fa8a5add7dc21539c7545ca68c600ebc62b10ae00382c9a538 -448000 4fc96bd14509bf55922cb5d8ed4cbf372f7ce991646e5be3a086204fea0c368d 0fff78f76cbc925b62ffe927d50cbc02dc83fd9e5405a3a77e232b55a494812d -448500 742e9431b2ac6f0ac24e58cb8e6088ac1de875cda8f16739a78e0f1f7c05ce33 d892c34609acf3eeaeb32a384985fd2da70c4f53f59f8c459eaa5e74b3d61c40 -449000 335341c810fdea9e158ba78a542922754fac2e0fece92c27559d14c5c3ca0267 8d6340cdabfbfcddacf2991913176b17513be28b9472b744e7a64b2f2ca13896 -449500 2b97e9d073d0b8922e73a1b1d6fcb7f8dbcb0e22fea6a707d9faa2afa1cddf8f 52066346f6120422b739d9d1cfd8452a00c55505e0b2b9805351f7721cf253db -450000 a6448ff3de412e8784a4d0590120e0727c3ef1c6e98af7adec4b687e10c22b40 b12232c014cf52f4f8d0fdb4037642bc1ce2a4d709ae37b91d908c9d36830fd2 -450500 32343305ccca111d5b0396816091f1f169314acfb4974629e7beb8680523cd47 36cc9b37d7962e434782de92543635fb826a4d84fb5260ca0161680523f54272 -451000 adcb05f8f053823db604b6278de320da2097890b386fe67c0104721e6cd76954 c63c045a3117df4fef3287be2f66c5691b700b18b42d3ba60509faf162dc9720 -451500 c3f6f574abc62ac6ee2b65eee953b3386808361f721ec77e4df9bad7811b0c13 8ed2df18709fd8580694387f903d9c31fa4a7c5e3bf3845b4fa4e9a701441112 -452000 b47901f63e411758d074dd4181d87fe30acb1b1623d0e69701093d93bc505b4b 227dde0bdd2ce1659265ced176e8c5514aa1d7c9c58c5f92d18534141e157539 -452500 723793ff45924363551d433d63f58d9951d58791f6954a6aa906d8c61f80d535 1a931421c2325c0c2cdea860d128402f6ba18decc20e05279f62f0d0f5940f58 -453000 14a86fdf9716b2225cf80394126c1bcebeba3be4a4f103a3497c8eb079ab11bf c0261d2846f68bee936c5ebfb638d9d4e6bffc53519b76ce72dcefa8f66e948b -453500 4204f92e27edb642343263ee5c8265639a4e4bcfe6743c323e5915af2db0f68f 681663c10b07fae27a187f5512c63f266d4460abd46ec1f464e8744b5ddaef67 -454000 d7173ff752ac555014e60e3928c1a8ba368d9ecfacec9b302cda79a6c6162eb4 c34bd72a990e253a26ffe68a91553b0b771083a569e512c6a46a52e5c7b6a724 -454500 df134eb761013d3ba1bd9ccb38d735427a299f2e275a3a1764ae436ba07f09c2 4d9b5dfb6baf847acb9499ef9cedfabe98dd58150569156e5bd692d1f7434f3f -455000 edf2fdc49b76a90ecdfcf0e238e66d574794b7ebab6a4e7d212e1884a21588d0 c40b528799070a1964e73025da6badbda9f994fe3d83cb4ac5fae95aa2e42963 -455500 0728ecc53f1b1b7be2478f687881eff7e6ba31e9d565619ed628ea9263b67a97 700384e16447d9873213d70063f468f9e4e9b1f780104d9a118d86b09aab9594 -456000 fee4d1a2fb2a99260e941a74ab4dc87e0520c28a115ba86c6382791b2f06f1f6 e0487333ab303a6d155cbc61b33eb1b23a3a9bfc3d466c32d8e6793328b3bd8d -456500 b5f05116bdbe8b51f4c1ffaff1a0e0a445e3a0f0c6c718a72d346162820509bc c7a2de5b71c4c7b338b04adfa8fe16857ba3c926fffbfc97dac86b0b75033978 -457000 b414f29bc13f7cac4f028641c788a54786bc9412ed582f4aedd5df86039a8e00 ce69e9060126b330e010d201b073dfc0e16924a8c11acdaa61c7776f0f2d8021 -457500 c2f18fb64768083a462a48b87b993870ab96a70e325cc1b7ce676a504dbbf4a2 bcf97c78db8bc3b69a377a185a429277aa530aa853c7ea12c2ab06566e837c9d -458000 379e0643c8dab2bdefcc1cedf8118337bc0133f0c938a1553088230052f5cfcb 22e7617308101b51b4ddaebed23dc67e0d1e0b3f84c5074039ed77c466cc83a5 -458500 5b8d6a2de4952aa7aa38b9a1d403fd80e65f6cefb5e824c062d060894d490946 56ff3b66fcc71ae8550fd0630fc358edf11f7afdd551d69a2ec9d4b9fe154bae -459000 426443a695e4615554b95c1070f14391c199178d8be6860807b69cf2d686501f 40015ea68bd905903100db2ed67d0a0e25510796dbcd1bfaa0b8dffec058ec4c -459500 561074bb87ee4d3132bd22b91af78df7d2cdec1c6914b43b12a4004204094a4c 86a908568cbb19be09a1c70b4a92a0b3022e5d0008ad78d6ed536a9bdb08deec -460000 7adb9b6d14e8124ab25bb4696bc8afe6a96cdae5396ac2a5d6d859c47236990b 6ea2894408475e17a8c4476b5084cd76742a3cdb97292eba2e2ba0ad4bb17d87 -460500 5cc330e1e985af39a1a24602603f26535df43ea7e5e164c6b654f292bb359633 69c11c20de0f89ada1a65781a2b7e7a1e235f964341eb70434135888794032c8 -461000 c1c45b5a71cf6ed3c5d9a739c227b68fdd3cb41e8102b7e99c28084776c3d8c9 122728c928e7025fba2e58a3b70cf5dbf448e26389be3606b43f3b014d5f2001 -461500 096479184f5b32532940e42b35c51e50008b8224b2c6d6317dc69478d3d316ac aa693ef567b3b7c4a7091b5bb3d34161b4235e7bb3b573a22e66bab0e622f16e -462000 c78d5a646f9130aacd23a52cc3dfc5a084add7fde9dddbefdd13d5c438e024a2 3242055c63d5e14c1efdba0effc3580106e14c443a3c39c699931a6c4a36c94b -462500 b464f9105311560ac63c29a94f8a0a5f378bcf5c22cbd23d5818ebe2e62550d3 4b91a857ed6803609c0f1d514e5793f3f63ea3dd37f84b345c3c64c7248f8358 -463000 ad7d579916aabacd745a9d48122a64e420ba111b8633119f6110a93125eb6072 ab7a1e347245f8d9ca551cc5e89247e18d130aa0180d375673de0578dffdec36 -463500 9f647ead66c59424ffdba0067d38a93c33cbc5cce95c1fb19483d3138d9a2924 f9be09f0a7ec9832b7d2e238f0f3841a10e99967b378bb93e1e8ed95025791e4 -464000 8239a8c5704697db70720d8227fef8093751df0e79bc792a4583106c5229d97c 56a2bdda4613688231ea85b9d659f05000786ebd53300466da5dcc474f8386f1 -464500 b8500802e87f0a3d08b275296b32aa66211d93ba13dffce95a77f4d2ab6ff8a1 87c4e1ae3a488895890a0dda084969a43703e9abb82fa8a6b0fffda090b1fcb0 -465000 9c5f241c6d7947c078423264cd080eebeb852aca6898b71dec1f2fe0f97f40a4 eef3196b8ab3c6d1e3df1eeed6f857644e50f6a751843e308a86d72e945cc6b6 -465500 714cef624738d796efc3fb3fdae8f42478924d28a0644c225374b1e5f8707262 8d68d66be9f3952f46bcbe5df4829d93eff2f4501bf422582e8594bf3f03730e -466000 760869daabeae89da11828967600ecfc92ff38d5eb79326da9fc526ff88e3dc5 ff631213c2cd21307d635337ecefd200cc2b7767c171ba5913ecb785d6876aca -466500 9699ebe38cd6fed8bad4e96c18eeb8bbfce93fa6be86c0c364ac187c246d47e9 f18cb4eae80510bbccc360228942bbde0144f6c66f378e0b4bd0005ce35debe9 -467000 6de68cf541236c2b20da6bb789be6df085207919a94074f31975a54250c4d918 0c998a0b617d6dbe4454ad981478bc5903ace25595e5f868c6bbab61f80cab09 -467500 34aae978a356d729783acb130e2238fefadba1789ddf82d73b87c79d862d297f a90873e05bcc6a81932e4562242f7ca201a07707b505f5dddb46418cfc26c5dd -468000 96a959479e0159621c8660165d2053878cad8adccc1ea5a4020c4a1f63941b09 ad947d10fe2c2fb1f61572586b941c872bd958499342e2e44b545d4c0faaafc3 -468500 ef36c23495b3e062fd2a92e24164f80a01d74452d2d439a23a38e403e531ffb4 5790fe543b78423f088a1d53daf1692a7051169bbf1e469caaa7d3862d709b2d -469000 e32fb17dab672f159e97ac45ddb12dfe0dc0bf2a2abdc455beccdfaca5e2c69b 56f4d6e427a46b3467c26174b6a4b66e30f5d962450273ebaa598c06aa31975b -469500 3870050849e79e3243d3460ea594ef741a1d6327f5d336f8036fa5e97e0cfbb2 2e0823dd7f7a137a063f473cb6991510a112460ecacfe18aba39094d410c8930 -470000 2aeac4abdc914d4ac3fde31a5882b242aa26f1049c86f703fa5da279edad5a7f db8d47e66737aa4776e8cb857386d346d356ba91d0f6212d8aac34c9ac2e5906 -470500 fdab2f454e5102f44be86a36b7c2a54aea2f5681bcbe811942451827e8106734 cb60e3d4e6620535cbf57bf0f94c5055eabf0ca48052e9728fb28f5ec913e5c9 -471000 afd4b785fe4656f48ec1120a14136d133df7059eedf76f407dc2bddb91ab0ce4 0eca3c26dcc9bd50d78a8322c07b18d59c7609bc6ac97258b56b20ac73187f06 -471500 e633efdf19faa95b16be4cb94f7072dc1238342d624bb4d69609555a927f2522 570bc44f8e51f6dceddce363db3b87fc17d9c8ae51ab9266a3d9248b546df4cc -472000 d4aeba089eca88aca7c2b7cc89e10146158dac72fd7643e4c7dada43c8645757 e49b1d22916fa97893a9f31f31bce50f96d49f6a388ee1c8ec2216aa619d9101 -472500 a1c6bef24a340e81f3212db55e9db0bbe8135334e14f66839123c21fa393ea57 1b5318294e73812e157fd78c84b79a31d076bafd91aeda00fa49055003be7e91 -473000 c2f76403fbff7b3601c0b2bc71cc00963cf0b012e09d6be5d8fcc12a8f78c8e6 be2ae59d51ecc553798bcd9c82f4e747dfd1782ad18021dadc24e4838c2b0666 -473500 5f6ff7d98fff43942ec210bff0555d74768aff3e5fd5ab6e0b546d0bfea79921 b828dfae2a89c1199e2cad79165f815f8d858620d87aefe17630048ec05f0bbe -474000 2c191256f2a1ea617517c81c3133a47d2fa264586885b2ca6a7b782f9c78a8bf 7d0b4169707e36667345fa68284bb9eb0dbbb726b9391ec0b3018c71a343ce0b -474500 50b6c4f4c1da30ee2043c4a18b0dfa1da9aa33000be4525bb07b2462d8cabd2f 097a81a5771e9db71271cc6c0ce12a4053e89f2975e8523b6dde6556c170e5e8 -475000 2c38054fd7a02ffcac28fb8c53ad84b68d50ef30af030e597414e15b59bef269 6faee9c17b651d220534dc8c66c0345d162426661af23bd6be235d1c0eef73ab -475500 8d981411752ee6b44f12860a9975ef23df0c7dcb5b5c621368be19033de81de2 23fd87f81163c7f0580a7eaf5f74b7501a868508ba60f47836488f5b72716608 -476000 27aaae6fc04f000f25a467ff5c2fcf62a6872b3ea96a3ca445e0947bc912d050 061c4b35170cf452518590f1e96624dbc031e5eec8b9de1acc81a477bbaa18a0 -476500 84e8616d4259371a11abc9625c4f7d55ccaf949881e017b663f249d29aaabf70 6e6418118d4d34c06bf73284c95f2e3622c87c42ebd4a8e1380939e6abeca428 -477000 d459f75729583c8259ea66e8dcc7b8e1486b0a30e14864332dd014757bac1f5f 9316f02e5bffa72a4ea6c7809be57001db28415e75048320d33dbf23c3a39e86 -477500 329e7c98cde787901a05bbae8aea2a10fa244630640182eb9fcb80e83ff47cc8 04fabe2b506d1c811471d88cb7986d2a67a988e0e094936d398af0b20dafed91 -478000 8515a758d83284a93a354e91ca1389d0dae0914aabde4c7069180dac0f88ece2 0f9d14354952b22318f9909502aaf188e43c511ea6c627724bcb7f0d14550233 -478500 e0b6428a55906d115c2365630e7a748422b1309a75df0712730a018e138f8ae7 75327db1cbc6d65c203eea4cf697e0e8674ff0cf180ad7730c0f42fac2cb2259 -479000 acdd6bdcb3e05e00631aeac70db0beacb5ff7339f9efffe5d125a748e050cf0a 2f4a8780e4913da0886b73e399430b0a65b84e906eb7b47bb14ef6139699e222 -479500 173ac0f8bef2de4b544b42c3506aa887ddb348e6f719f2b4fe16beb569b6b9a9 550714098a237e5f2a2313711787f7037937081893315ca43450ca64c071c798 -480000 39a37003b75d37e0588e177d5d5566dbd2cf4f1ade343067de439e4e60d401e7 e90cf6f99b06ab2f396192723accafe62f0a7705a8795b39371238dc660881ff -480500 675b1ab9b45350f0db5814692844dedce30a416b0c5a6b04e3ec778de1c54476 0cb43e9d578692ced5b3c43a067a09dc8e582a12e46208e1a26841645ebbccf4 -481000 c49b18c02ab6cdbcbd1380535c394567b0fef261db605ae42584fcfc5657292a e45920a96e78f6ef20be3f24d9a8b1accb6ed9b0a9ace38694eba826aafe2bd5 -481500 e70588e89d0a3a15d7de9bc26e47768a94964a14edaa0355853f5629a500dffa f623feb088592f1cc01e94f8984e5bd7f5469ce71ff7645ed81648dcb25ecebe -482000 bdfa119169d8507d41720ba8fa40f5ecb75267570ad0ba58e342f4351fb74575 f28b44f2e70183e19deb6562a107d204531edc8b46d4f5aac76884d7d3a9e750 -482500 14e2be2612c4290229084f2c1edfefd0e432a91254abb83ef8ddbe8d7bf2e661 aa012dfb4ea0b0d0a565fd8f2f55692135969aeb6a9d3f34cb17b31e32ab22c6 -483000 8cc62d490274477579f93e8af507c07b3816d393200aafdbb6b68755b763c2f8 3bce0766356c52720491791bd9cc5a6584c48a39d620bb185f368eb7dd7db697 -483500 72c78ca3f93bde96a8afdc199714ae18e9c15b92526ff48845c050047343f548 f4c218fc750e8b31e2b4f56ea5bdd7f027227b58920c7d08946d193bd090a366 -484000 ad5719becb74523e16221adb2353a4786de357612d9e2ae86753be7035d1074c f040df388303fff9b7c97bfd38d55a94c1701b82ff4f2d594b1f4637fd8ba964 -484500 a143595d89e542b00901e959c20b1bee243c6b7f2a8bd930401a0a922586308e 1c50e70afe27a5026a6ae968118f5141448e69955b431f74c2b94af7bee31ffe -485000 ca0faa2c4b601116d3e03c898bb6fd6de955e9e083910fcbe93303702522fecb 98250685f5d2fc349e6088d617a7986ea28204843abf4e887ee121b3f89a2b36 -485500 1d2f98bacec2bc91b7ffcd9e760c49bc18183ddf1bfb4aac8145abcfe2f91adf c03ae99bd105f3c8154bed1630bbfc10d56a2aa4e36a85d4a9fb2e629920e285 -486000 3f9896825fb06766d9216cf1004aa6d2541642253b2980c59775fa720e1af9d4 e8ff26003f9db4ca25d4a5e8f22c615b6b376f2aba0b6e3d3ec1fc54bfd3e8c9 -486500 8387046d6d520535e933c40c8e7a9b253dea20d1d4fea49c53cca41d13f87b5e 29e01fc49acda9fd49203e03a86fd7fafff8dba947e907ca41db1b6e2802081c -487000 3ee4cfc2068bfe1472bb2345900fda4ce7d99aef724ce5c35e8dafc97472a163 84ee857e054c6f118f897926d53b546c4fbaa38576d66eee4560d88f90f2ac91 -487500 7802c03efcb4298fbff0c05c7c2a2670e2b5c5c0a912260fca95f5ee401f9fac 9c507f7adb01fdb9fe8edd09d969ea7b12474cd9f317e6e0c8d1047f720cfa01 -488000 6c0026aa2c04a1ab5ab59df72d9ac017f559889453749c95937e01230628ff22 89cd039f94be43a6d229425daa26daef3bee7688fd591dc954ee503ebe2f3573 -488500 ad7a33c68b62d181fe269bb58ad9f00b48b4b19f77cae3c68407ba81af9e29f5 e26367c609049d5cd867041787aac089a459ae2a39e420b791b778f49c4222e6 -489000 dce5e567c4502e3b3344804468bd48900df890568521360b198e5b7e48c4a7cf 497cd478db672eb3f6e975b722a162b26d5f0fffdfeabba6dc28664d4dc76bb2 -489500 326013c6ec37ad623eb9c5a35a51c154447c8e180d4efc381f02a791c8dff517 81c2d130a11e3caf98c5d4af0ae7c05bd5d79099d5c959efabe7766a211c87f6 -490000 b0ddbded4a9bad235b75d2dad597b8fd87b80cb721d2c322bde82e9bb3763d72 5abf2e1aa1273cc9de5eab070f0dcd5b082cf7459de699a96e7b12dae3311265 -490500 40f093e9a8e074fded5c67276c85a0261d15f3e418e492ab1452e340da3c0469 0d79b5359c16640713fd6b885d6327bf67971e99395eb633ec71edf9f67a0649 -491000 42ff56a78710f1d58f555a7f55001a1760c7090441dd2657f959a67b2d8a8289 7a167a1f0656c972aaaf079ba002f35ecb7d47aed4c72a7da645276ee21f9ae5 -491500 38a42670dbea9a526f90e8a824bb52398335afd259b0d89f287687810cb3a268 c4f01d0a2b59e7cedc7957ca4dd510eb692cb5ef4c257a76fce04c3e51487e20 -492000 1aedf52ef4f42d0e049cd6f2b564a1416ff737cf792eef860c4678cf4b1929f6 a6c9e1dee9d08b510553bee2acf0d1b8b2f0bcd202ae4d28110fff8dcedd85c8 -492500 d7c8c52fb1f9138293bdf0c28ac68aa8447efcb1246b8896a1777e5b20800ee5 0d6687cf95402d4df5a9115b6786b1fdd27493c88b0e1fba921bb7b722084a88 -493000 e4265d17c243d4e4dcbe12d216d7dfe7e4e3b7da161226203881b0c007f2936e a6f9daa6f9635dcf4a2cc894a4b459a8aa5dc2ed487d95d733bbfe827aebb0f2 -493500 9c3b415ad45f42001d88e2dd38748048ef9f40223e5c1c62caf5eb7912d78b42 e68eb0e1b1b95dea2fff359dc5444930588ef743a58da356b8d33d8e6a0ee1b7 -494000 e78ce6a76a928e878b6cb5a0ca25c6b9a8cd69d4e2db9a066e702635c11ebe17 ea5640b26510140f3abd04e611f124851c15338caa163bea3a5032fd0d16b160 -494500 cb62ce4407ef63b81d3afec33e7b57b31a6e7c8b3e0888b8db96f17e4d39756a 6600b14d7f4f7bbc0f680587684f9fa7d5a7acd26cf9d103ac31bbedf9d6afed -495000 0e8a7e8cc89426af75740fb8469fc9616a8e75401fc785a8e686d5ec0f4e5732 0a1ce34d16dece7d7bda04e5b9bcce126b08d7e514e0fb37c5c1b0871cff4cda -495500 ba423afca93230eb911c2f4dfbba40b893b938a7365cfc2068e1ecd3bc770b5f 5720feefb7971397896c9a270a6318f2adc667cb20f2cd218b2791778cd50680 -496000 352a1fd91dc52fe0cd78e2de4240e75a785420049e7b95e01adfa3d1ac4ad512 781da1ffa0ccbadf08f451c290221fbef9b440c52b5f7ef5bfa3dfe51562de47 -496500 d0743556e112656c069f2749baef59ef56225b6bbee44b2336ff106773fbe965 ebc3df7a34a4a4e9d8a60151f4a5bdce4f40cc8864851520f5161abf9b9e6d51 -497000 1887117917c8adb81cfbf85bd4950684145a964a12c81ca89a44fa107247c275 e48c07018555f1a8be3ad71f6ec7c31932eab7aedfb414c99bb793715ec36e4a -497500 2ffe736439e02d764f544aa4f86a125b1567ab7d24a9d944313877d2d7c39d14 a2b4732449a3ad1488478233895bd8ba26b72f14bf839a33d5fc0f2934bcdf2a -498000 0bc8b494b42efd68080fb3d3d83cc8156b56439c10fa789814d751d5c4f7d9dc ea1ad23e7f85ec30d138ecdf527a5ec5ac6d925eb888ab061b9ae24e48e60b2b -498500 5440fcfb2e8888508c4fd6920d0e6c7c1f3f1095813d45b691edc3a2a475722a 4c2c9c60a2a43f9786004a9b43275656b60a70c9643d6c676ede104b9f0cec12 -499000 d84c475656720900a0b3765c4ed57ae1f0ba17238d34ac17b1635c6c95064750 236f102f6f2350128916d138401344233a7483a0dcb1eb39730c6a5fa22fed3a -499500 8b9aabf8cb60c29c4b60a942812968ab80ec48cad4053de2624d42372a547756 4fdf0de2a22bbd66bcebdd844beeaa7d5caa353352275953936b6f7839497577 -500000 bb94f21cd879e992217888fa56f0cb57bf585f8a41f845fbb46872fd7ddd4a40 541ce9a7c0f8771a84281db66fba7cc2dc43fa636a39a840fee5bdf987a3348f -500500 d74c1f7510c4307c942906d4c66ce5fc542f2a1944659c1ad37a0eb82be11751 976e8ed703619833f8d78889bb8a3a71a06392e257b093a01f7a1b7036d22fb0 -501000 3383f0c0456774cc529b5b0633a947e0708156bc873180f56fe3c32008c8bdac 69c86425b5c47c2bc3a9fe3669b0a80aeeb72bad8179676a55dae6445b7bdd36 -501500 d076738e554cadcd99a14287f0d0af18fca6f893e6ab519fff1a9c987e3aa7c9 9ceace4059979133e529e2e33930ee2ceeb2058633e06c31efecc7d2112a2437 -502000 03b70f8f87fc995b1f25c5979cab284b112e66ebeec690dd93e6c1f238ab616a 5c4442bcce1ace2848f3bbff98abe5776b58af7da464ea4d8ce5c681ecb99261 -502500 99130d7f62752e1e0a7318ae3a933b638ae37528134af7b76590d477bee107b5 206bd50bea02399a5ad897c4e1190e96ba7c092f83cbad5e0bd65955cc253219 -503000 3eeca5fb5aa1f44a7a86e9c2756add708089ba817e4ebe983da92bd815fd51da fc3643c494c343939f26a8237b3df02c2b96235e034e92e199980834ed4a59b1 -503500 8034c879f7596a3d9846ce1ae028fa596b84c62313f9b43564ada16c3e2f547a fd766d22b34e5e391c7a3e8c1318ae469a763ba6c49b75d55b0f928c83e5f992 -504000 bbc5fdb678ff466da54e09ab29562e16a798ae2a05eaf776d97edfa35c839a85 b6dce69571860fa8d6db1cae19087b3232b06b8282f5b905a6ff462528a1fcc7 -504500 956aea829d066998cf96a8b8edb9a0323dfd018642692dd7daf59d0be1b31ef5 f90a6f0b96ed84327fe33e6edf930a439d1843046154fe1fdcd65c011aafde2b -505000 0a3445456f4807eb2f234e51acf42870aa7b6a2eb96749ac3cf764979d3aeb14 f6977bf4113ff5e28895c0f148fa0ae812a4dfed4ac0483419d08e3493c90e4d -505500 fdf15fb92600803d9d99b54b13c028ebe2a39d0681e7cb751496a155b11a9656 6fdd6b0729448d9a5dbd5b5ec1198c5f89d0a437c9019c94e0cc4b0cff9344f5 -506000 94533d7531d5ab46aa3ad4c03ad71b8a6f78574805a683be4021d3648a56b0b0 7c1f8200acab1aa87ce1ce548b727d3c47239045d9dcb6d80ba58d908af43c99 -506500 0f86a6ffdc4880c047c73dc16aa8d0bf27d1dde7700c2fd77e4cdd7e7d926cd8 e9c9a93746ec3a17feb362c2dce6e9a9c51a0d9f0d9700d21bd8aba906602e95 -507000 431e08381fac05624f905ca38d18e788204823803e0607106e147bbbe8bf688a 4ac228d8c9c41f4e3d3a3c4e320ed04c13be367680f9fdbe8f6e5a7ab2a23f36 -507500 a227a08c0b6d0818ac30280e4cc9f422bbb17cde711c371acb7fc19c8a642276 6dd10139c09a88ed1692aa137b788336a80ccd60753eb237e90687a15ec987cb -508000 ac9eed373dc35d2906cefc9e3ad2c8044253e75789f4d028b84a5acab33f8187 d4fcd4e62b88c4ef4e9609e8e5c85ba44b15b999dafa68a7cd45eea0b9fee193 -508500 82837e772818deb177c58056f9b8eb8c42b42c75053c206ce64d4cb0caa569a0 088031bb4d6c8d50690782746dae3a2894e04749cb8073703758bf84403f65e9 -509000 46d4c946d3305147e565ccd6bcf5049931048ab9fa78fe64a45fcd29df7edeee 0d2fb9af0d18a37f8bd0d90677391033552038c5d24a58db89420c355342bc33 -509500 dd8574ebf8743606a8b2692ca8fe7c406487b6ba9a0eb1194eba2631c7ce67c1 2ff727ddf8cb09ef0622821c1886cb8270d4401658d2249c402f48a6ffbbbcbe -510000 8b496633b233a6ff9deba1fc40f3e1ecff693d91d8abda762bb165b4f10933e9 3a409f0d90719857a525deb2038518acc44e2e710e3f51830c11f3a83c89ec22 -510500 1052dbabe3ecd64ab6a4b0b05f41c6c4131f5beee2028096f688af8da17151c9 0cdd930cbfb6e609de9a22d029c15c5106fbb5603222b8e470a43594d1ee1dd5 -511000 e1718d99ca8b8c0e1f84663aaa6ac9cd8c369e9118bd6ea5919856382019f5b7 8320100810a7678c08ef0003dd4f057369386278d95ac3d9b316a062b1cd119a -511500 df937a1ddd9ab676d6b958c03e97b7789fc0b486d52e1a518f4d4e46d22db830 e5b333e553b5a4bca5ee6f4a3ed9d83ba46d981a3ce30fe8fe0578788a400f42 -512000 38982a86cf02da0b76412cd5bc52aac39854cb1d000c7f24e6b66061c9552820 7b4b3c77c94a5b9de5a7ce479a1c15ae56663e655104b0f0efb5f3adb971cd4a -512500 c668fd92e5ab8abe4fa8c66022eaf0b8387408849349453ba8751194bc9ea391 aebb86a20afe467e4959eb4704849a076a8e02cbc51c2dfe07648562e42f9f5b -513000 fa2042f44dad2c0e4b243fc07a60172d057c7715b7d7f73e9cdab068df241dca 9bf87e1bf1a619c55107e28f3abdabc3bb3267a0b0225855695ccae2be2c8492 -513500 3ada907b4eb50e027c4dce815bc8464aab74eebaa02c3fff63e829fcbcc06790 1504730fea3476e4a5a65059e9e45acf9fde314062f93761273d0d47ef900b5d -514000 b690974d95cf519aa561d59afc9812bf23f8596633d4e43638aefd0a645cfd9a 53527239f3915f67eca6a1f57a5b82564ca7c4c5344668140b960adb23246528 -514500 4efdb833ed17ee35a5c830945a287adb464a23d60f16c1f1d6d3488d628df9cf f6990f581fe79ffb9d1bed01f84a338213c70bc996261e07507624df42c528a7 -515000 f902ef1df4acafde6dfad28852fa03b1961241be620aa057860c9a70a0fffafc f8f7c7f68536f87056eb0a199f0112974f80f4ca443721ec8c1d67c3cbb7fbfb -515500 df363417aed948a08fe0c6aa48dbc5764fd5cfffadbc7945f1a6ae310a9a1d50 d55f6e43fa28f97008367107abdef40ea271780e5d19a561db5f3af215e60ae3 -516000 6af0f998e7b95f5928801133f52c03133ca1d706f044f545812d0e64afa7eb56 79daefaf210fa29d3c633094944a6ea814f73589d3d477a38fb6d68f0380795c -516500 c7174fb637f35bc6822a651eddde06e842534badc1d7a4c2d61090e79510b970 ed427f81415ab5bfc57f4cfaf8461c18a23a2ca0a7ec9b48002d694c70137716 -517000 f4055907d0bc72d6e28eaa1b566ab77904495bcf286d0dd6d7bc297b8fef7a63 74104317e7c69033b643afb089ea06cafe18e13f125bb7a2f381ac88d362eb63 -517500 dfc6759e8ed2c1078dbf08a64b71ddc9ab2a04fff41fbe9a5c82a250cb3ef4a9 5a544c7180a99ca77684597ca3cfb1257ee0e3fccd468e3771c55e4fd9a1152f -518000 3f867c72bf194f1c257f1476aa4cfd18cbe3a5df52e374b1f705e496e06840c5 36fc1c6723e3e48773e1bd8ae04210fdf0a9d22cce523387250deb28c3793a8c -518500 941b4dd50e5124b756a381e83ef95106d15522461c348d5e032c1b61d838e50f ab5d00a5d8df0c54e297611a063ba4357b4686259473accba2b139ee69dc4d8e -519000 2136325d5351d77945e009193f054b04492a8d8f210eef016a51630313a17c3a ceaa807d0b581d95060026f8ff02c392db4fd0ab5007a86053f9e0b93049aae3 -519500 8740a71b16e0335054adba609b5df4dc066d157dcb0511442d8d413c2333d883 216da33354860bd3b2b44d9f217b89d2a203836e5f0c04de39381776c78d43f1 -520000 21557c530c9135898351f2625779248d5c5ad1fa473d8989e8795cd650f3b036 02327cfdef960f127b2a99811b52f651fd5f84d3064dc10b2b8c4c528a362c2b -520500 fdd0b3a9a08562ab9256162fdf1e8aebba6589b585f34ce26ff0ac20f3b35715 cb7b802cfb533b7191e892348f4076176e842e2a598e373e6653c92b62b4d5f9 -521000 4d45b8b34e350a098a5ec1575639465783982db7710d4ad07f7a299a19b860b1 587836bb3390bf2dc472a0b9e20a5e643cb270d85ed4286180f358cc8d0dfe88 -521500 8357476f03fda1bb1f346946484bfa6cc9d80a89b508255c3c4b583c71ead128 2c2d08c950c6437e2f9ff89d0c3b0d0467a7761a0f19d421e0c0846c2792bb62 -522000 a12936a6677badc6d2c8e83d2058abcbd2deb580e5147f1e742e379f0ffbee7d 322277c4d49c9c37e94b84c184e09dccd63cbf0154e61e36b497369c4c7f3fc4 -522500 f0770540ebe64a0de99c169cd1a7d9c8459eae0e67873510f1a8dcf4841131a3 25ae4d82a8a9089095bc4583c9842984d53bb4b0e6a162d369a70802b7f9476f -523000 72d57e281db8b4a79f566fb587e448883bc1d1325c9ffc2931f1100b63e5836c 00fcd8bff8a5e19824f0e98fca489d02ca2d27fa2b4fd9a73e410d935a1b93d1 -523500 97b2d54ba68ed4a14ca1fb4e4b697b2bf8f7d0332272af4531a72c94c35dc932 04d4f8ef5ff03931eb5c0eac18894a9a7ac8ac7f6bc0b34b43420ae9d7802a1b -524000 f5c96b25808ab9cbbcedecfe467e163e3bd9d771a8efbd3cc414c7adf1b7d380 c11e17455d687b0dbee864879ffb41fa6dfefffd54d339fff58dfa99790a78f9 -524500 cc5a17d877467df92ed0b3462d0031003c642f64896f4019da641d1572d693e9 471a8ebde906603f5c054eed0da8b69aee53c35133712be35b22e5b4a8a3435c -525000 1b009804fbb8489d23d5512262d7536375873ef933c154a7058ec1c934f61892 d583cc3f0f7f01c67294d2e98d28e83c81824cee30d1252816a7828c0461f350 -525500 63de360342a1abd256b2f4a3f1a74da8e5bfff409282c8d06cadfea596220f9e 124aca94373c78ba91a8f1c01d89d5bbeded60581199d3b12ac66b76c37c112f -526000 25464aef8a123b8bc5dc4b9f6b83149c84511a88da41f7b5f6ddf4cbd340dd30 ca911108aa51b78a806e58f876767baaf341c9844f31da71959ed4ea2f87d62e -526500 54cfed1a647b8513e845b57381456d983320e1f6dfc26bdcd4e97da73f31bd60 a5639a2ead728587161e02add9b047738a8534d0725a84c5532bdd054e715ee7 -527000 d601736c31be7964de7a76ee1fa2c4771d804dca1c1a268b608f3c77971893b2 1831200e768d735e9bf8b5ddddb9119ec19c43e22b966bd969346814cf454d55 -527500 dbfd9c8fe9edc773e210401cb7341166fda6e1153a1fb47f866b919dbef91d31 5f15be969fa28b64f5250f0787876b05adfcd2c64ee1c2c72eb9724403ed6dee -528000 92d74a8d4df0a8f7510fab8b5d02692442d1fb8bb9046cff981cecbef3353585 b67baa2dd73a4061188c5cbaf13ed1c063e29193fedcac0b5440e042d39a45e2 -528500 b4a034b57dac02980cec5830c0718b0ce4a89bd3ef3f5f36e8b4181c1f42ace7 de92eb4a468c264b4a9ad63eb75ca3702af7c023481c829041f328797d2e3636 -529000 a05c9409ae06d5bc48284e5c624f8d6f6b001cc6f887d459043f442367e5e1e3 dcb56fadb166de779d9d0e4e5e4d30dd558b0ef3fba4f9afc8023ae5715d30df -529500 f62867ba72013c202a9a61da49b6e4eabc05e6d247f2ffd98235b8e4d862e795 915588450e5ec1300605afdbd6dc47954df1fcb45a6a10953db21bb54bba5797 -530000 35c57a8e961f11ffe1cf6712861b43b4e7d3cc3107c28d6d8722de90506a5b54 1c060c7a921b2d8567acb70356957e7aa044d8e37abe1923ec1ccd3f0f7191b2 -530500 0aa4f3b5419e0844a7316ac4b76e00f3230781c8d320cdd62dc1dbe21875dbbd a3bf6f2508bcf7bf8a6fc19b2a75859a8c2d3a68858d6dedca2de5a5c687b94d -531000 b65e6fc5a87f8d30ac2203e13e9e9fa450ada17650d6c639fde4f71d2832062f 6c4e276f9cc20e4111c9c45b760cb529b12e6f6f9d984c6338e47ecf0d1fd5d5 -531500 4fc020cbe21507bbfef6eb1cb30c11359f8ba8ed0fabfd67181b596859a11fee 736ebd1d9d616f4132934784dc13c0ddd6382616a501f11f84071f39bb794a0c -532000 936bf25a71f4f427a32035e860b049c5e0ecf36b0dc007608b31fb9a496b058b 9c412485687232293357f94ea0cf8a76c84e8757046eae59406f5ee225651a55 -532500 51b5d1a338bf32a3273b45d2dcabcc8fde6bfb68f80624624b8a0ccecfacf751 81559753a06dfa90b7ed984962a88154310cefa89233d47edce8438601051981 -533000 d80bd2b8d148cc346bcc49974171c998a30bad85878c6e508d16c728098d5418 cd8c0e674768e8afa69fc6366c3e2aa66ee31b8a10cceba75d3148857442c30d -533500 06cddea66b25e0387bb678836918cca4be53f245e84c01fdd8194ff147377a1a cc77c89ce8bc38a702e21b00df5e4e65f2217fd7e3d330aeaea89e67b2906d7a -534000 0427f67b170428d1d33242707a2a8273c6447a2762ed42e49580526cee35bb3c 66b923b19b1dae626b62a5c76dc9710d396b9436cb8cc549b87a4878f457e561 -534500 de3c914cd38e7fee1888806ccd3d4cd5d39b81cdd22f869cc5c2d5335fa29533 77b2265b37eef1e316d0d480f28bbaeb8faaefee270991fba6bb5680a65f5298 -535000 b4c2ed2b12c9b6ee617058231e9099ceacfbb10e344c8060df631fc42cc276f8 1cef714d86e11d17fccfa377f5550acbdf781a19f272cc8917c3c9886b99414e -535500 9515324744b14c233fe0463842b81e99c1c7bb28d99234d0c2126ecea9a3250c c96091825c57b11639c7eb8ac6f6c76d48c4507af32c1fc95a93fad60e5b1a78 -536000 ba4a67d76d58f76b3cb47b9f89792153db68285c94062df446d924e59ccf7b87 6208b177efeaa145f365051fd3d5f9e82dba8c42f1d0d2b67635c4a908b7dd17 -536500 865528966307aa0504e45931d75610ae56b4c4490c763198c1570a66f75b1f1a 09c2e4d9405d693c07371d2eae527aa1c2311db979f6d2d0abfdc5467b81cb65 -537000 c3355c3c49454bb38156c96fb23c13fe9e5fb73129bfae6c61ba4e6d1e46ef00 29ce20cbec7687f75730f0e4be6c672d1fcf96baa9168eefe3030116e7f06b63 -537500 895be1cd157309627c65fc37e677a72fd82f27d0418e6b43998aba564d205369 d5e4a2bc8d014079e205050f18f390c776f5b45940c5835ed995817dbcfb9da3 -538000 99248aee8ec1681099e7018b3f27ff7d48023639c7a16f846ceba99bfb8b6794 51589b8c95d4c555e3e85904368362e86c1ca65ee73cf4b3a56348352d48187c -538500 8ed90c82d16b675f2e1616b4e6877fea7d223f4c6049c8abe24071ed0cf55cff 0952515dbe216e7f8705998796c926f16186b5d911466f31d36255852c2a1740 -539000 5eee066175978a2e04f8070ec0a1c5e215afe79e6342f882f272e3ab3e5088d3 a8fcd0b0db8bf7fa522a86757bc674077b64491860fe1e1c346d48b5056c3625 -539500 1fc7f87c388bd6e524b114ae6bd9654031d2cede075e50c5070d5f7492238b49 86203c750603c2b64073e488e635049afd299e58642bc90cfc7bd562fa1372db -540000 c7c3d0e72955da1daf3ed29a7f50e39bbc72a97a7a3b9657151e2180b297bfdf d8789c0edcb9150d9cf88b973a2fba35c0e8a13a79e9f5e6fe67eb527f100dda -540500 078244b881a7ea8079cee149a21afb1f3e12513eac743435b26fca944d1f8c0a b0d2681f5339e6747da87fbdc8eea0947f09458e9e121fe715050d97d5380b1c -541000 c1fc5936f601dbe88f86537a73e3082d817270cfc534f985e6aadf1e69017c62 c5025d93f22d3c16cf3f1be03756c8a04da4c330a8779bb156b6d6812b65db25 -541500 f06fc398ee363680986ea85bba8897ca25e7d7398defc7ae5dea8950e5e10b9a 6eb30b839ec9f6b85ba6a68be9a25f4ad0d72cddfcbcf5bd4346e61905e1ce37 -542000 f1133f6d4e5f03eee2ab13868e8a296ecb14fa9a0fb0074e5fc3cc46a1f7f2f9 b1827592124a51a20ae293f4e824c8030eee78ee82ea039c27e427fe4d2da5c6 -542500 7892e32548d849918dd9946be8adab0f8d0842afa1e9f62c066d27924a96153b 421009927f9b4183293a0e7a57882322f87b30137239b6db48168b25d1fc5ede -543000 656da82150e03b0f6920c13ae9f012c768ad1db9da51f3cb36cb08f597c944ef 3fdc935dccb715960e745f505147ea8508aa5ba7c7f2a657a14ee46eec52732e -543500 9c3e877261982dd30c2c1c7bf6604e64b22fcb0ac6f1f31d133ad853e8b2475c 058abb454a8f38b333a57e220049716ddcf596ca81ed33fa28772cbd87968bf2 -544000 1ecd239bf3296b13b04cd7aa240769324beb8a9de6e35f10c193ce60adfcd2b0 7321ab6022acecdd7ec7526d7fd560c768da79151c01e409de85f70e8d9d9bf3 -544500 ab6981fdb795d866908290b102477a670822935da8f8af9c6a32ee740d69bbe7 c1eb309bc65e67917e1c46e7d0f232900974267e048abd48a1b04e1d4a3172f8 -545000 00257b2829d7c11f95de86dee675a7edb80dff9715bd2ab64d7454182f213a0d bf13fcbf0b1247b11accd940ac8772789e081f0bf1cb70b1425d6288c69b1e76 -545500 ea64a39237ad3d242cb2db3a1faebecd3b20c682383b014227a3f230a3345dd2 09c175ccbaa02745d5f72bb6f68a9b32cac259ecc88aa1f49bb30d336d79bf59 -546000 efaebeda777c28c7e35347e84da7681aaa14c502d53698838eea8aba6e55c1a4 79194dc97f5c84f2a55ca245e93b69b5caa44c6bd5e581044e2e26580bcf561e -546500 bffd9b66e5207f5cb60bcdce5dda495ab78fa6206aed6981bfeb3ab4961ed56c 2e133bc3bb1e140288f0abd4ac9fa18fc4e30ba6fa672f75cdea8fedbcf093cf -547000 b7c08bd8cd06070b6b52aafb511d26a3e4dde18e15ef004576de6c06024f2a30 6aa7c21876ee2145c6b97d41d858abf162abee2f179e94e354799664f38be6b9 -547500 77b94303d50c7c640f68812f0dd13cde9cdc2b43c5f6e3fa4c99621be61279a9 31c6dfbadc919ec783b0bdada382c4c3e1204008b245b6455679b08aa7f2a6bc -548000 bf973366b8395a897b56bb1f9160f8144c40ba17934fb14b46d2bdbb32715fe5 a732ddef1fa97dee750cea03675a6eb9557af9ed6314a162f5ebd8ded9407698 -548500 c2f20ed6a252cc714238efd5531084bd5555ab8ec65169a86c9a0ba97b2a7eb5 d029d1bf6706c1b298d9f7ffdd53a26b17704433c42683bc02718ef33d2d70b7 -549000 7e07ebf8ad3697390d81f7381637048377f461e46030c8eb1feb17eea4c9d3dd 1f2183d7618eabf7356a08a0486675b0163aafe13e6b27bb6179fdaa59685fce -549500 7ce04ee7a21eaffbe862646c3a301460da80cecad0e9a66a157bc1d0c335a18c cc27c95b13f1ece38002d33c7f55f371076fc10dfe1b48754e3418a0222248c4 -550000 0b717011e4c14ba25388b6be779ec7a7fa2939c68a49ad5fc8cccb32a3fc96e6 d95f6b2500300308ce3f44e53c38e6f0eda793b3e1d96f698cdfd8d70888e277 -550500 b1388fa70e3a79143b985bbe2587a8a36a3ce7f90dbdf93c312bf375b04204d4 2f81d9add40226b4b3d3f2466a2330e412de80bc31cf3242e0f8e8c1f45f1a88 -551000 b0f768d89c0f0e5929e41afa3e9711a2f6dd04c71519c718ec5a4851f13ae4e4 2b1fb05c01f17b3eb7268d552a99acd306e4dc0107985d6020dfaf4443dadd73 -551500 891da4a1108be080247fbc0089c4cbc2922d25cf2285538261195b41bfb48747 e5f1700d6fa46e80db5586d1f3261b758d374d43adcfbfad70ed5112bb1bf603 -552000 8a4da9058e5aa3a483af0775ddb984048bec5a52dfefe711d620a0d179856ee3 333c9af8ca1f58b6185db26d60b4fbb955176320995ce208f18aaacd277b4f1e -552500 f290fd729e75722394720a4b82e34da44d640af62c995fe6867fdd9167ba8335 e85093bef089d344639461c61bd1ec7819d5105b4f984d423041d035335e24fc -553000 2558178ee645f229d1b39f11e8bc8e423e6665ce3e7491ca195fb72d8a13034f 0a823b23f9e2761e8f32e42f7bd569ebb56869af3a1093d7a170f792605be7dc -553500 001c1d53874f0032ac25fabae2f92deca9235bd409eaac1aebec39bd798830d2 d36b5ccec99827a8a5d775d707a82836c0a10d13bf9199e25a3c31bd17f66370 -554000 e2710db357675cd18df933733e23992517017ab0507fa218fb45bc9f5d812224 786326555bcb406ffe22d8dd499684db1b8b70df508572f1ada7dcd6eeae85d1 -554500 cd244e1a5feb9d4f3a6c51f92f1c9396b8871ac5a20cf587092abb68b4fe2eec e7a78e8e16dc73cdf9064f039df1a67996bb3eaa744f2fc0598bd07519078b24 -555000 1a6ebd86249e3a3837d8a1eff644e240333704c7f9c48515e849578016d8fc8f b5da194a23915c042e044b0d3e5e1856f7640ac8344a013d7a1c459d967d6eb0 -555500 978b357011addba581355b92d3faf71397a7c55689ac4fb0d4a6eebd8409f714 519677a9eca60cabdfcd5e888ecb570d09275bb7e2585e9226a9b664ad0d7fe4 -556000 edc28b6ce373cf5a5d13e86ffea09ac385d8d2bd251ea07617b10abade558e12 7b3f6c61707185443f2565ad2f228bcb006302a1bec5a203f143e730c681a9c2 -556500 95ae0bac1e11d4df7fcb554f665966b3bb2195010c0cddf48d07803743149578 1c9c7ca6f9c8b40134151daca7a7cd1b7cc24deac24aaf2f3a450b34b74730ba -557000 a1cbf8cd746fe3b27616f6515149cfb57408d82b8147c19510ad13806b7845b6 2287f21d56991d98d17edc545f93a85d01b7919fde25d726cc9cff6f62d97461 -557500 1cd1617ae1474529b7b4f322db9442763fcd418410a3c3e918e17f13966491d4 e71635aa05a9aee0ca857b41574d348954419959f8782b6aa3b7a3e0d3b6fb43 -558000 ecca0843b0d748735413e34ca513454ce2497271cf04a9d12455f0bf07c09f22 c3a7537c5ee0d6615a53e3e30cdcc6433a554a120756be6247f3c3b703f023c9 -558500 0bc0b2dc367328ad409219afddf852412ecedb43e048ee73449cdfa5e152159a 64f4cd8ebaf6f492c200b11b080c521f4efe87e777818f9012e969eb2dc0fb57 -559000 ac95a1595559d38fc68c9dc48d9af40b3e31d71c292a83998398af38f09b3fb8 a65b3a0e37cadbb31f367a83edbc4c70d0537633af498c9ece211c681fb9f671 -559500 06afcb286229def7721d7a5bfb22cb59f1b25c6aea819bd26456d5fe0baedf74 b871a3c694108b366de593c52d6a1b3c38af1849b0092e5474275258239e6088 -560000 538bfca7649306c7ad77eefd31a7cce9b81ee7ee9d20d97322e9f785cb555afc e08954b12673a8e87fc4db6f848c2129d39286fe856ab80f3a11480a82772963 -560500 05fe497d72e403e9753264fa5d4a7348843e07afbd260e21fdcb9898d9de63ca b538d81ebe3d0367d4820f155315debd0b078100fe17f3ec6a0c1b1d989fdf8d -561000 b80da09d4fc326223399fac5659ad647dcf37232eb63546212c7b951d429effa 014c43fc1995d966785af2772de5f8d4738b44785a2bd81145d32236931bc978 -561500 998927d54433d0ea4fe19a4ab0eb8e08ae656e8cac608e3a824bb084967a37e4 a7709319ad385d1345ee6171bb57bef2d0a648278e6cf763068496eca01d5315 -562000 a005e7c48077a108e353402f478f0f3cdbadeb95f360f6d4d056ec8aab302f7a ad678ad8a4b421f5211b5953c3080ffde18f2a395f5f77a467a6a3991e155b97 -562500 cf4a618bbd1d4eec4f6ca3993fb2b3ce901592c365c2b7526c9de2d0c98cb74f 05921bea10fcdc426b73459e8ea0ab421c1635c93b60ee8d950cfa0efa91a126 -563000 ffcd676fa825e67eb4832cc72b5767f50fa306f1dd251055ee3f623d9fbf4d6b f3fcba9c0dafd172664da1d0e692cb1f4e898f23eccce5a265104164a5ece2d4 -563500 5f96af414cb11afbbcf48a7fd1738fc1c8ae91dfe58ccfaaa7149264ce34c5d4 54756714dd75d4cbcf87b452238296c5acbece0f991ff2cf3b239d6af4b7f4ee -564000 0345b35925619ae8f774196dbc6ae52b2d065ee4ca6f9ab87aac366307e1512c 7ccabfabcd36f82cc3195d587e6b530f2e303525e253d84376f02b907e1bf611 -564500 478fd153799b8afd93360f4288321ae7e82aa7bb5474f13913274834bd4b1ba9 b73b7af475c03ffe2bd0e9b09f32a966126d650007f991cde96bc8ae208d2844 -565000 4bf82342209df889c321571400c9170621b17c9b88b60b609a7a9a31a4e6879d d33e0ac1f8f8614cfec0768dca67ba99561976ef142a62171bd596ca26265462 -565500 18ef43d2230a09c588644154757d4c3136a0dcebbd1e7169349f280be113ec99 d3cff22fd147792fef86c9d94f7b8553c555a925e7038e738bde608c83ceda53 -566000 178cd3b2773545e457ec933671f4b7e0cfa269454371789d79c4c73d879fa497 776636ace5ca4a51abb4f04c22d5a2a0c51d42368f43b8b776299b087d1bafff -566500 6e70ed03c1ade6968a6f18aed75a42130abe4674a9cb3d6715d5320474a310f0 9e51b370f5e5b6dd65ffe6fc854265dc071b7dddad6a68e25a6082d60a4573e8 -567000 6a0b1d677c5cc0ce3f890ae8495c70403ffae874414fec9e3ec8b3aa73bfbf12 44a2fd59a3f18b4d59d7bcabc842bc21681b3c82613c95038aec10315bfdc050 -567500 aaa507e4d8344e885c748389b8812c28ab49533b13fa635bb345a4495be34850 f0b2d2e0f7477c8703fb6c7ddaf4d22c17da14d6bb1be606d96b4fe23932ff61 -568000 058e126ea94bbb99030e2be4364db58bbe0703c0fb4c3155ee7c386e19efe976 e68dcd0c11aa8d9b09161d9fdb25196b0b02017743235c5e77c83314139abc6a -568500 369e444ff13a9ce379c2c98e70e2e50e18c823b4b43d51e57224f9d7bf7c2a82 e5755456750a9a92ffefb86ebd18fcb6d4f790bd51e47f1dd92d5d0db8c60b7c -569000 50685dcbbd12f30781fbb546d1a4cbc349244a2d6e14ccb1530059e4073fc0d4 5841f99c2648c1075709873b22b8bc25695c01fb146b0e82291b6a0f5cf16fbf -569500 452253574aa43c9f3ecd39f7122789bcb9c83e343843540860b950ff27d673cc 2ab70f1d2aa896e8a8495df628e675c983e45047d719a9e8fa0804f34a8f82e9 -570000 c1b6627d3100900dcf795d2b684e83d11a797d2302a3bc058dab61ba109e5d08 997761e1d03f77cee9256dcf268f308a14899d00386cf1cdcd9df39a57ade810 -570500 7cd59e7583d4c4878b1dc3171dcbab4832d2c4d61512d7f313ab88782a9d9336 0a439cac39577c5f0188a201ff1ed831ed2fbd5d819c6682d7aecb2e4b77b7d8 -571000 6aa099647512a9654c54e730e3f1d4a1fda25ac58387503932ded2817e5b446f a629a59a6420e7edf13f0a7dc05a918f86f9fb337459a1f85b65cdc71b301d92 -571500 a3d2f0b075cf3e735e586c69c3eeaf7a07cf0f391e1a6ecada1327abe8ab8c8e c97c75ac8bd884337edb7011ce4a68f31d1a06f477d821b9e473614f871e059c -572000 154d5a1e996a34d40d3aaaf2244d5df055de5902201bbefdff166b63d440090e 38fafdb36a68381be6d3a3f358ee61f1998c8647949eb6659f8794c5d84646f9 -572500 05d47c51813cee5f42bf7803a627ade017772b7f4e734fdce5a824edbf480359 ce6eeaba07d4a7d43ae137f3f66d7bd2c3ff0b55b973c0e87283011f58f94fc8 -573000 2cc24da51032f6db15842996a46a0f01e17e7c1fa178d34f4d520e57a1dec5f5 814f5511a95d2112e9d6f5ff9147e4af6d2d14c674008901888a59d77adc0127 -573500 5a412746451823e5fe7cf63b331c59b6b1808d176c1f3562631755a1aec62267 a8a55f440729934a987fa7bcc21e4bed9ae4cb4fdda5bba05f328d33c1c93dca -574000 4e71a21262bee73564eed3938de4c2a673ae763450fcb183bab52fc3739e9307 f5fd0fbd347c9146a3356914145926887833b394f0664b2e5d098660848e8b5c -574500 bee3161612969794e4cc7811c35fb9fd844623da6a5b5f2dc38f32d50728ab90 d97f6edfca11c6cdd984f126252ed5c39587feac95f4d412a947fb327ee9f4b9 -575000 0560ddebf2a1fefe36dfcbf14c0b9e2101445b34e79b4d2d2f7c329c1dc5c97a 58a5850806bdc8a70223873c23aa3a5975634c989d8ef4f4f78fc0b71c025a59 -575500 077c9db46dee33b8fed0edbe55dd09ced1c04eb22096d9a7f0a8238b764a9005 a527ce25eff18c724535306c76670e1a44b010183ad970d41e4168c7e47e8ef7 -576000 f9762a0e8b01efc84c09bf94e0eec3168852cac22bf5e0e657957ffbeb857c08 41b866640d3804e09ffd386d7f6b0cfcc5e95c65991fa0b753c875676eec7c37 -576500 fff9ba66ac3dd62ff0931e644ac522896b5e86c2a23e04bb4f2501145dd96b75 def321280e76f1a8aefd6607ded8cb73769de57f19c641b7c6356e60105d89a6 -577000 69c48c7908b7b71bde3ba3aaacc99951cccbbf4ca98fe699367cda9c2101efe1 da1cfb6020117eb45c262bdafdc11ef962f6156c0c95e68cee1bf1a2b7b9a1e5 -577500 9c563371fc767b2343d7f1cf6f23e4cc7b42aabb564e94a5cfa940cd84330cb2 33aaa085f7076d2841dbce57b42bb7c61739c76f041c130becc350efcbcb5138 -578000 e5b36705e126028107e070cd6b748d0ba1820ef3f0b7cdbd8c60a822011afbe3 b2797c8eec34eb94ad7b5de3c93144e6511d79ec389cd2b3037abf705da704c0 -578500 0bb4c3b62c096285827dd7079f91bb367f08fbf323f01cc27257c6ad1b6b09f2 2709c029d1cd3164ac618ca33d9453913f52247ca266755995eba29516fd6693 -579000 62ca69f749191230d6588250d41ff452312e141c30bdc253a4ba473d3736c8fd 9690b50bbb4fae4acf7114beebb9c8f012328638fbafd2f54c18db4983c019fd -579500 ef36ef78010479cc9664a2e7cbbeed19da7b60b990ae1d6ca1c62815b74e4ac7 dedc37c50f5ee81e9697c49243e55aa6ed5c5ba8d1d56305c5120b308600fb6c -580000 439f43597ce36aa161cc2c4cd7c25607edada72003a7fb681be2f6d8b714d14d be5636a23710b20c61b3aa181bd75a4e0992dbfc1d267be7c66a3bb459ad10cd -580500 c6b2c13db62622a7c3ac9e8072840de5d24c34f6337fc3d8f826933501245deb 25eba3116b640e04a77b843ad79a25847d31c2c5eef7da98952ebbb526440eba -581000 4dcd0d20d94245063d630bcf6d8079cbc52dfc522c0e320e39c16ca18853cd6c ee3c988f0ea99a39c2cf69e88ba22aedaa2710f49bbaccd1ea0b2c1ee65648d9 -581500 44b084102871018a5db5f990085f3177856a38a8b727a36b29837c34e4a8ce59 6d6899031aab90e68c34f4bc3c1458960c7debc0e5e88de13bc0d29d9a4f1406 -582000 4fc26f1bccf775fbc7314ca86532fffb93b9be94bc6f1bd75fbcbe688eb9dc1f 07296b68ecad02d38df4dfc0c927b430ce4c978fd42772740cfb185d1f73cf08 -582500 fcdd7ac7dbd7a3ec5bffcf498ca341ea6f45eec4f07fcf5d838805979c154e75 1fdcf21608195ac2f0076e8203f72e8468099613e8edd350440efb4fa495de35 -583000 d32c77f1ee2542c91734ccfbbba36b35dc4b76db17374b52d514ab45e03031bd d7414a5f1b9e801ffdd889f95d91b381486c2b7bfd718907df3e4f3c16f831aa -583500 bf8b25a2a0b19d293bc739d63786a6e5be7cf111d60d6cfea462dc2cc7cab22d c03d273bfa3ebeff31d43a7a1fe34b51a5c968676dab85910f61691ea66cd879 -584000 b3ec434425ed197a317fe360d7f2bdd065a7f167e5c57bc9623cd150df2aa5bf 42bd629da8bdfeaa2aff0cbd4092f1db54db6da4e4487a7460ca7081849b1d01 -584500 f09dc804f47fc9fbd5a391883d0be1d3ccf5b71a69e9c2571ce1ff55b83422df 28cec5b73ebea11f29daf62db2ac9a594a7497ede4087e0932881d39343d15d1 -585000 5874d180e9c48959e292587310dd81134eb03197f0257be1516c7c50248fc3b5 c5e42637b4e90535090b09f2d90d7ab90ce46eb3255ce6abad941ff07ab5e0cf -585500 a6dd4e58143b11d190e168b1dd20fd7da47ba2af0d089f70bdb5ab423c8f47fd 134ef498a9bf87099abd879d68ad7d67ef4dc45b63bc16438aa0f95092e34c8d -586000 5fc5f5de827b01b620304dc74ea53a0fea4f814bb51ec5fe3b6c74ef560a5917 e1d0845de83160f08be85d114882976278106adf7a3c16ce16ff6f08caeeba7b -586500 2d1270ba120a5cf1427736d7f89cb05c42af508e0a0038833c9445dfa9c66fd7 be7998a06e1fa3910cf77a7cb385cbc6933abee919664bc52a52afa5388c5b0f -587000 47ae47f30d7d51e5b874e5ae103aa38208203f2a380b624cbe1ba122d222f9e5 81558ea382a62cc93ccc002e8ba9d88058ebfe683b05be16fac0d84612ad2152 -587500 a558bd54422bc5d0a90c20310f81d9901a9d3956f5d5505a5dc50b6459ecaffe a8994820ef7c6f2fd8d9b6d710a0f83b537ff6fa1368060418cb00ddf642f357 -588000 fe5749f9e8ce47f885f4335cf2b24a6659913ed62e7d5af026ef0470004d4983 87e2b4277260305d5bfbd921b2d4592e180837e092f2acd3896621cffa5228d4 -588500 4c798283eb8cbfca17647b16a919d49b77a999d0bd319fa624ed665b30172e21 a4c43d466e6429ac399cba93e1a594703176f7d1d7f86990936973120554c72e -589000 f8c9ccb89cd751d66c9e2b053cdfa670556f6dafac1e67a12f8bf06790c9fb93 ef76c7bdbce08ea6dc8dfbefec9d64b2bbf3180dc4304ee7e39d8c098ce3602d -589500 0971e83e6a813fcc290f352ada5422a0f48b12e15628f9522d1ce40b2fd01e85 cd5ac7829f9c4de5b606b3a5406383ab2634f09661977f867c47d58f89f16081 -590000 cc8a0c71618970a1cd40ecd78572568e8522faf1c6cdf597def52feaabd15eed ede2c72e45aef2c244f56183b127ef08f9137effd46386eb8013f1435de42f08 -590500 6c876707aa719eef0d5a9534f9961ffceadfdfa16e75a4a8c7f5c7822f8d9945 44d6b98fec0842acf25460f93ac90ce132d3600c752bcfb18d3e4bea90b9e052 -591000 5c5a7be46768f7b29d8912feb8eacabb2c592fac374fd8b1c9d74124a5bde94a b725f0ce70d650d386e7fae730da1d44a308d2517c91e0f6d6fc659316647202 -591500 4df0cd912fb5772a508f9ab6fc5dc26ebcfc8e5fda9026d682cdeee3350f7f99 1a9e6cf241740c2f4f615bf2017473e6eccf52ce14ca3c244609c83411749374 -592000 5a9465ba2bf3034272ebb1a8b742abe5b66607193dd04f838bd9a2e9525081c3 c36756b7c0b4f7577f33bb7a6a2cb06d444e5bfac823242a2208a74dfa4a5264 -592500 8e712cb434a6086e1068c5a36a70ac8382f8bd2df8f3328e869b5f74c4d3e268 1f6f8f8c7b6abb35e1bcc30443a2112a1cf6711f020c6474ea2b987e122e2710 -593000 5d4b59deb55edff702d98ceafe7e74fb2c27a9e82b3b8f38a747c0013210125a 397321c39e0255bbf2f345d8c410a3a75f0cddf11f90b04e1fed22d57313f436 -593500 efab77d82b76d1ba1f130c61a5146828ef22808cabae00e8aaca746c9701756d 5ae3383c918a2d0de41ef7e68ecc81a14448ae6265fec8146377b88c14678583 -594000 2eddcbffecddf8dd19c6183606ed678b8d3c80b3d18a03d1f6c98de436465bbc 313ed4476687d320b09ed8f775c84f848b315ec7051a819b7b5db928b06b10bc -594500 17c2823062fbd036efda8d7a6cf9f02177470df9ab03a1ca6a49a4feceaa813e 967817ffd15c1eb09ae18be9c89af301d4faca27bd1435a4c1b016328efd7452 -595000 0b2d83d89d4bfcf2ba0bb0d6f4f002f83b33532a9c72d204b84c3624b82d1d12 ac1ae8086c27ae5dcb5491883fd2c00dd1936ce5ebb753bb9721795b51ac427e -595500 94e93ae2421b77bdb8eebc5a889e0dbf64bf0af3a9d7d718b92c626186186adc 58b3debd63420f3503c3f813e1fec6e2dc9de31eabbfe6a5517eda797c5a1381 -596000 e556867900ceab6ad0fb7923aaad1331b8a44fb432ed5479bc8255a9f9889db7 5608f70ec745d7dd10b0d6650661ee7db9d15ead665ce8062892cdb60c51b81e -596500 e07b8c8db8312393c02cfe1bc00a1a5ee6166083702d2db0fd24297095202f77 3df091b27bde63d70fc8d0feb4da1e97ee21915b24f6be2a60bf702051c243d7 -597000 8e07ad6645a83dc63b311fb7d39bb583980164e40032a0821d0acb50953b8ef5 96c796666a2f4c215410baa022874914fd9c04a430313d38e98f6c5b743b969d -597500 6681cd271934d16f89af3d71bdd886f5d3d50f6ef9fbe17c4d95eefb6c770974 e7909149c034c8ea84b92f77b39a9331560661cb4c158edda770306a4ed7cc9b -598000 92b359d658152c31b8c2f32c4509f3ccb1cc18b4544745608da9a230327c109e 3f75a2b9ea70de0fdc330ebbc5f83301dd507c4e0fe536200402cdf30fd28a12 -598500 be474d552a4f17ec673478af48534ad3c65eef1752223ed3012534dcc4274db4 9c304d0d24348fa013c7223f1e05fc9092a773e6da14920e628baf05669a0f08 -599000 275ca25666031af015670734cd4fa02ea0e0b099921240991498e684bc234940 83b44eaabc822a3d26f168dabcbb175357e1a37a025813fe30d5e6560418dc4a -599500 f20a2a85028e0a3c65f118e50296794ae25821fb5dc0a59f415305d826a827cb 3dbc1d013d4559da355fea928c27fb17e921124893b7052f2aced8c8ef9c9085 -600000 fde9cb0677887e2f966c3be87d1780db88353977fa2e426249d9b26b01be1db1 74fc8f58d336eaafad2f515f0b5a5eaa679c82160f2dc54f35fed44bb845c395 -600500 ed2fdfc9d3b07cd7e4d4fb46b5cde484b7ea5cbd436608698ba0be6407928d45 78eebaf2d54a3f5ef9c98b58e75325a263d7040a85d2757eaa6fcd9edefa8bfa -601000 3a7b3e53a5c38bb7d0600352a71701c8c7b961a9936d319ec1f39eacbfa317ea ae8e3de2cdfe471244ac6698534f60a82a93e59b36ff22135ad57f5ffa9eddde -601500 9ac84b004712eedc9cb82e4eb4f459e92634ae20ded19ce2a01b5039bc9be041 b1800a6430feb20276c6d1f65b1042d5da3d547a575d7aa8f8515985e793cc8c -602000 e584426ba4821ce97899bedc37ebdc5667d94f796853b5dbfc8597123f61cd93 670512bb3eb55350a01e55a614addd9a1936e220c349b5fdf83ff85d36ee4762 -602500 98c1693b6c94cebd5e17bed36779a7c1498f43d83c3fb9f833ac42eb3b1f148a 4335ab6f363d6556b820a8527702f5b224789aae810a9799c40289f088d876cb -603000 cc90f10fadd0c325018a7f5b2819ef126eeeceb29cfb1abac3aa4d918dec8ce6 c323abc97d8ddde6d935f4c4a3748fd5df141948b855062c0d557814b6c57582 -603500 88a282051002196bd7e47c2d4d05acccc49be9e0a1958c608bc8857b0752d805 4a129ae3447c19b8a4ca1812fe819cc571bae08dcee26b2f312bdb2292e7567c -604000 8423befd6cbd718339237b9fd01a9bbc7de101525a01e45777cecc593795e76d 10125b30e2a5762ca8991b3ee699bc69e552b65457759c8b0a85468f52575c2f -604500 5f07bfc38f07c663a551462ef3fffbbe9a1f01d54e4987727649b2cea7ea3716 f17db8519ba7ab7e3cd0442a008bd05dd5354ddbfc696dc9e2aeb07385929acc -605000 691b12ae780daabc6228123ba85e5d4ce2c48d1f6084a428ed5d310d644ae101 15ecf51f40220aff461a2662902a91b0ff974c6b5dfc6853a37d492ad0e7c507 -605500 52537e09d147a2eaf5a3e843ce45824f3a0db686f36cbbe72f69fca61a2b1c01 ab643490828905c7be3f1c8afe6f7755a27c4cdfaa5c8488fe2441aa6afaa70b -606000 945062759b3b417205cfff5d9b2e1c29d29fdc235efc71971a5c930ef5fac2a6 5cf40892ca34be01dfa549d94b8784051375b2949ba916931a8addf7eb3a9216 -606500 284cfde9bc92fc8a9a75636ed0bb98a68a7d26fa82acfdba09391939c2e9acdf e0d8d1c85bb390ccf48b59af60483c919c08df0f8830de5befe65a43a53a99fb -607000 fabf1c22a50594542dd8cc8e0aeb6ce78992e1fb97dd46f25b1f766392b8c466 c42f95954963685fb338b1ebf0f0de3c8fcbada7fa53dbd4c0472b7cabb75eee -607500 a2af7276cb9398592a0f0d137875baf3d9291a606f583b269540f9ac44a17ce4 b5170fbaafdd9059ecc043f1c4ca714de50133bee7054f8c119e0eed79e20ef1 -608000 6a78949783e00a8ac3d832c24e69a2c6fe028f110e8f1a7d87d652acfd5b6b63 01ef19adaaf1a1d75900879f2c7bd5366ec4a6811ee539db16e81a2b981c192b -608500 1941dfc27e96aee1848d5fc8ba94bad2507ee14f8a24235e4b35af5dc0559f05 559954098665a3b7a698445445daeee8967c092ce38be59cf1fe78ce354d221c -609000 ddb824a17fcc47e7312cbc0b80838b8f4fdc077d1f8cad5b08008aad8a25afdf 528daaece3c6a912cf0859f93018845f781575fa67f27479ccd56480f40b8c10 -609500 3f80a004163aa45d2c9d2a1c8bb238a15b9db4214c8b0ca08effb0f37697c40c e6a2eb1304a43261fa54127676cdee58792115ca1b400c4a08261f1e170f19fc -610000 0362121a825d39875de7eb528be247603e5d93922f21f738f255ad44171f5edf 3b57b352f45dde9c233dae766260ea380cf6114c7682dca95566e656e9be1511 -610500 d39319109dfd619800add37b85ab545fe8832c50036eaf1aea5489348e749f18 14c16bbd895be10be482c66ae8444f39cfd67f9c3c244f86bb3f309f3f38ea3d -611000 274d0b2789a39a2808a69e9c7d4fa6b2b34b7be5ad55d541785f6230103a6110 610d4811e3da6b704ea224ce3cef798b3fb9495609971c09971691d88b714885 -611500 c25930007a1325f971285a32257362f90f6b5da474225d3cdd19b9053a55e6b2 c052c3e6c7b866d2212ecc66d4956d8b3c0a9b97381a822ed203ea796ba58581 -612000 8dc46e21fcf1b95e59d6be6454adf1db9d141d9e78d583c0f4efa47e0b2e38a8 538c9ffcee5485b309bce281d6913a254331647ab43d492250c66318503ada14 -612500 48c70c688ae362b4ce2e19325b0bf5335301f45cd6f0f562ff263d5d57324a2c 06f90f226b98bf0fff455478d39513800ed400dc9dbf41c3a6e498730c883e42 -613000 a05ec2324bead1349845a8000c76ff7705e0ed1f958dfb46c92eaf3180f301f7 4d6d1eefb176cf04b6cc0e9554cd81bcfb00e1f737ffe5e25e752f9eacfb20bd -613500 6d0183915fa23fbe61d2cfa7dc9ba9c54c164b246d9f3ea2bf28c675203896b5 e233a4490b16a593a62853877efc01bff2e03b4e5017027fda754056171236ee -614000 dc4d72e154553d04502271aeea36609af31e967faec981fdb7aa7686b194ef72 a20198e44d09d5a45d18b1b2e20911f6d8840ae7618e39f1805dead4136ff220 -614500 401187c2be8053257741c3c78fd751d5aa80b74239ac1a5fd7c2008623b8056e b3d69a8f679aa779dcfd6b03d44da4318c10241e1a87c8de46dc2067879e7561 -615000 a7edfae28117b555c502b1b0866e70c2e45b2b53095b0b3ec0518f76a3250e96 180c90afe2385b2149b5622d702e1ae33e1908e03fc9ac457f18cc86e3453813 -615500 247cbe6b3a28a410c816bbf3e344fd707f5b98c9fc7ea74a653e55daae43aa7a 675ffec485147855367994e9f3ab4ac5ad7bedfb39a35959ced78034e9a04318 -616000 091e39d1de4719fafc22075635a0ed10d1d8b5636a21927557b2baee8bc453a3 5cd5dc9688dfccc2024c771720a75202758606c6c2b62b3317eaca215338eb9e -616500 245d68d439cb7cc9d17d41d8748be112448c1c3d757746c28c32e3531a23a66c dddbe95e870b48d8e1d3be72da7976def8a5f96e20846bee2ec8d3644de876bf -617000 9a08546acd2859279fbf0a140d792be72040b3b5deccfdfcc3a40d640c60f35c 3fa1b0094367169cfe3c3047b01a8bbe5bd1179ea5252153da7113477dda7bb6 -617500 ec4c7a99f349f9b610a1c2c94f01fd8e37bf98d8feb6a68874517a47b27a199f ada5742a01ae9d78a4aaa0fefcc2542633e90bdd178f540e802a4e5bf96368e8 -618000 30bf0bf59fc693f06b630ff38f55f5788f24b27fec1c171fd5f63b6a75729f83 a4d0bec878322f07128ea1f7318a28c492a27649b4e216332589628ddd9053ae -618500 095af87395d73d93df9f2531ad54c6a486b0c98fff5e59a75d9f468e2317b989 c98bdb9ed3f618281b60f496fad0753ed0610f95899058a5662a45bdc30f2c2c -619000 53c7aaacaaf469764119760051cbb7be6806f80d51f75099d8096831443712aa 8e52bf819476612fc0943a9b56d5027935ca897f9a5dfb686cbedb8dcdd83bc5 -619500 7e55322d59a65d0ff1be11ba083fccc9800550a273a52a77926d5a67c383f429 1cde548b5fd12717415c6f8ab191b0a73aa77acfb6c8db2ab9ef1f374bb8fccb -620000 ce46ee172a243c059752e237dab267c4c95b111745b808bb9ad1f8e99dbe84cd e14873bf1154683503d0b3a1d0180742f3eb790efe5a968845a337a4877f9cc8 -620500 31fca5e075086e3ce312c78e4e67a24a245c48db04b7d07688a46be3efd12560 d5c066fadd66b4053f35e728308e8e1e9594693f9afe8f930e342f89014e1435 -621000 c27deb337c86fa6c1a9c967c1c0e967d66ca91c3a605ee42ca9ecaa3c7801715 4bf8d5ac8c9c275f434ce687e9aa2e5bb0e1c1a8634ad7dc0380ad74e9f2a471 -621500 6d6de5c0c183af66e09203c1f851e005b11ffc3e65821a0b0c53ddcf0577a86b f8e09ce62f6793636184630998b1cdd6e513174a268fedfa3c23d1beedd6f127 -622000 3bb4c331c1c410066bfc9c84fa96f35f008d7ebbb8630f35616b07d3a8f6bf09 2625b34fe7f2c205449f2ff67a4bfe036ef5f479b520c16f0fc16ffc43e5e713 -622500 b69c590df86c64c53eec4355ff7e4525ab0ede7c40da8cb6304556c465708619 ea025a51dbfa831f98ebb1597cb43dc29f34d18f5522b57ac06d7e19bca1ed39 -623000 248e12a541844945c6b91e45f24d7f63db3dfb41016952e628c647bb82562c91 d2dcaa98eed5db5e34581c8bc52808819c5cf98bd564661252e24fb7f98218d4 -623500 0f6332963afce6ea94d654d103c3604c724a5a6bcdf6e32bdf9a708d10de519f 80f5b0685f010693bff7453273d0cbef3d878e9753b19e05a5d2fdb4984f8a0a -624000 3a250bcfa462ff8b750d0a725962879d47832f0c77b46dfcd27e3eb4bf352257 f75082779f75cba11e26f60eb9556caf48daa15221abc2b4a83a1cdfff9368f0 -624500 6a0ceb40f1277b4289334b6cbd593aa5bf593160ea960b4887e40afd2b06d767 54386a3f312db13d8151cdb5ff628ac2e9e13d897287b553d581a6c74cdad388 -625000 c28164fd18e1087787d2e3c7d67b8349aafcadfbf815fd7547fd7ae8da9e7937 319cabe08b33898fc3421e1cfe329711de03a92bdf21828a59594e813e71393f -625500 00c9e51e1237a00f30562f40f8d7696876a62523a7888f3019103f97d27c2afb cc7d1fd4e2d9a95e3a9a7e23f44a96f6840036265a29cac5b4a364ae1ee1b806 -626000 452cd22905dce67c27114fdc0b6ca64f4127abcbaff999b7aed68be214fc9313 c969541e23ade41ed8ab864eb6fba11ab9ba5c6f29374e666af4912c2c076de9 -626500 7a3f9fe36cb72b3529747754309d2fec46a8155a6f297bf5d9998336ca26ed2f 9184cefba7d61de4482fb57cafe1420eaaf58e3f2fe370e9c22f2dc235c26763 -627000 d8f9b2f906265aa50c5eefed906e89c06856dd2c25bfa2df52f402fa029b6c6a 1c5dfbc7bb572903d6eb6a400fa50df3c18c87cedade5b4ac63be7037f050a7a -627500 711651d2f7440f20927ed66e680d833755ffecaa905c0712ed31e1e06a81a4f1 6de06425cf412c7d272841f1b3de2652b15d3300902c0da6b7c1b08bf4e14112 -628000 1f04acc62ae096325174e8ae11579d88e65ab4f435e3bb8c41896a1cdee6e231 c87dd969f7dc7a3a356d7935a69e4c8a4487c72e7c623f49cf0f60cbc438aded -628500 f55649153110900f0fa6b7d2f9dd6c293bc44ed7911a6e4d52ebe5563eb3a4e5 de1bf3695afd590e9ede9881a431abee861f4cac9ab8b42cfdb8c37f0e02e19c -629000 8e7208c5c406f95dae4ffd540aeb30a111696ed10374f03cdc186db66295f054 5a8b55bcbfe3fed8453499ed4c4a51233f65626132aa23ff6acae30dd5cb3800 -629500 30b5177f1554053efca360e8acc003ef0cc4ae26820331715fdfeeb2003daea6 f7e5d1c5ed411c3afd3a51d63abc4f29fed49ee8bc2f810481491c138cf09183 -630000 9bbdcad95ee5cacc45ff51ca8d627ec7a971b1040368ac62a4616f873623cc79 306b7845856f157aa25e14e34165e75ee5abdef7337cfbfb9611f628287b83b2 -630500 cf2b412c6c992847944b1fb396cacf61bcd03aaa460cd810e3f42a2866e8d729 8d2c8d7be61fe16d9f5c0f5ea155eaae7f926fd8011209de27e41cc67055f5a9 -631000 ea5e4b4acfeba1f4a69c63647cbb45147ba1dd101b9fe58843dbc6fb09f7c12a 2ef37567bfb65be1417d9b5914570c55bd88da0bc07f7ef7389e6324cb0b528d -631500 539334450cd6eca49473d63e4917725250afbb6a546a025b57b40e4ced8ce63d 865fdec23689d881dac49ab8fe9a20c5984f42b4be7cdf3e94118a4baf4fdec1 -632000 dfdc58aa41d2ebe7751fe2b3ff90f0496e602cfaef1fa0f1c25181a3be4cebf5 8e3f86b2b753e8f342046b61d84ed4d2e9ce107d7f30a47361e983aac874f448 -632500 54f71b9330b758d881d325e8f3ac9e0f042d8ea1222e52b580a0337a3b4f3fde cc0ff7cff02212ef316bb6fc2a131b018fef8b6dbfac01b9e2eb275c9008c613 -633000 67de40386baf1179b74ea2a750bd20d6de8f6ec3cffe5100aa3307ec81bf3a4c 7d69bc05bf967c291b2156c18c0851caa853110a8ee527bb9872001cd8179b34 -633500 4414265aed7c038b6f7ce24cc86619b0596162ced270a87c70a59ee3089165a5 09970b09ad4958924d24703ec56fcf49a7526a0916cc7f0f841ed9796bff86f0 -634000 a55d577e338fdde481a3cadfea26ee6c1777ddd6e35e66040a4d99455626d9c7 5da3e590cd7190a473f7d61027754e5bc50545fceb8867db96006d3773a2b746 -634500 571d3172a3095d0a34747c18c2e2cbaa4173a09ae3a351736b2b4802752cd9b7 6799dc3c2b9fe39f72a22e6fe27ebf46308c887e31245a5cbcc2a55f1060ab44 -635000 6786a43fee0f379b103bd594943f26eee0f0ab3af9dadd36d6afee547d7ff8b1 60794659a5de639280735ce3ece1864a66e5754bb1608b2aaedb9874a6c34d51 -635500 bc5896373cd6ab14f28a690a7d59366ee57a625cd6291c502d64a3a9a5969a96 cf6d7eb9c0306f24bd7a47fa0660804b633f29fbfb647e79d03a545518d5ba17 -636000 1aec8a1d1f6f5abb68d49597795c24102bfb767822705205486829ba50940cb7 348625a773758822cae41638d27628bed89a118fdff13dbb773ba28471ec914e -636500 cd844ea294ba265e14ea515b603d35c2dd13c9c402a4a1a13628925634e81f23 2c881b78d84e98a3a6dffa6d4e55c347947053f184c22f2a75bf62cd779febe6 -637000 7f0393f05b3ebfd7838740f3030dd915d2125e9546e39f503e288a20b14d29d0 ffcda35e368f4784c75aa0e6a98485a2b84fa1ccba37f7fb5a6b4d4e187a5033 -637500 7453182caa6345472aebc820d839d70e916b8e01527e69d2451e68df9f5fff94 df9418647903ff269234df3583ba76f054c7fefb3237b47206f7e25d9ac118ac -638000 2917816bff7d73f4b4f03a31fdbef162ab7b2bc38e2539952648f7e9b66dfdff c7367a49d181f9e332613c76cba3371c16cff94c10a6bacf504c8ac404358b74 -638500 e10674d6c53842c520040ea608584860418908244a9203ea9e726544ef6dcc6e b67a32293808e06725a391d616889dc4a438c8681893c17646896d19411e1cba -639000 a4629de92adb7ee055af0b7a55a0690efde637a84e9c19fd423aa74389c7ca4c 95ccb5ef5e2720ec5ce9635d8eaec7d000b16b3abe24936fb8daea2def31b681 -639500 dffba976bf5db95ba5845ee2863a8f60f855391a80d3a59cff38762f0992b38a 589744adb3b63b274b63d7c83913c65d121c13dbd8399aa7e0f317d4b37b5155 -640000 d5c3942c19dfae03595dbc0683dc712467c00e5307bfd96609c4a728eff4f586 33aee46df3a2c807e3fb8961929402532d1f1061a5e1df2f28335ab40002096c -640500 2efd0a03b8098ebfb96870e4235206b8bb428b5aa568aab56db36e3124c98c04 e67d6fe1642bd591df2f838f07190f8477622358706dce1a631819c828dc4980 -641000 91beaca7dba7afc17cc193cabc2fa7c34be665d2d367c9f0d17a8385903c5299 b90b505393575a5869ad32b498b2fe7ae026db5e3be2ae066ee4c8a4e50ccd0d -641500 52a2ed25b8afbf07e9bcbee8bab225af6bb0834b500ec30114697924951b9db4 0d30d77943438dfd2b1d85adbfe26de36a3f821303c50717d3a7e55abc59cfd5 -642000 24cc44ed0510958b23b614206b702fab53cb7681905d1aeb12fb532fa850a415 05e56dc42c34c44ae0c67c45985004c753588fe4588a4060444532194840e5a7 -642500 2cacb3c0be5a18667d5972d99182b87eaf485c724ce81cb59f3417691a920977 1d5689874267933eb1b72a5696935202699416f5f064b689e7221d6dd4a2c3c5 -643000 94ce4d9dcf18b532dd9f8a490fe270dab5697c14f49b7326efb3e3f82ddbe7b9 f8466520f91a0a9b5136c8ba589bf7fa7a5ddb292516ea1dcf7820d3ee7c0cbd -643500 e3c751b8fb071c5ef4fd1e7ebc9e902d365b88c3dd5a90ca5386d7cc42813b39 fb799e659716a37ba6e9982fd09e8848d637ef1d85555c61af74dc996e1c6908 -644000 2873489104d5b817e24659b1c91e0b4ed350c388563670846658b452e279a44b bc4bee8a1c8a2b98d32ec490a31632852f7935737bcad951d741e789ef99d15b -644500 2996cff77ae12636ed2da94137e2dbda45f5db09c968e13d9002d9d5e8d1bc8f 1482ea5ca89d761a9b99c8e0a5791d430478b289ecd506b3b1ee803d90be7f94 -645000 db1d293ab843d88849874e33883a8236a8bc4bff1d93b7d9922cf1f7dd3d0803 b13760cc8ccad388e7a35b3fa743b2c07b1e40cd5604c3d4162695d02bf601dc -645500 0c98834ca2fbd0b1f4b7e708c5f9bc9e820370fdc2b1126aa50eca16a46813cf 95b1ca36aee7f85aa247e91eed0bfd17f8ea675c5d9db342d9087017117d73c3 -646000 dea1a9883f1c3af496fd37570580c5c9a1e1ff7e8822d70188737f7aa45df488 ebab9f3327181450b58a388214d86b56c395f2e90be9f7d595ad7ec863e6c1c0 -646500 5cf92252a010e2d62030e5d74d6371e873f7fe6353a010791c21307d8236a3a3 392318738e04bc641e4375f47820bb59664b62c88a0f62a3f1bcc75be023b3d9 -647000 b0a00219234dbf1942eeceb7a31565ed117dd8a8152f1d343277433fb3a19233 8cd4d156025aee385a9cfd46d38594d1c4825f52555a703031c99c005adb1513 -647500 8cff85fb1e3b4a7218a58b6fb2e7d0168fb5a4ce4171bf3f0b7f1e7a5f214d0d 50dd61b46e224a437159c8faa7d18cd9c100d1e3ff75eccd770d8debd7723410 -648000 133d2255f56a3c2737eb94f337c9fac97214a7e1f54e8ca9b4bbfc6e056443cf d10ca77595aabc294483ef2fd07975ec43cd2e0764d0df38786d3ecb5cdb810d -648500 37691423db6098cce3ac61dd2e0ad5202cd08d37e2a810a4b7e259742b50f561 4fc55c6790346c316db4b0f1a35d067052bbaed3932cb8a369f8263791b9e749 -649000 e8f43ecdb6979574c66b478a2d3ad028145349c43ac18f67e089f6948a48812d 7609d55e10c1b40d62adbb39792b58b5c075f1c34c6f8676cbbe39e91a7e504e -649500 18f631309a2acc38dbd4d08322998f0d4fac526eadbb1aa2ef1ccf75173adbdd 83794a76b25f0ee49153d50f9bf6d196d1b78bac25dca55b9d3eece5c8c1c3dd -650000 fffaaa151d0634fdd830e104f884bc05d30160640eefd126e0e01b43bd5db5ef 7ef1c36f637320886b505c0ad5847bf0a345c6abbf4e92432d863b0ff517bb91 -650500 bae09e49248acd64fdbc94cefd831ecb2a957c0d5aed72644a3607a198c77740 f1ca4b8b2e74774fc3d86ff3f2b5e6ea8d59e40a683b993fa638c6770aad547a -651000 5d9f45be4e7d558b3133ab3a7d01a96db73f6a16604f4e348fe04aedab48fc1d 38c0484fb001d8039ac07895bf04765ad79babecb93040f8b45e18629c1fe566 -651500 7e12af704c44d001d842767b49709eba23ffc53c8a20bf96b0cbda7955168521 3e563eb1f016f0b9a83caf023067785be15032588fb1ed9d6dc2e7d47d7df8d9 -652000 6577afda5b1a2535cf30f91faff821b56dc9f969e590d406f644518ae4dff6ab a6aa3534f3f962041d6c88a5c413edb0860aad04ae8068ee31070716e552c03d -652500 f60863237c82f26f35682a510882c8c8b3ddf302e479fd201a5532fe02993d3a 623ee7add095d1a51ccbeacebe34fde662c727a14ec2ce8c856d2da57ebd1537 -653000 6d2f869d3cc7314a06868edf43473c3eb2a4ffc902b6866b2b6d9ed8254aca15 ddd54a91243a02e778e23135881e1a17a5829d6a698410cbc91c9c70047f5463 -653500 32d04fcd783380025ac2f7776d0868e44808c446df33e7790b9eb06edf1a13c2 9dce2c2f0200948be45127d74dfcce50bfe2787f01a1f62cb304cc7644754999 -654000 ad3da7c147ea7020a8854d4768937b46b2e9ddca13d786a2dbcda5fd691aa264 15baaddcb66534aaa738d7370796b82234bd7d1a183081ebd7f452a33254bb3c -654500 b38fc7f77f763e12c55c816230cb83453e513d7ffbc2f71cb18a4b970a30b6dc 8b8acdaea52986089352c0b17b8479def4e4e01d8f797609fce1c737e36f4314 -655000 58642d4240fc44829a1c5fb427e034890ca40c5097aaff77eadcce464be04701 11f24474492b2851fa79a42ff8d8685162e2b4dd1099722f3ce9ec4d5686cbfe -655500 d71e2ed94bdc78741559fb4c58bb944dde0adedc05e7558d7de6ab254c332fbe 7bbb488685c2ca7c84d98149d2383b157d88304c5b34aa7679ac24ad5c85b006 -656000 c1d7426dcfe8733c72b8fae49fbbd127a6e257ccbe4120600f8454287ad26105 2f8f7af5f2ec8a3e0333cfafc069bdfca90b0ad6b99ca970b0f458bafb0dbc3b -656500 c4f911e6a72381235e92a8c58ebf6fc654e35c3f5f4b2851f7f8a9ed3949e047 3d157f3d2c8158bf886bf994e549a6da2db2c092266c7050b831c8888d62b205 -657000 da224ea959041cf5d98fa040a10ddd7a1904725a649ec84f2ca403a8117c7f5b 9b9b9bbc0221a24b8642fadd26c1157ce903d7be532aff91519f431e886f9ebf -657500 61cdb241ff295b25fa6a478eaa78f111e8d7ada328853b0af54bb1b20a2a427a 482b2e9a549491f90026f8e50ca10016dcc78e4c3d2064e9f730b23ca9520a2f -658000 1c4498c323201e26bfb8a8955f29cdeb66cd43d6a2b2befb1da4a6c0647d1c53 931ef1f4868a3c5b54ef4354bfa791c3ffe15c02b3c704a6a281154e2f5be98f -658500 33dce694605303583aeadcaa80db0d8569ff712b588875d48edb395520a43981 6247bcba2c8883551a85e364e30b4104edb0318eee718e0317dc42f2a26c7451 -659000 339aa922137edb48aa37b841e956adee6c9222ae9bec106ed49ce5843b179681 ded7991d424229bf67cbf220dc2a5a5b223b571374f52d14bc9e83df72ea4753 -659500 38dddb9b6e5dad4ec1f95be3a83a156be12c5dd9d5e74a20bedee990b3f511fa 7815a077c5c8a265fd122b282139e3a13ef5951482f6d550a566ad74ec2db369 -660000 5562a936684fa4976fade44cd5eaf6531bcc844027c9ca01e33516c0c87be6e6 0af9d5b94d513c095d2883a381746ff79e47d5179cc95165708ad37dd0615764 -660500 de362a2665571bb51834a5e8cf65cc0b436097d1a640ccb9666fb41ee1694713 b7b39581644d06d7672965e189c645b4396f4d50b223eed99080a122b22c2f1b -661000 7df5c95f34efbe842ac26e4252440f4f315b342bd66e74a3d1bc3c48ca0f3844 0a4f81f5017d079725470dd800ffe7e955bd82df18b6e8abc325165537ead1f7 -661500 dfa40eda9296e76deebe46ab09b9d581445d20814c44c42090766c0015162e53 88b577c05b1a5f27b2aec225732da967a44e30dbb463455bc7ed223bfdc76025 -662000 7cd8f5daa828803f06d2ad8e7899d4993999d0ec37e8a37ec52555d1c64acd8b d0a6e4b8cc44620fbb80e061a949a8fcc371fd1f2a0b05138978d234a99fbc26 -662500 057c9dcdeb7375f51cdedc28740c881bf6ae644ff17c0aeb77ed796e89db8672 c749272ba9509a09bdb7697c6197f132c1de0c58de5130e8c3257288be94da8e -663000 d9ceb13692d03610ff6e97eeb643407840e27d32c389404cd3cdd14733756dcd 05b1659e97dd91ccffdf180d8da3a35f6b2fceb9676091bd997ad363210e2f5b -663500 cfe8d9435ad14423479546bd4d6d1e8dbdcd62a8214ab922402a86838a8fb3f0 cf68cef0e01bc5856468753c4df42bd16f3d33dd68783e012c1b012a3cfddc48 -664000 e18e31c640bf36f6cce981521fd55f42761fda24538dac34285fb02e69c427f2 f237c6c072f16f524d90aae138ec3a9176c2fa8f3049ac9ec009ecbb678e4f77 -664500 2cc31198ec6c3fe6e286f01d98f097e19a5c23d3f478916414e83f201e724e19 1805da29e7f7e8dbb2b5aff1e712b3a447106db48671120732111884e0783b5c -665000 4b332fdeb19f5d2fc8108c233679e861bd40df746262d5412b8a6800f50ec073 b2119ba9b25aa2a5921c7aeba1759395795989824a5d6d204592d0ab6ee8ca12 -665500 3f0705d552dc4294997339d7015a4897e55790353236540c775e330c78cbb34a 9595abcff6a155b8b995057dc725cffc3b283086ca65a6213368073f7f5d2b34 -666000 df535e0c312494f9f1a288cc54b72779ec7ba745bac09f7b952191c5a904c56a a545eb072527dc053c0630dbd820c51a2c3a22510f31a389abf75294dfb34911 -666500 ce6966c65ae25a88bac2a35c95d1943c482febdf7f9c28efb57eacf2dfb9544e 4d6fbf4b0b9c493ac96d63f97dee48afd60c2c847f9aba07110791514b0f4e21 -667000 e7a271b35d3fb008b6938cb618fc6f57032c92aa1e09fc50363cb181ca53e2cd 0f496a3a120f9644e6e3c5d371e6e01de4afc4a85f010306919bbef0aa323942 -667500 783bafc58044919edecb6e3938f0ac69dcc75bfc220bfd8717d419091bd680d2 b22cef79cae030286f2fd4b62c409c6d9a801f65e377d66d455fd814628d5ac0 -668000 beaea7bcbb6c4c3a18e0c9bcf6cee525f9036796157c8b4ce5748819c13c2967 a81cfb88c97c1489d9193801faacea720e98d21981856d121ffd5e75f7ab393b -668500 393c647b49312eece8839452c0874a2e82aff7169a3a7e1e5326b1993a5d1af8 212bf73b67feff4a971dde4a00c12b32fe82859167687a3cfeeb03a93ccdc14e -669000 f24c2d105f11f385c356455d460f8b74d466885118dc0e1ece8bddf624cd5246 d91bbe1649788ea71e0574f15865868289b28651ab7e28455d823a515492ce0a -669500 3dcf0b942af949fb37bdc61645d89efd6f72b13c02fac02a96ccf1375cf3cc21 81fdc3a3d66e72026b4bc01320881275584a05be5b0a5f8edbb2a6f334126024 -670000 e6d5cc2dd441d4b9f08b05a582c291a01927bd1a945f1a43557e3bc70cac59be c82d3be4f90e23836110348e66a9224cfe135ca4408363489f3296dcb8c33f2b -670500 c420986426267474054b56073135491ad4381376c64dbba0c57deab84ef61846 b0c138c7e5b8bf286b3f5b6ad0a83fafa7ba68d499fea78553241e741a05d183 -671000 d21e66d96e08adbb61bbdb75a7e8971ca9bd45a4906f3ce23dbd84c2e5e8d161 ba60c1936b7c35369e31e9fb6be2739cf60fc4685d210a209c4fbcf341d5c9f8 -671500 f7bb538d49e99ee06136105edfbd282e2f370d3f4f4c6d2f20b75938aca43040 9c1b787f1413f483e72003c0ca97831ef1e616b86fc3165423cc84e878d487b0 -672000 8c85db8531cb0e6bde769d488b6c6a639f4839a819abe23ccf88f3756caa6089 598752609771c022cecd036a0b8aab8caf8fa3e64724dc20815a827b750daaa1 -672500 efd3aacdf98aa1fc4fea20a2f4cdd9ea3eba6dbe03a63a149610d842793bc85e 93df0fed7bd2dfd8ca6293601d799ea9a54af7b0d45997c821e4a8a7ab7d1f9d -673000 3109a32670b3c1a796f9c6cdf5f3744848e8ac3ef0ee2ea891fac0eb69223ae2 baa8971d22821acd1fee4649f702edc70cf1b072517f4b69d6bf4060cefa34cc -673500 8064bdf0c36a535d5d7788f901ac0713b627e2f8b80c4b20d26cee0daf02ee6c 5548c9d616e98ed4fcccb300d3e35a78d66e61aa95c6465fc66a98c1e40405c2 -674000 b409ec86b27b1a828acc7f056dcece326a7892314cc5b0d6682d21c06d4e4cc5 a25e0ee6404f9db371913c15348e3aa8a9ad4b3cd99cca3fbf1e8f95b6e152dd -674500 0c8142e02a8e0cc1667a81f4c4d08ab7577102481f73d31b9d8c67589874e970 e615eda6aec462572a43acadcbde8bccd88e07fd0029bd953e04d7022dfeb355 -675000 f200a64f03ed78fdfb3a35be9133cc144cb7621be76f0a470a6cc451d31de7d6 2dec2d8e6cbe5d122786b9c571751d54ba1d597e23dd4aa03ebc50212c68cf8b -675500 44927533602536ec6857a62ddd2e7ca31a05c733cd0699a078c5106620da51f3 989564e602ccbd682fcf993e4ca7691f049bb6adcb099860f9577a83cbe436bf -676000 1349301af96fd291f3f6cac4d6a6a94779a2015ee9d63989d79c813e7bf3ec81 c196991fb4a511513fcdd4300dad73d556daf8eaaea1411a5c4b0d0382e96d45 -676500 7a7071dae50a8ee6f25b289f3e9d15d53661469e5379b56278f391381f2b5ce3 918295a1444f694e137f7f9653f87f1863884241462386fffd0037927c3779c1 -677000 a816938aabe21e8efc9c41ccbe0e7de2188e0bdb3635541e05b9cc8e61ed3dec d59c6134dc9539b3cc6aaff9870b30ba12676fadafe95167bf90bda3f074bdde -677500 d06ed31f2f1a7dee027e76fd419c93a2c80824f31e5b0bf09e85e10362cdfa8e 30baa2fa7e5834e442e8445c81d124018eec1ecaaeea695d4278263ae60ef134 -678000 356bc1b553016f0a17399fc531e9d5a86bb273ef944843e8aca16d16480f1e1c 74c26fdb3397f25f794bb15595b8807b7d4a4500ddc941e7461bb106a69daa62 -678500 e7f83fbb9fef902caa5ad499746100c3422842f793424bb2b17f9431b0a3b6ce 5177927957f3b258bec01be88d817c262ee5a64cee44e04b6d78b5f227e44442 -679000 1ced7af5a996a7028c63fe45238dda8c540295b48d082cc278614f68dae0e249 cbc8a6d5c9ec62bd0d50ddb90e7e1efc4b62dfef8d7aede6279ad95186497f7c -679500 a00fef7924aae620536c387899d8628d4eac6fb45bb1954447e2de6a4fdb2ab9 69b47a27d041a54b0be2406df7be07f3fbecfafc0d58407a7946bbfb0f65cec9 -680000 76831117aae716df313e1e7af8c4c8076e2b7d37bd7239c827962cf903afdb55 0ba660526d75f5b1765967a87119f6bb67d33a496e23b13e58335e960610b38e -680500 17835aef913aa41dfe7a49e91fa7bdd85411356233f5cdda375771706b5a4e5a b88eeb3ef96d4ce4adf49b87f88a5c835bdf4ff88aa3a45bc46d2970a14533fd -681000 86ca3bca8de152e4ddd4ac3171ed463466dc040afc5e2f38eafb7fd0ce49dbdf 55a9a5b5ed90ef00ce658b5fe52373ec23b37e7ae1c477decf0e8a41326cad7f -681500 5b31112aa2d9b190844d109c44f8a4845bcb0f75e567055bc1368bfbae9bd427 9b695ac5b41310d05f09d0e5265f53b4ff475b10d2b0e27928d81543857a1f0b -682000 0f036f94ee9dccdbb0ccfd4dc10663890af3c2b7da67321baf4919f8da0ef388 a9d70e8df288e875c0361d7273ff846b54dbdae0d6d6459831e71ea4a41397fa -682500 18658069c688414684b22ffe62a7e4d9b84b3f27c28351b57c8c5763aee40ac8 c4ec9845b905ddf71c374d400faeaa649ba8b08751f0a5c6b9780d4c7d497fee -683000 ab2a4002ccfc546d80417f9c1c66dca34d8de7df714fbcd4eee134659c6b4261 5bccf1dbe0d677d06768a02a5bb6fadf5deb0075582a97e4524e2128a4fa4363 -683500 5b302ac27ba940456860fa752bdeb27a3c8494c1fec08578c6d204588ae18420 ae3de94a6481c28aca678f115b73c830ecbd163fd2e11a9d85b2c3132911c3cd -684000 15fc8d38546017ea2ae0e0b4387d74bf702a396b52cccfa879bec7c415a164b0 9a6e35b63f814b6837bf67d897103f320a25e5cb15dee8e5524d9961f53368d8 -684500 e40472171e3915e9518f1646a3ca09a46154b226443848605a4d8c78803c90d3 2c7e33f27973f6345dac95862d63006b4b1506d5979f60d8c52fec12b74a1b78 -685000 742e161c4d772ed9ab9b2aa95ab7dd4646e7fa71a7b71d0062120791fff3d538 7854ab499956e6893c2679a3393fb30e450f2cda76cfbf08bb3e77b586b10599 -685500 697224d799e123de9da2b93aaf6a3f00ddd507080eca2357c7cde1ed1ae8f189 1b02e1bbb85f1e71e1a1bd1e58e4eca588997cddc1f545ee293b17267fe5fa50 -686000 7a7fffd9aa90d0d9e7309ccc0e450c7544dde058085bf4bfc9efde0cf8fc7b3c fd10b3c2c0539bc586cda1dbdc454a1597f4acbfc1d9e7e7b472e2d3547c76a3 -686500 3dc10029047449d4411fbefe15a7f25864007511102972f14697dadfb914d5d0 8064a285a9ebb460f864525434c5bfd94ea7c437f67c9eb6268c3f3e4737b798 -687000 2e2c774dfd40cd18616a82d3e5769d4f447a2eb5214bd8783a5084cb8ab38e20 52379664d91e53a60d1b1a4d64ae2005e6549972c45af11ef2ecf2f2faf82ba3 -687500 295e12eaca70c7eaafb7cd25efb6b461f5aca68665832ab9eb652e6fe476d809 43763991b8beebed72f3b7215ee72a2f074daa83a27c8db1decca52bbfca7b15 -688000 88efc791202d8e4a0266dc8114487847252ff2497c022ff4ac237aabc6602406 560346aa44e4afaf2fa9a4e1506534bce8c0e113efe4b19c6aa26804b405bb11 -688500 8bde3d0d7f23d76ffb10e59c43a9a2cd4121c3f5033204c4689fe77b860d616e fbc4d97609351dc9fcc8f4e08b5a0c79624c9e81989b684e219245878ec2fed1 -689000 01a706323f362664abca40cfecb4c6efa65aece3270fb1240e238f1e93ea3ca1 e4672adb018af124ae848405442ca5e255ff9af3909d258bba12d29f3aecfae8 -689500 3d25b5834362be1296b92448e3d2ece79f8017708479f56d7e28d602817c82f8 643b9f9b0a754b768ff504c9941c627627b49aecbe170a72590179536840b843 -690000 0e622f16da74d548cc9e49c20d072a9a8a6bf45dfd793830fd25369adca29bc9 fcc1d77406d58f3e1e5630871011b389449597e41f1df035518c1e25affcdc9c -690500 d96ee19654c250c20011f56dff3850e61b9b01a8c3be009b93c0f53c79d6ad5e d3b6058792062983ed59720fa58ca7cafc890e475e2411a01331a4e3e8ddc580 -691000 0e02a80970060ff139ed4ce0a83bf5221895d80de69da89bccfd720da52793a0 20279d4dcc8aaf7a83a59d70cbfdc4c51e8d034467a956cf012349dc01d875ea -691500 6bbc975ee40102521ac8b041e481797c83174c5f2b5fceaf3090895a6301f42a 4ba322db9723202338d5c0e46427fdcf24c8631f53f3db590489cf5cd74311bf -692000 a36c0ce45bdbfbcd02fe25ec7c199be6e01f6edd8e5095dd745b136e1a1956ed 65fb3e0023b45c838637825b0e95f461b02f90134e875d85ca8f084bd30d3eda -692500 2f8577c57b15cf8c176873a546e1451b379f4e09967643452a37b037b538a0e6 b15ca73e362e6394166b6e104ac474d1f73d4fe671117a77ad3f9786ee35488d -693000 634e96cae2b7253783b3ba6dc65bbf79ad87782a46f07a11ca8c3b2325e2d2aa 08db37defef7bf06dd75f2d8e4f8d1be0f2004d24e816a71ffa4fee43fb5153d -693500 c472b7da4a1d6e9a9728e58dbabfdea31af58c18a17e79e3dcade6d96efdb689 021ef6717375d52d4e02c36bd8757c6c73b77c97bf3bb4d6292cec23afc3c8ec -694000 8d5000ca461da1bf1687fc3ee92e3a1b414a92737d82e301895d6cf41e0e4cf9 e2e6ad6d2a58ee8538e7dd8136587a612c39ac281fc3e6bf609b1c497d9e331e -694500 daf014e18bd15e7a19ac859acd668aa28bae8fac71079e0b8285c25fd28a46d4 9a671a25ba774c600b2f967a1632561ab4ebbfc4b4016979aa9288af8be93065 -695000 f0d64ffc15600b2a53e5b9f09f1a0f981273e1cff39f01bb69a3c27fbe679c71 d5adc8baacd5fc0635fe0ac739a16893fe0c4215655ba111f49e3c709f0d1faa -695500 d784ac30db59c0e5e8906f2211b6405356158cf57af758b047445926e8dc140d 7d0c9248ce3387940358e82c01b7accebe7d3445fe97f6569b0a99a1a4822b61 -696000 16e6034f4089c38e9eb2a11669e4d5b896b4e36e767626bb4c2cb852031099ae 5f54a918561ebc4c21c27b793cee698c347e8dbfa49ce72f4580ad7d3e464a91 -696500 bde4528da57c22025db1123e7fdf3e58f020015b1b500be5d2ea13be8f4f50fd 954600e88d55d507e82333a0b9b36f5bfd5da128e5dfe721ea486a117f196e51 -697000 eea7b9418887e6bfe3a460b03f30f800672d8df94217fab7d1e7a74f437ebd50 a210a2e4efac6617e3df43fd4219eee8e4a9dbf05e4cf103cdc9f39e162d61dd -697500 af96502823fad0e9693d94bc707b04d59d3f42fb27a12134f1aa0a863ca616cd 8cc57e73164f446606d37223429ba5a37d92d1ab52265fef43c81d8f5d9756ff -698000 8a0878bcd828268633df687a5405b2b86051640a122f616231d8d6146d4c2ab2 27a9f143cdcb85bc01f31868f92a964337c451cd1a546f93c29361f245aff07c -698500 afbb603de0da6476915e14cf182c6c785ec6514b17d9ba7bfa74e5a228f6d8e6 f730e6ed2ef1334071ce63f9ac851de557383c98b40a72f8bdfb29c49bb7d571 -699000 4e3bcab244d1ec2528890ed24340027a9add680ccac038c42e9a5b4880368a57 1b7062e806e70df560b7dd19713440125dbf814412ff713c5bafc8776c443a60 -699500 69c03ffa655f439caaa38a36031f45c27f6afa345fd8d380064ac4106a47b9d6 9835287f527b8d7075cb42cd361e6048b9defe40cd855bf186641ac16a40cfa2 -700000 19c87f86c5d859f1d4ba642097f626a5c6cc8420f1b438ef0ddfc52d77b5a7ce e7cef1ed642d40f49563c66d9428c699a66241a86d05aba5cb6fc6d6218317a6 -700500 c22be0aa764d1e0d90432e726ecb95a769d691a7de81ea480c1bb9e74f43bd8b b0c38cfcda8312393e4906e1068c7a323defc33624e99c8c8f918771010a417f -701000 b2505b0ce33e22fc06044bc95bcf1bcea363d91c541451ba7ebbb07079c9b8e6 36066185fdc8a919096d36245786b921b24ea4b9ad0949d3685c7d54fd3faeed -701500 11c69ac149f239f122c309f5c7c8c08ae9ed95e563e6e5ebc0db4d49628972d2 52282de896ddb2f1cc56c22ec74637395d1c2ff49508e903cf4ef1f5c01a1da1 -702000 73e7769b7982c2e9be15c6d3b0156680f7705c802452205d64a5d66187de5008 623290f47a7ec8b202b95f45d5c6408072766e49439c1aed29f023bd79a8e1d0 -702500 cd7f69f08cba82026873f72e8709cffc89a4bfe3c5300231a180fe4e7335e87a 4f1bd226f6b1bc4313e7618f03e4522da41509937f596a3728da2310deecf49c -703000 6253ae1e6bcfdba8257a18760dbd8f42bdfedce3257b9cff76660667e29e5e20 05134bea7f58be79fbc3942bff929fef977a42b5bce28e787bdf2bbc1bc70764 -703500 affc08445fc42e60d11152790408c66118b2a815647640a3eabc3006e0f58f8f 34c74888ee86d1759127612373b099f56c53bdba1b0fbabb0a7ec61eb0f24ef7 -704000 5298b2ba05735ba586e9f6aeaad350fe88b762d00c4551d6b02f6c0b706b0f34 9a36354d1266eb50f84338359401e91aad336d97cbfc39d574a83fbb4aa11d67 -704500 f674bfadd8d412cffe1c8d6fedeb91e9c8914c3280414896f97e1c08e05b53b5 6e593d4f49588dc6a68b5adbf870674cd17037cf7431f34253eb6cde06364421 -705000 d288536328fe3b3301de1ba97c0237dcd740f225f4df07e923bb570f68716604 b918a47fe346fbb9958ebff0e557b9febde26c435ff6320858bdeaa09ed0eb60 -705500 bffd8b226418632ef3a9f71f473093e5592f446776db14fec222f85de068c840 e889bcd01a761d5208221642a51bb1d0afb1f324f74914590242204164287740 -706000 2547d907a333fdebec0140593814d90a1d806ee539598cf0672cc30a1d5c31d6 77323ead475140b2224eb35de6da439d3832a091f1ca17e53a885d0b4d469105 -706500 5625e44c5204f1d9d3cb4b5b55aaa18f13be66ec9f76988159a172713f141fa2 31a50d4821509dd711e9a541a3c54e28aad4bd6c6314526ba82e64857f52f4aa -707000 e15531acfd422b5932479ecfe5dbec51af4e824298c73658bd43c143958a70b6 e9af02a4dbfa950c0a45fe96162bf991f65df101072db521b4631ba7e64ad248 -707500 904129b3e99e06b3a75bb2b903b65b1176d82601355b13c92dfd2551edeea6e3 4e5bdefe9ac9916fa5ba321a6056ec1bc8fa32ce3370587f13bed12c32976b71 -708000 23cd48d83d0bc7e5b80c8a337389801ef9bd5584097667310342d92beafbabe7 e916d2f42c77692bf97058ded798c541ce883f69786596ad94a22108adc17694 -708500 2f58264be757741e695394b348381a9ae8fd583341791a84d68d338cd811ae39 dafed9faf74c750eedfc2e65491b75d4bae7d13b9e082e6fa91376c2d6034da9 -709000 e55588bd39fc8e754f2b272f80ac86b5515bad37eeeac6fc3dc0d1179fd53423 69815269b65b334aa89cfca70ebf71dce7de046cc84b68f0f9c462da718cc469 -709500 e30d4db49a196e4ae4502c992118f37ddd6da696f296413500ce20b4b9838497 4cdf69b6c9515176894db3bb5ead92d5ea1772d53717224656242e8007552228 -710000 6f141473cc79d5def23f888471ff143ab546b5b1d1d5fd1fe51c996674e3018d 5af180a3caf0ca42e0ba20e959495120693f273201de65aec15993cca37cbd2b -710500 10d11c0d1dc7316a7bc8a99b685c0b12c9e2bbec941d3c33781059c7048ab022 541f760b8b3ed77398d5b5193220799c84f36e5cf342256921661f6d6fee0316 -711000 dd068ba9611f623d9e761f5e6a10b0298130c8b25317f047b6a4e79a3360909e 920987e93062ef5eebcfeb0a98ff5b108649f1a092f76cad1c7d09b276469f80 -711500 96778f4ce3094a1c3323e3afd658b20cff90b2aa7f23d886a5f5629704f5726d 9f4d8c3657fbcdf2375c92f6f7e700f8f108a1a5df22468685782c897b15865a -712000 f4414c743e2b4f89177f92e0e11d61e9f3b1669d3ddd6148b3915862dd2b87b0 df705fe65a056478cc8c914ead67c0a9b6023fcecb68dc7d9ec56a8c6ea1b865 -712500 fba950fc02bb67da1c4de9b6805b7bcfc0cf7e2bfff478568be99a70596267ac dc357d74f8f524808f3f41d6604d74a8a96c6bb87f695a15ad835abcc6669be0 -713000 ff4dd851417240d00e594ee5fb5408372e4fd5585bb5ebf3d73a97dce1f4c41f b54673e8a2bd6d75e2218fecd8d20c0bff1b231b80fedc53b3f1deefc7fe4747 -713500 92e49d6caa2cdfde8ec7d8c37ae12d995b9552c76f7c7ba0abacb77b02bdb5c8 4c7b0f7d4f28c7c4d35a29c0a74310b38789decd628308c72a5a270a66ae55ba -714000 dc8dfa5b910afe73d3558be9d077fa57f1b6ac42e058227cd73b1b1cc0c70231 9ccbffeff96630cd9248b3001d7ec7ccc83c9daa5351bafbdefd8a88c03f3224 -714500 e172274b228f5e4f49167f7d36076f71db89acf666b9e519da3a33c548515826 14e35bb2ffc296d0d1f30be89e8a66f0bc7ade63250bd68043acf98dc625c91e -715000 a9b83db90d65b2e1db885b5b708f1d7203019a7073ca3e5310ed4dfe19bb9d61 1e2fea7d862a4b98f558f07e35d23b1d229dcbe2047a58f7bcec840147dae863 -715500 969fa24302ef22b2bea25b3f981fbb756f3de84f841d6f73ad9d6a6bbf463fc0 31872cd93e38c92acd7b1af2ca83b7ddbc9319dd8606725fe0aa2b50026d98aa -716000 e33babb3b3269852ab03a5044a595312e1828dc11169020fa2a05f4ab329ac15 129a208db82ccf3418d94c00f39f3eb81bb7ebbe901f2a698362be4fa1f6e7cc -716500 9c0cd626f57ca90c771b00015658c387466c2f3d462d36d9fd3622abec903b1b 044c3a4459440fa9078eb26f15d114c6ef9d63bc5b8640f84289a1f376b4b85c -717000 77a31d517bfcc769f64d0de88617d62d4d433c1d1a3136962eb07baa5f227a86 e1f060643884a9ede876b52b38690ccca9c9d94140470024d2f825f4307dc918 -717500 546d0c517b9b0c5910d4d7337c366d76c7d99be4b875f673cf3876ca5458cddb 814a3c25d78419214f5645a68ca361b0199b58ba3fd3109817b585cde74503d1 -718000 7e44714aea5af5ac9195904d29c9d53d03fca15e00e0f2c1a071611b6fd03011 38d5d155e5a9992a6e9c1423f0ee621f19173c533e6954a46258e02982b89a02 -718500 dabb2702316c8e8043539190a1581ecb881dfdb7502a517fa183815a012eb344 268c57e30e191d41a2793ad6b70796829bfe2726aacb3864283e82e384eea0df -719000 9db785b29f04f274688856f0858c7c63961a6aec5788a94bc1aeaf483dcbbfa7 8addd23f1cf6b051fc6bcd5558893366fa7a54ed89deba74d79f7a307c5224bc -719500 4615a7726a6b3b00fe5a9cc53fc916af6402871508fdc9b9f6e5799083edf0db 3d3702be96cdabe826e24dd724ecfc426024a693c161889d0b41275cd6130d19 -720000 6b70419e1023a8dd272910d32c30aa0617bef67234063aa6e7447aae5356fe34 55f7d559d3733e4d3d6b5c3c68265e088eeb6d2892671e88e9567f238268925c -720500 473da49304fdf70d4b5adadf6fcab3f0c332ab5ffe82972dffac6b14aa20f23c 3de3c3ceb92f8a7f45fc19ccf72f79f2fb8d3bc61654c534f81df978e905a3a5 -721000 c293a009462b561ea37ba8614559acaa63cb6291673c68082a6e4691ab0eea86 ea34bdfab3e2a7087605df85d858866b54b4ab1acd86619e99f6283a99f7ad67 -721500 a15ef2603cf7a7b0ebec81fe4abbc6035183755a08fa11604e40c95477d61812 6aeba98a3c5083b997eca56cd003e7f0285963bcb8502f73f2994dc04492c35d -722000 39271600011dc5e938c1308fc8f467fa44145f8bbc5335f24719d125dc92f664 bb0387e362d72388584708287f86c92ae50f7ba4330c9857b308837d150906fa -722500 d7f846f9e439702e48044fe02c689990aa0a56613fced844d989816e0317be80 f9308f9c0bb63c44b443473a8a25777e34d9a0e903edcd33598b270f0d7e9036 -723000 6fafd8c865b3d0bb05f18cac70fb93007cff223789fb46958b55a205ffbbc959 cdc9d13b0b9a5fa827d2572e9c3232f498e8b06ed8627199c61db9525469fcdf -723500 6ed55084a271a39809b6f3455a08d082fb7c56ad97427307ec207135c7c16ef3 cd4a3d7e1dc9e293cecbcf14b969480c0c2f277819e9eb2286d1761df7320694 -724000 c1b649d3101d61bfe8b949f443e1035a3d5944310f83e94785592c4cc91552c7 452655726058f019fcf400a89e464688ba4bd0fcf267493e54748b146c7dbe1a -724500 21f5f4bc2fbfbfff183a3eaa110c1e3f826eae2f58d32242919026a8d1ea6206 d15908ddef7626667600c5eedca9119d82e0da5f4cf56bf6616edce895b38d9f -725000 5db006a94bfe731764372f332c2b23f9863f7741c0aacc4d92769f353cb4a4d3 db57165deffffe98c3cfe7b95e119d0253a6e984d11fc2b1894ba4bb3010301b -725500 f313538888a7b2cbf72adfff7c6aac1583c44b477c27810920835e1f36104ec8 c811a4d09b2afb0e9e70bc9416e58aa2c3dfa4955ec4ecf03b3db9b65450e858 -726000 f9f289b08641492431e4ff87acb944092bb1fd4ae405569e0f3f14e433aecc79 5c10e47957ac47afc2bd4fc6daa0c7e30f127f0ebdeb1b52149756d9f996eb76 -726500 769de3f5c47b72bb76aabcd88f8c84595015f6f3f8d78b4d4a0df2be171faf31 12f1f3f363f1cfe762d972b988ba7e0943520065bcafadfeda1cd73aad8c2aec -727000 2d757e0b21cd7f64dc962c5ef6a7268d0e0223814f74e6fff9c81f849e496ded 3ef2c4f48504f065f4efc06814674b635ff6d31e9b667f9b1ad864819804f446 -727500 5b2875cc1b107110464a44d7d9a1835e8c19246cc4d646402fd3bfacd53b7201 48695a64b57a8523e285989dc5bca5360df44847a66d926c154c6929e92608a3 -728000 35fb3c9e4fb0a40ebced7b7d2e9bae928790bac78a8460c311b99e70cb109c9b 758fc72831974d7f37e9307b34f80de04f3ceebebfc97c79eae5e1dabcf2374d -728500 156a06f3bbea42cebe61c148aa7ac4cdfebf95edde5d021c03a90ddaabffd20d 6b170063e91dfa3d05c9d6edf71577d85a9e3f0ef734b7376f757d1bd5a42705 -729000 e8771ec45982e5e9928539d0f4f398b3a35f02b92f44ff6937e6a6a50fdf4100 bba9a535cc36db2ca8af73b8707635e3c12b3125b320df91257a944ea3a6af8d -729500 e17e17e50ead400f5dcb3f3ffec5a1ff95da211a7f6d30f87399cb034b2fed00 0263cf2e76899d4424125c726396ca7c8c3f1830eef290b084bc67aa3dff7ea3 -730000 06ee01124cc2d7e6ef4f764638700ae11ca26a457317564df6e5e7f0d881ba4c f20e5e74a5a07e05fbea7bdbc73ad393bc83a144a7e15d03a096f052d7065eff -730500 2692d795f114318940b89b8aba8a910b6360170048ac824590c5d814f8b01973 9aad48ed4e603ebd7c79c8535c24ec7d2ddf7db6eed92b9d1e83846e9e139a1e -731000 e167080479d38ecc4cbcd16e4fae05c1f87e09d33e4947b6a9813ca63e147d5d ae82cde68df2aab3ef79112d4080a285b806bed3e457aa4215c6ee35a6d73e33 -731500 d8c7e6903152f5f559f108449eead76f647a5c9991f2815eef0d0058c25b6bb0 f786151a72adafd6930fe59a04cad481a49770c191a3f5444eb9b4d49b000779 -732000 7371a17e1393bde477a0beb136f98e89dd30f49ebb28cf59a265dea0f82deb70 67d98bd80facaa69bcac4ddff46661d1dced445c622bc90bbdbe1e7de9a8f768 -732500 921701199569749e2d13f7940e6347ded7a3f1dfee26b7f7bb744d5d3db586dc 41fd3e2f31c4d732326d13c5f31cd850e864c43f1f179d8631ec1aa69c506d88 -733000 d452ca29f9949b714f175c7ca45841a6519857541c44df4e52caa73b4c9b347a 616e3b11378287c338d03dc5e2395c5500915fff6340d6fb48c0123e33f92d51 -733500 4ecb0e1b2273ed4df5bb7db47988c3271e81cb9933d7cf50120e9730db47c82a 6dbe9a6615825d26d58bc5a2c068e9068dc5b4a1402dda75c43ad3810cc55a80 -734000 6ef7723b332f6d1a4791f14a1cf2811870cbb08c2484ece5cededa3f69fb920e de8e532d9596a92249adbea9833ff2022f96bdd3f82b7c734fc3580b4b3cc946 -734500 01d19d29a83d79e38c274b76943e9d5769932a6a7812e3f297620a40a0bc922c ff43eec3f821cef199133f7c5282c9892c1b1546a77f6fac3e9021037481fdb0 -735000 544a5f6ce7a71e13db7335cd2a4e02fb7b5ff98253016f9d7f26956dec908470 662695548e437e31e7687cd4aa3a463d2dbd1b0579df23c6f5daa7e9b3788e66 -735500 997d9b45e87e6f1f1b76c7c212527bef213f348c51d806200bf6541da07b76d1 68e5ed2790eb489379491eeb583227ffaa09afd5b62b9073117e540505058b8d -736000 b371ea1a60567133d86757ae1b12faa8832166726b9c2eb67a643e6878b0f64c f5308b0f2fe00d7b1e1bde602e6028ba5f2ce8849da22ecf2cc07edb069a540a -736500 ce6bfc2ae42b6e0893e4abf6edeab04ee36cae259415004f71811cac250e2abf cf5273f67e35b1bea345758b059f5b4b05ad705469c64e85cd90f392f03db171 -737000 79e359fb34759ed805e4ba17b22b3f64f4e05bff59b0929d5a996038e3e2684a 06fd8eed2bedf16f590dbe5210c4657f8f14142fbd12b823b4972a4062c46476 -737500 3d69d33e4b40ef18a677394e025c74f1ff03807f1cc1a9924301da4af97d40b9 8d5cdd08a8a4db368da7ab6be4a68085fc9b2a156fc5e89b69ed661267bd9d05 -738000 de67c044daf5e82856c70c57c05e0963d2767f721c9a2a3095052d271ff77a21 3f6cace03de90c0a7093e549aaa5862b4d0d4304d20e548c1b77a7022a39722d -738500 9857746dacb79d61819a9a7bed47d4f3f8a8ef2f0a4241e4a26e84eecc388178 b324b1e1ec98f23aad98bd643e12396cb0e6db5b6679f5f197b8c82a74912869 -739000 e760e2ba3fbf67764d9ebb7a9b5684b71d079174bbabdf7de315b7814e6a6d74 74cb6e148688d11254c235898692018c699071730431d7e9f7438c6859e1b140 -739500 f066444b8192b7bb857f79443308595802f67e277d85efca22432c5dd095ca02 91fdef383bf939a8e230f32a00ad0c58452c3bb0847a257a136297dcfd476a6e -740000 8d11e7b07aad1f84d0976806645f5d508acb6aa563e1905bdbfd49f88a83f561 d1fa7be0afdec09bdc631fb8d5a35bdf26f47b479aeee287cee3557ddcc412e2 -740500 54b44786a4b53f25a1ff7dcbe85ba288f6108cafb0abaf193c6fa9fd1bbec690 511fae7de79f3e6aed0645375673168bba00a2d39563ea2596e09e3a0e609840 -741000 6e98421219a255828fe8067f68097ce9d08c9f33886b8a29a22d2ebe6ba1f3e0 ad33286ebbf08385412b7a732c551354dead015e466163e74e7fb5f94f6b1cda -741500 81eb9f3b0f352e0ed1c5935647d526ac71e0b775d8715732e262f50ab6a55963 fa8c84206d369ea634fb6668aff771d4c9d3ca7e687a6f2aabf1b2c80563b955 -742000 540e29303471cd64e05ae80fbd19847c61476ca202848595583e1432e45b6a12 01c47d0edde8e38dbef982a21b7b95e6049dfd3ecdb75763b3ade1cb8b804ac5 -742500 6bdd578f687b5b04d2492b7bebe989d618b7d55802b977c9f1362c022d37b5e0 abaccce8aa24b8424fe18df7490c67e36999e1f44dbcc68ad557c59717da560f -743000 1a56cced54e09d3e03f267054909c5800b30e571a81e21cb8e1960c32fb615ce fceaa34349bdb34a4bd0125a9d5a0d73ac8eabd0da333a665f71613075268854 -743500 2b102f1ce482314a2ffc09c26320f241ed197ef0ad1b0b1b05884d95e98b4832 0d514c31a22d865f9480fb408373139aeb312d750df0441dbba91f6dd74b7c34 -744000 9eb6d3d3bb45887dccff04f8555b7b6ee5c16af80cfc8fd132f2f5d64ef32d85 18c336ab05bde704336b82417e0f8a33d6d70df4bcf3fd3277dbdbac7d285313 -744500 2c894cc985ba39b9d41d6cdffd9225d1137285bb2a9faa355fc04e1c3a503783 fafb7464d1745969dd5edbe08aa6400acd05dcfaaf6d09a135b206eadb2d7a5b -745000 0d3d86df05886717a850b573d540f01159dc4aeb9715260e19da107d8a5768d3 273a426515f6fbbc4d1f505ac48c2be61e47dfddeef2e0725d1d287da3706876 -745500 b614d96445616a551d2ef219bec80a8b104035ae75230819c08c1bb5d40d3eb3 e8a90e0d452a4db19b7703651fd04988b45763240ec6e769e681cff12a9713c4 -746000 32fd2569cffbaa373077a1d958628f5bb59edb4f1123ea22d827e59b58e6128d f0023c390d625e1286ba9aecfc80f28d96109289f7c438379a75c7b08c915f24 -746500 51f9b04af9044618552cc030e88269c4c8b6f6285653003ea31fa0596b3be8ca 21e1a38a259322e17a4fcfc9d45cbfb75c345d2475f7081373a9e8b791e3d906 -747000 ea7dec43ccd90255b703203200c0b71d3aa7332a2bb43549c5b713bb03b77f9c 9cf126abdc8e883dd428ae846e7fa5d694e87f40d1de07f772f916de45db3de2 -747500 1b651b29875be11fbb4fa8ed4c857b030122b7facdc75ec31ddaed88e3623566 66c676aae65eae30d876db4035a19e8e00bdf9a9331361e72f57af17a3da4dcc -748000 55f61b3e6a5434428b1a062ee86523b68f5459e7615c29d83f01eee310ec66bb 4927588d5f0600d0a418298312581aab6d41144ee3bb87a6875d7b11c676704d -748500 cc910d9ef1a087c0c9aadfb77da9051aed5124b7d072b976f4d34dc74f842f14 f1b10cb29bf15f5280b2506a480c07a610de4dd63212ac5fb1a33894c2fc0353 -749000 70c48f09a23f35a244e22e7d43f245a20d1d171bd3958ffe261363536f92a087 5cf7c04ef74572576b5debed4c20f3446db017a0360142b325a330909c904b09 -749500 33d54681aff8149655455f3331792f7a4582c0f0a436b9d3ec0fced7a525ecb6 382f51b24f05dcc78ee7b0e02e1389d1247a30489fbc317e6588238d78cbe478 -750000 8e0b562cbf9f5d9e0539f9964745265261cce019e73e22cd0db86f0dc7049110 03a1b08260d16527973210066d867267be1f3d4692f3bc680afadd2b1653f995 -750500 a85d11029aa82c4dfcad63d3e6e32c4525f9d192fe8ed223ab9f05a3fc4a5d11 1e1aaa3b0c05e04b991026c5a9b6a56228b007a6f936902f7a80f1b8f48eacf7 -751000 bc48dc5090db1a9a8016b89fcef45999f9d6c87c8982dc4ed52e4b583ac2f7bf 94ffd27371d8ad63511d87f728731b0513ca8d8b948d8b777d852ea9aab4804e -751500 c45fd98831ad0acd126e9fc658da6851a2a14a1cb037ffa596da1f2da2fc47cb 82be3962eb66aa5c0fbbababddc65c99ac5c70b372b32aff94aa47392ce6b802 -752000 373e8654d6a04c16dc7ef938fa6db6abc8672283a0f027cc34eecb1ec872ab7d bc163b7e20ee438640c02e74d48ecd1f65a4bd4b16d21248663a48e63eb02616 -752500 5f217d14da39d80fabcaa06ee56ddb41ee0dfef892576c2e100793f03818145d 91a33cc31ca938ce0b222ee141bb4edc500263a0689d0aed50660f8e4581a960 -753000 3e4aa8b1ce5cd84238df7ad4558f411a41a674ebee9fbe087bb41e880936a7c5 7b8530bc78bb832d51460962af3cca2f534cfdc28760d7f5363534e68a72ec9b -753500 23a5236d81db31cd3e174f58fc2f9c1263365c35dcde4a20f315cdb01fc29d65 042dfcbd5f30011ff7476e398e4c4b90f890a9fa4eac0da6b809410c3a9cbba2 -754000 5b4879ebfac928244d38117df31bb10c9d7c9e8e8d2a35c5c2f8a230b4593434 c57c3095308f688759285e35312da7e6da208cba0f9db64180d551affaf107ab -754500 96cc5bb1028f5ad1cd8a33800d9832d85700d037d5746d6cb4e58c1eadc8b119 df2a0abff85d391ea42eda8fb0a1d7a750eefe9d5fe25efa10a9f46fb6110f8b -755000 e7129e48fecdac55aa3944a4bbd19eb16f0d8a73cfadd44a79d641aaa46dfbde 385cb4dea3040a9b4d475877dd9d3cb61e23091f492fc5ad741a5cad2268c6a8 -755500 93174ce679911cf73dee7fb12bc26b02889deb145dbc92d69637a85407812272 5f000b1a76187f1c309f9495dbdabd5001f69bee3f9498316d0277383d861388 -756000 d2cad51c4c7f604a86bd42e5fa0855488394561fd8b8e403c968676dcecf2f9a d24b9c50230b5c1aac5e5937e488ef65f19cc11fd4cb6b97497cea46061d7e44 -756500 2e24a5dff5e90a2bddd7343297d9e1cc5f1e8555a19606314e46c09962ead770 dcd2285a17c2b37a17fa6cd27899af70be173d7a3d5c28c7f3ba6cf4d835c716 -757000 d11e6ed1c335b9cbb3db5e79e9ac728fe2377ec42de299a318dcf31ffc545ae5 748036b1271dd158b39d7de65e91a95fc4e51fc0e9eb3445cf7306f15c0974e7 -757500 0b5f20e382095632dec99c72f66fa419e1ce638a80671b8ba91b9a6d24f51e29 d6181cc28a4fd461f6de97bb298ef188941d1765a5bf650e95d418fa8b7fbd4c -758000 5a2a205c4c51fd035a4f57e79f2d92ca5e3c9af3c8c2beba21a442fb02b2c705 e019ca24e6b67025cf564537c25fc2e6e241b44730988c316eb32aa8afbb6804 -758500 e33c965b4ebb8b924a1fb73c65017199c806b762d4441854b79661f4de03b427 313706df2d3cde7074b2f6849c1f134ede50bb46a297da3884d21a1828ce8072 -759000 31928e69c1bdd6c727eda5662bce3f72e36496d538d9fc1cff1424bfcc24d0b8 98b76d0e9682ac933b75419da77ebdf7ba10f016d35d26638915a5ba5be4db94 -759500 2d322b637e8d92f51372101bf714ba726396d413b0a8e9ba573018ee1023b0c1 caea6763d02b49152bce73655908d1bf489b2918b8514982a2fbfcb1099011e9 -760000 1cd9bc900f95c2e15a802f7eceb33ff51dd12a71718cb4220e466bfaa0f5ffaa 0243b603adce50f296920262a13469d2ac1d0c42c2ecd633feaabea80a4c6100 -760500 4de4cae653ec7611cf7079c4deecd470afc39ac6a083a7b5ebfacd9d789c4394 d3a390c8ac0a632c7565327db3e9a4fcc30aacc43e2ba57377a1477235124baf -761000 6aee8513d50a19fdaf21e0ad49ffd92cea289ed0fae844cb3afa16ad3e60b934 045c6ba4c62d4ae995dced0633d85b8e120542be2533abd9fd1fc8c651f47563 -761500 b1917f5b3a3f1acd43c09e2d975abdf63f4a2c6d0b8ab429b47f467020e5b31f c7f69fc7d9f169a97f9ce25956c25668cb780205eb59dbee76f592718d74503c -762000 5f11eb707b887cdd88dfd5f98203a949824d1fe960c4c85525995a377a39a79d 6a3963332b853b978afeaf71fdf868b0d36ab203773c958a5fe5a427013ad02d -762500 8c3d3c496b6ab6a1e56cd5fceb131d8a9dd8c4fdc938d15e6ed090dab25889c2 e6eb9f858bb451d57926036c80c3c7ac4617b7897b19f67e2cb1952ecab6a24b -763000 6fcef4afba243507e7d54aeeeba6cc7de011b43df9d90f364794e3c59621b980 47461602514b2ae53177fa064e5abfc46da728227988a9388120901fb2dc9a94 -763500 41ed18026f39928e570601d40419b18758312017a7c9568d73d12d4b828a121f c04c199a5b9d12441ed489dcdff90453791925fa29ab6eb6c62b0c4d648e28b8 -764000 67e928458125fe2e3c6970092328b48497a4d26c6b04b01e53cac4de70fea64b 9270bc1fbd0aeda1572f2c2ef56dc700086652533d70be2fc6d13e5bde70f8e3 -764500 015f8999e9b59d173970ac6f7b5b6b460879a56fb254c55fc64c79c2f1ceb2af 0fb0da763fc466bcda98bdb2d28195935e5ed9c8d35fdc877160aacf553a4a3e -765000 9e706cdbb0b6dd01e5fed36ab646fc0a80a850e08f2088de2136388d4db8a219 f307dd0ce42f0f743054ed8236b6e8c44e4370634d9382ba439ef593210f14ca -765500 76b996f89bf12e2d725e1df6b6e1f9fb71a0e4741add4657f8233fa6b1a9cc0d 1c1d390e6e339f40129dd63bf89b9dd34574b6c0e16739449ed1936b023f73a3 -766000 46b8674f0faf71bdc7bf0a656e0e02660d90388ec7c3df894b0b3562d8541ba3 ed993dfee8eda538ad156e46f49e73c96e6abeb40c4e2ce1b34751bcdf4e7bbd -766500 719246e48b8d681ea5869953004219e8e9ad1ae095d9f7005b39316010542a79 7d760e07389497315c4c3b10c43d939fa4e1d43dc29fd4e898911ab78a6943c4 -767000 281b1c63ced6e6a9e548f01039e79b341b4c75980548acc70b0c52d71feb8e6d fc8bd623900af0aecc3fdec5de0a55fc7889c6b3005c4aa8fc3973a221702eaa -767500 d9a20cb9dfca54abe3534dbcf69a04b8f6b43afbe3703e7aebb2bee8cb81f73d 899b241bdd3264be250d3f665e9930a6b2f302e1eb87ef65845be021d856c35f -768000 8360e09883922bda97c55167146f583896798f25e12baf10cbdb39254ab11ba8 fa86336cef4c01ff1afee67169e0f4a3810546750ff4c38cec86e37c27444bb8 -768500 ffb03996ae3de8c5bf73eeb51ca0527f6ebee4b20dd059828efad08e7e6601c2 df22eef90381eb583a9e93e90e0722e0a6210c72da28deed40c27499c7a5ef21 -769000 2103acd9679638073a79876db195d494213d9d6e749faaeaddd6c672cc7e177a cc3a63870c9ff71fe67008397b61d975a8147d03a0d8d35a3565538ed514b4c9 -769500 9336bf1ee4de809e164e98a29bddd7a448333f2e25de891b4ac528d1bd7af785 605f77b3340dd29717f7ba780e9f4ce15fd0fa43f2ed916b9e54cf23aab2863f -770000 6182eaec959caf801de20f3000efc3b9431aa1af594a05d704bf2c53d810fd83 1ff43d1f6b27ee4063f01fd16f49110f0db50d58ee4937c28fef346f0777335b -770500 5405e7303c38724438e124b5e518c9af26a0076596be02cc57348e91a89abb6e a64f6256dfe425b8fb3b98b45dae59bac34213b85fd777b91d08d15a62a25623 -771000 07874de328fb41f73e1aadae9e57705d7679e8e186b8b6a2ac50ed5d1455d1a0 38084368706c2b4c84de621b821faec1466db4cd8334bbb13e4eb6960dda4b5b -771500 caf1cde2dfee0a11872272140e8043b92a33ab604f0b8a8c34d7a7006a11381f eb96afea84eba379a82e30b8366611d133f219dbbc728f99d55419e5494c5b6c -772000 3f8fb7f8de518b519eb102a29f372ffb4627dca2bbe06dc035bf7ebd4e6b733a b6de44e3b4a2a16494b4d6d7e5423e1ca66faf4ec0916a8ac97e4a3a656fde81 -772500 2fe560018de02c9be5e9cb02c0d2abcf8d6efd94390f10d8eb84d9dd3964d53c 631496990ae92715067442cef87711925361593696c1ac62ed053618951f9d76 -773000 53c1e8e472ee4d6bad6411fdc74d9fe4fe2564d0baf1bc5107b9dc4ec6262afe 8d48f77bfb9b49f20dfdb2168f0abb988b8ddcd8e9e62ac35ab0a2968b912986 -773500 2836b1c2239c528ef1ca59823417c6ae51c93040e1a5e3ca11742dd10350d3e6 16f14274772f96d6d2072a33cafd5c8f9cf4bbe37111b3f620e04bfc42392829 -774000 69a397d817d7155b644d650da51d5413ed2c133a3cbe2b54bbab7ae7e5a82914 c50ff677b8441b9a940984cf5ddb46f4b690ffbc9703ced2b163d89b929830b4 -774500 e7569a38cfb85227d2d2189a89c59518b64da01e2fdc89bca8e4759269fad47d 3bc601776ed5afb50fc51058a988d114287afa8fc4ce04c8d09215ad8ee3e9a4 -775000 d62bff072790320b532267e13d16eaa2b6124b12e9dc9704ea8b3472c33a7584 2ccb3c701d5d6730cb7fea0a703c1228f75c58b95dd167e135689d020e686cdc -775500 69206115fd6be6c73b95c85875329472d8550ea98bbcdad27b1fff5f13f1a383 1044c0b51ee23082e8268ea9f57e614ead985939009b2d6595f866bfd407c543 -776000 acae9ada07a40fbcd1abe244a88eea4497d892f56bc6c47c9a3256960c48a674 fa6f6390e5912cac9e116a1dc8ce23ea3acd3a45ab8c372f265c2a813a1d43c6 -776500 c7800bf474c58aeae4052c7de8a9a5be9ec371403659d6ce87f478083814cc61 5801468504c422c927e64b555cbde135e90690036800af540e0a515cde84a6ec -777000 60999146dcce1a4d7c57777fd14c438aa74620575ee304da40f3139145be094e 761c802120daf7dc3d71945a83698a8ec2813efe961ad3ddd5f0e8b05d88824e -777500 55464b5c24a72ca78e577947e5e31095625d4a5453d4ae8e1a628586173696cb 7198361fa24cc1510d0eed076fab9402f8d312924dad53b2cffe4a2634450753 -778000 a96e3ae7c78171f4839888370b8ab6a75527c35181a76170fb0c0048a340efa9 40f745faad08e9ec7fb07610cee6fb0bfdc4b221bfe568e692928cbd556fd0d1 -778500 dd54a9dab8dfd4362d396a50863007b96b150c454397a2b4cc486f8b4436acc4 45f3cb013e25a9a12e1998baf79504649e32d0405bda1b8d6cecb7f51597dac4 -779000 04bc1cac32dcf0121905e3b0f8bf15938de5a5470e130dad3d5e9478e5c04ded dfbf8b41e5cb2498ab9f6c772c18ae3af36f693115fd0b7ca12fc18fe8dc9d6e -779500 acdc4b3a573253149261bf7b8483f07e26febfa36a79b0f85663d0418bf89a87 c4e9858c10b84a43f0d48b59f2aabbb978411667e1e740d26cd90e824e60bbcc -780000 70e69b1c46b39329196e880591e35915ed2ff68cb83f2899e1c8a09885462ddd eddb55e0d58a9e963cc6bd8e74cdea45af4a42783f9b070eac50fd00b10933e8 -780500 44f6b73dd235490b827c83c949f8116d3e794d139ff88688db18a6b45e1473b1 011d86e2b32e548d2143b273ff895d85f132b7ad91a6ada40d29517155de88e7 -781000 afa04315bad0a73e082c417351c846b882f070fb89fbb62f94bf6627355eaba9 83f5ee23a34675c501aaeafbd8589c2173bed116beef5a6c05da3652da34eb4a -781500 daab9fd8e2a04d026d3dc748d775734b92ba9d42af448b88c4e54313458f8e55 edfa9dc118b24ca0b01976fa94551d0e78fb276ab38af92581b336d08ad979eb -782000 71ac38f6202666bef6bd02261cdf9590ddc79b15b1f0fd74a0991f32d7076cd6 d02102ec38f004cd966d4e8d53db021475903f0630404bac02af92fc1ba0f055 -782500 7065d66fe20e800ec4e007a0cd3301a98985fa7f755f0fd904b2a999c45f16fd c68d77bdcd1b1080ab776a210493e4371a1d30e3c73d7fe871e04b9345a0661a -783000 d494fe23c434284aa32d3043e1cc6443fd7bf9b36fe12410f7d2e35f5360b5e5 4ef3f9328e1d2d96c19ca549d1147c2063430601ec62870fc66c5b6e68aab6bc -783500 568a8df7d5669899b02e916c28755a8d1fc4a111f3af3dfd4195298ab257a847 7f752afdb474b41347fb14da6be44561bbd5dc034ad25035718d57ba0e326165 -784000 98aa97184148b247fa71460e2ac43389d0d04b6265546ce0eba7c2be328b6bbe cbb9d6529647174626503265092201bc8ed564798e1244839a9a2f022c5774ad -784500 db38f59e0843aca6f105b25581ed990384b8b6fa6c340cd21be37799ac892e8c bdf27aceb99b7e0386f937d7c1b8a5a8cc92ceb95cb3191e5502b41245ba3465 -785000 ddb1f819bd3e7a89588081208e3dc87ebca46dd381593d402bc80aeede0cd724 814c34edf844fbebab1739243a0a664de608eab49ef2d91c57ef7195bbee80f6 -785500 92f3c145e77f1f518c1decb6e99b826ce6d778c24634b3d6d3340897cb670c63 6d607478b75d072ff0a14c4c23454a04b9a08d3f9c196ebc0b817fc7b9efbd30 -786000 07a5df141fe4feb999505fef56d930e19c684e5e452ca352f0fc49c2d9eea76f 192297c49f950aee2578f0ee3249bdebdbf6955714b4a4e05edb3e8f24aae8c6 -786500 d9b454e9c5a5a6f9d16d22acadb61cf1ce231ca4dae12878d868598425eae775 d47d551d3fde80fb8fc6886f235fb6164cd99133fe9dedc2bdfeaeb10bd45308 -787000 1d5ad94333c42f9cd396bd5a2772973ec2440f1d9f3cedade83af2e4951cbb32 0cddc7f86a6714a3e3d2d2b004d1d3869d5226992f0bdf0f0d3bba94177b6a49 -787500 b454323565de62c5e27b717877037c918e5c046dea15404d0817ed066267fa1a e428f7829407e31e1079ddcac80dab9b56743be59912ddbc0e0691178991b568 -788000 28c337da150a017aca9d5619b15d605cfe5c41838893650f9a8108c4844dc5b8 0d7ed84426c912c0a3d3320009e66302ea92039ebfa4eeed9bce380b2b2df8fd -788500 5f6ec263add108aa8bae692f8381bf9e71a615ff5d4dbbe3785167a10465dfdd 3171b907ce8071d79c40b61ab802f51d8f1ecff22c4cfcf618065e8bdefa3910 -789000 1a1a8318353d2997eb996843165ce0a2879e058d6cc2498ac43fc495f3010874 0832a6b246a8221f36b8cfc3c15c743878842545a3ef3b5ffc0f1cde8246b72b -789500 88387f881fec667c0a2943deb34f9e508a994383c3ac8884d24b1dfc400344e2 866305720d60de682a074333f7b1512e45c63ab0f9090d8791f315e199222519 -790000 1659d12734baca5dc87174dd4ea3020c907031df843af6bdf22cc2ec8dea611e 63e7e3f379c2e361085770ef24c82f250cb47056045bae37c92cd369aff4984c -790500 a01132497c3c4a8622f3c0039f319e7bee99942268a0ef323cda3fddfa11f1f8 aebda06ea6afc6b95cd31185250686bdd815e89025a1b067f47db36dec1fb8c2 -791000 9209e4bff9f2c45a6bf3d2dd4f8960b050fef2a600c1dbafd65dda57bcd909b8 e005838fe0d4d7128702bd61e7be6be96340f3d4538aac8ec8adf6955bfefa94 -791500 facd9b684bce4af3ed32b93fde842ee8d30775ca97b1b3a691ac0f267301b280 df48a7e529861e94604eaff33a4ecdd7e35be502a78ce16aaebc413f4f4ba59e -792000 8439d367ef216677cf50d64e35abd6a55d555260d8a4f53af86560221aa48b07 6b7959d457444a0e8c085d2f366d54460a8e8ea5691d8d0f198275ef79b72ed4 -792500 2200f9ce62b2fbb1b25ba5e05a09301f576ca7606c2eebeab05a7188ff5d714c 2b7504213f6fa99dda613f8e7bca2fc6310930eb40c405a06df793406d146b8d -793000 3c520432d9a47e6e272dcdd99e656b04a1bcabdaafeca135cdb61b105b31d413 6f6b8a462b2d883580b1e2acacb9ce051016c06a12a87219097e5327c39d84b4 -793500 a9ede0aed7bc7639d97fbf8c81203349b1aed926ab534ffd055199c047c427aa 6b6e849eb0227f85c0faf658c06e5b4b75e15431263bc587a0417b801910ed72 -794000 8173afb6ef69b30acaed892e2cb93eb9186a55ec63a8730cf5f23909c13cfa9a 4f340c5f5665cf08ec366e0ffe561908c19c646b9567ab3078ddc99ce216fd32 -794500 debb2e81b7e22fe9f49c42c5d747837344567a5d301f900731c7ec427bc671b7 79a735251474e25bff8fd23b469f0d79eae7b941b45b181f475d7bf8ac2fb842 -795000 a83507c3c3bd71dec9a8b3f471cddb67361e6401767c8c8ad348926ce4830d89 e626138e04de566aa065b5a7106daa670c614de2ab4d326523bfe5d1a4ad4899 -795500 0558ab8c1e1ddaa709688f0fbdbc1413bd8f80362f6e053f20479e9aeeedb4a3 13a40efafdbd6358d9ef9f1b9307a88b458e999100a93b8f4611542996eaebf4 -796000 a141fbfbd754e10fd7e956c10d459834261d3571affa49b8fd90c0c804d0fed0 00fc2ab3f76f3b577f97c348313e9256331ea81a5cfb7d8466fdf144c8e9fbcc -796500 7351e53a275444b95005213efb4a5a1397a7a01d58b750323bd37ac47326c704 57ea2db92ddb3e36ad171b3bacb48f883fb7e8ef74466fb769f7d5553be66c0a -797000 80fcb6e51160ba191312939b815fab48de5a56f4121a3d2cd7b6925918a07af9 96242babb7769751d636828f5fdc2d1a44ca57e399fbe5b0683d09fd66b83da2 -797500 57bf7c33a40e1813c1947efd7412a3977b0d74ebfb6e846097aa45d03eb1fe47 e1250b6f44746881c59360dd6144bf4d2e86f8e31e68b0b820732b2a8bd69d5b -798000 f3370335ede3598caea04a87041fa7c1b51e5c9e1c5e0d50bf2bb136a64cd167 e6e1d946fc72e48f0399f980e5a4f7e544b4eb2997739223c355e3b15af48fed -798500 8f2f93e0248a8d8ded2c5106fe5034916127161f1a554e2ce307c5b6afc3e00c 2db41c24fb6ddfebf0b3bb5d74fbc1cbff4185082e7c22ef66c336467c652180 -799000 5c376ff3e907391741b0ce9601a65e616d6183cff6bf744bdd6597c455b306eb 9b86110172b3879f17995b766972b505bf547f40e1113cdb52533357eecc4ef7 -799500 bd143703c66bf324a5cbf67f9da778755b4f7a598450c328fbb011d1eba4d96c a4c63a77ffa25dcbb59ef8e829106f61ad3875ad2b9485ee6653a83691bc9ef2 -800000 e951054363c21bdb8e2c65154dc8453a7ed6908ecb10ed72fab814899d3cd345 9a0b2888559918507acbb704a78888f3293e34ec18cbc9961ac7842ca297984c -800500 956b9c5b3c055d3ff4ca81de618186166629076e317b2bc429faab8ed5a9bea2 9a80628c0558276ab328fbbff05e76501ccc20593000dc13d57eb3ac4b618838 -801000 3abcc1a5f4b6411fad8b518e4e0266bebf4d74ec36400e0b242e299aab5d8d43 6e72ab4aef323f82c48dcd697cff16bb1f0ecb039a1a892a74c57abaed498d92 -801500 c49350d66b895f226052f92ec5d5f35b70596d37a64fc2f36e386c21cdc224a2 1e1eab3a1d14c473a254babba1a8c9f342cf97b0ef0f60c2946149c72cae6423 -802000 f739f9b985ba0ee82823c7c03d7ef8788d23c01ffa5ab040ab23682d5e1f27f7 45786b2936278a79a8d856f96f53f0d4b09a04056b96a10d5bf71f5ff849cb58 -802500 1bc5ec3d7f952e5f27e9de2f21a30fe9333fb4a53b9627d78567d789cd578098 11b12b1784bf7f779aa53e67753bb6eb9d1fadae56dffeb1b9efb5f1b1ddbebf -803000 06fe520cf2eb81478bc9548d5802a7ca815743a5e541ad64b995af5b177ed245 f2401149fd3855cb680fdbacdb22b368edb2a34f73c59af55099c2d44e79adf4 -803500 2bc1768fa981d73fe4eef0174018988fcc0aaf5316c8597cc1c1eae8618eb055 b1a09ed639e05848794994217faf96d9b66a9e5ea926a08efa7bdfcef312b107 -804000 9d0ce3d35c935bd67f2970d8d3d5b098f99f936e880f9ec87cc5e0b1f837a0d1 4eb8648f841497a4bf8388158844361e138eebcde30aca295e530b9d97bbed6b -804500 87f582951ccb498931e71f194f2bacc2aa593bfd236519e4abd2336136333283 9ba93a57335f44c4bfb962c33fc0698f6846755d94ab393b23a81fa9acf72603 -805000 efa84f401e0f8a68ac402f09bc3988192fd6c85f22fdf239e5b76ce100e3a2df a4a5b65c94cf7ce1d1cfe3c087f63037ba522ee4916dc20051d5953f6d42e067 -805500 c0aa476e7e6452f41dbf4cb5bca05893a93782716c3299f44cf31670079f3190 349733cacd77e399f52831dd1f33884319cabf7934c3705e798fd8add0d90247 -806000 8459d195b63e53f3495da811539f2c883361bbcdd4b0097d0ba214fdc55a8219 9fd38c1f19472a144ec9b8cf57d8d9a85966dbc99cfb05628f5683dbe75501eb -806500 8ca60c34843a452a19d05b38dd13aaaddf0cf602601ab66769801c5443380904 f1a31e6d1b4cf5387c7def82294d179a656a10f438585a643e49dd6372982193 -807000 ca98242c7ff34cee593fe6dad4393698bf5875e9a980928363fb0f2bfc01e0cf 040fc4bf74790e2218abe48b6e53fbc6103ccaded8f389a0957e9008f96c9e2d -807500 39be5b7e38795922ba3653d1310f1579b152e493ea3c8bd6630e0a561465fd7e a88ca5c9790cb9542ef0a64dee1b5c001d56bee7636c09105a95abc859ca5335 -808000 8e9c44d713b7bb2ad9d8cbb9ba3d9aed199b4a70ea1f7288795ca86c966e323d 2c9dbc0b472b7ae26418b1def60df7a4869a35cf9bbf74b9a323d08035aa13aa -808500 dfd89eee02bd3dd16482828c743927801121f67cab61a4335d4eead749876a21 549d7b6c5b66bd74331c6cb6f937c8cbc605dee884796067f42fa1bd04bc6a86 -809000 676d2d9df28b1d4bcc68bbb1606033349d3e3a4c11790eef43f689d5e8d3ba7a 18d4addc8cc3174723f9ce263cf632f3817d015245ef3fb6ecae87aed807b0bd -809500 001261eaa38a49c58facc31b6c7245af90f5ccae8d120be1aa3b23f80e68513e 1489cbc34c82aa22a7de85e615f2039703a23da1494aaf7b9d1c425e4839849a -810000 051b563ee0050d2539bb0f57e3a5b5edc759af06e4dca9ecc9b651122354d828 84359c9f7e1bd44948c4df3a1affb6a4ee05c2761f3b22a192faf696c1c8cfe2 -810500 9ca81889bc6223d0195bb98eaae9b2b81771b202153dbcd4aedeba781063e4e0 9ee6f32bb1bcd2ac2787662019ca595b8a2569bb90a38be9dbdc77fd30e0f541 -811000 e24027de80e7e3cc2e2fb95439a4bc88541b10316eb1b111d107119a154ce444 373b8d3021db012bcd4b8558235d625a2d8eebec48f5c9c8784ce80be7ea459d -811500 2188003a3ac1f51c3147082a9737895235c62f579500ab7207e04c3db272300e 5d5c778748335e1c6a4d7b72e799a84b1128150bc5b782238c222d234b6e916f -812000 8edc7d32936aead671b293ca3c35a4f2cd8da3da8d0a911eab810aae919c671a 67921067e57ccb2692bfb932c9fadfd695208ae63e41c58cbaa2d1ead989b572 -812500 f93429e089b8304c72beec28ab2589d33557ec36f12f1e5c21acf96a1eccbbca bceb1b621ade4000a2e9855c387f4575dc2599df96fff5fbb43a4e934612010d -813000 c50b28d6a65438104f28a3518afc71932e5acfc9cbd3dbb0870dbdf8e175e159 b43d73d2203a216818e42d28b5108016335c606dceac6f6706641e240b065929 -813500 9ea262207c1743a9666200b8f174328d53875437ef4238ac0f7f9f1e841d52cd e915810eb721a46d939812114e3017db4a2fcee9c0d3b6701f070d61260706a7 -814000 7fc202882e511a8dc8b76ba9fd0e5d24578c5c45f51998f83d22e5c54eb72c5b 69feb5f7c9e1eae4dcb884df1bed34f628846110480539f3ad02db9e49c87f59 -814500 946dd535ac1806a838ff7af300006a3b019926e3caef42f04e77cc50453fb597 91645835f2dfa4f7bcd0818c145f349fc912335d0c28bb21f5a6c88833531ef2 -815000 32f06e0d2112aa022953d25a663a77c34fb1f0089091be64755920e082588a50 09503cf3aa4c5c2dcdfed49412a77bea1120ed6741f024f25384f9a2f6865f4d -815500 ac758032ea15073a6e7063dc49bac109b04e84245383dfe4a57d8a2d68e74c5c e8796fee578d7b8c3a1282cdd6106eb5be84df03f16f290b1042788e3cad77a0 -816000 4b0a8e17626d583d00af2d1e0d3d5aaa733b2637c0e7daecdc9ca7d32ef78b16 5513bb0e272bc3c35af92c733ac8e3f54a4f9280dd6305eb3f521c0a798864d8 -816500 7883f443a30cbe6777c45da4c70e650bdbdf7f2296d0eef9580b412d304dd1d0 83b8b3ed3caa544c6827b267919896ad0df9b50b416b4092a81c4a16cac4a2e1 -817000 d13df124f351e01764c49f28bd7bd9d94ec697abb36970435ede31462e245b78 3668760c6bac61282ad6173be88f0ac74108aab7e6b2d5b89bb05be5f7450139 -817500 cd9bec7288443f2289c3e350aa1e2f133d13377ef45051c8ef68f588f0ebfb9b a6dcda37fb4542b47d6358e6f4990494b3889031b7d57270d4581c3c5f5c834a -818000 db2426a8e3f0260a1385c6514a424c1db30e077cd18f25affc301b857899672c 1e887aa787c16fd0a14425d7699a20ce4a184468a4e8ddda982637cd60dd684e -818500 475ceb331fef75bf43194e6ad78493ee5a3132b1366764166bea3f98214c5e02 67e95130d865ef6b96c3c3594993525b0ed740d94de1322bdbdee1ca44c52be8 -819000 8bb061140f8217d2d20fc59542169fd7afa823a911f74040d58b3c86dd366481 226b79c0b56a187130199fa71bb43f0c0c17986b38be4bc953aae9035b3b137f -819500 9fa10df35922528bf712983310840e630f4293f91e9e81ea9a6f416107b4b385 23400d8d0d4f2eca02b0a320b012d9c3874250e3703defd32a742ff3a14161f2 -820000 0b83d657248250c7e9d96015875066e2e5d59b7a0696af84d83b246abf9355ae c7575028b8e2df600f1ba0acc5a101952b47e9660a8a912940a2b548172a05f4 -820500 e0176c1631f2909dcccd2e56971085cc4a435398a3a967945666e2d7b3232d1b 86cbb6afeb7fa1e6ac902b3d28f2aff25971d24b6cff228da7e4c8046b397ad6 -821000 be0584aaa7571f33c631f75d7881d80e2a19f6eaddb91f311547687ab8b6127f f8edec8d65127f3eaefc274cfce29f29c4cd339739f2903ec60759367f283f67 -821500 fd2e812d81cc2da106beaca8ac8e7ec4ef854416f30d7428c83dc72944e01ed4 9bccbcaf94c587dafd152fa579fe7bc4e87734d1840e0f939f494d1d60dcd499 -822000 9054e0ed1b7621397499863a4dfee073b379cbab6d211118e0daba86ec09b239 0f78238858465e4308062dd44ccca1a81e3b1aa830378d63ba37cf340272f04c -822500 c50dafdd9aa14cb0fb01b2d54da426cb862dffeb6369c1ff1f27b86bec6ea28e d7d020758a8d3fd93ce7a603dc710b085d16c3c232f389f2518b96b88d903a68 -823000 6631367fed6a7ca98d2ca58e0ccb8060e9e0309df1bbb5d76ea337c386f3066d 4ef109d1b5fc3ec978f34d66b8d93cd3ba0b278d7ba9c6ddf4fc3d56039e0fec -823500 b924862a40ef19454769b776643bafafdf407500c16dd73a70a61ff7d033519c dc8d2c04b3dc1785a7a76698674830e8aa8371dcb815083d849851ecb47f1805 -824000 d9ff8b7426f57da2db3d9f855572b493eba90e61b0ff3b40beec0b46578679cb 95e502ccf5b34258f239d7a5aa86f16c643e189873979210e0cee9c5acda128d -824500 b668014cbc4e38dbe8870d15c7ece604e8a698dead63136af5954cc403a13921 b634009a41de61587a78dc3ab8aeea26b6d107f5e59df2e927321f31c2751347 -825000 ab26157df7834e458aacbb394f8f6f34fd489cce3c7a1e6251289401acc59062 73352b8b59b8fdbe1d83e82c2da9ed6282c5788802e2eaf3db7e7647e04d83c6 -825500 4447fc4bfa77499510c1f033998de510174732f103eccea27ffe544577472f5b f15ba38703c021fa9419af02b8210ad9a9658b8866f70cfd734e282daf996169 -826000 8b30104ee7551d9d564a9142e2334aade0c93f1fe7846f2d2d21380096a5a1c0 dafdfa617b0bb3f7980b4df7dd4d0159144b7973976db5e60a28308c0e9a2216 -826500 0e2e09768e2c0cf1f39eaab0b5182b1616b40b9a6d931946bfae09c246bff35e 417a26d05c6fe49e0800213efe648fc7fa29040f0f16b4e0f3814ac4087fba79 -827000 9539816f7acbfb9151d30dbd91509b104a83bc0564050ab5f3c3a180d1659bbd b8d3ddccffd24ee4f56c161acf6a739668f48a10fc703233bae30108e8b23f04 -827500 735c35ab86f85b3d7c430b126cda4a4c8e55479a414be9b344ef0749bb2381dd 526c10694250f563eb1f7e7be275d89c14893a95118bb5caa0fa3757d2f1b08c -828000 846213c0f91cc5f47286bda5e74a48dc86d91bed3d5549f2130211dff2210540 195e0a72d1b5934d7b37d8678c6ee6da4713fcfad761e397921573f0c727dcae -828500 033da5a6c02d67fd91df3e6d357de891ba0a8352546be1e4c3c47d6d7a0b8916 3d55e3405532f51149ebf67cc1367c225ffcbe2832a37814c37dbbb324fe8c6d -829000 b64d6b04a7eeb8513608c60f52b3a54a2758808beecc359cf23e5a1c9991e1eb ccd618e28a3217ca7d14e462c4d2df34473438c0e89e68a498b9d236507003bd -829500 31cc80619db75aad85974e5c52755375dba0dc8ce67a17e6e6e4cb29f60dad24 41145f9a5566c0d919937386229a00f302067d3d0dfdc369d866f164c4edce40 -830000 ba6ae9853c6f5efc64e12f9982df9f199587f43ac41c49c56c52a217c42d31fa db3584bd7127b287f20a097fefea21aafe602b6d36287248e5b878d8f59a55c0 -830500 881ba4b6afba166f55baadba4ff7b98076398db48b53f05058e4fcef5931803b f2d61ffdc8eb96d572eeb829ebe227489c2748aabb4e7ae8dd2d4ff04db6135a -831000 a49b5343b0e4fa384c6cdd8a9b79713ddefccf1cf1b9a9b8340a55ec56330684 d5d6f8ddaa5631cc30932ced1cd5151825bedbff4f7c454fcbccc0dedd8822c4 -831500 2325e3f54a404e7bc60ccd0acd9ea77d90a31b18f8368ba2797d9a2f7388b482 09565fb72aad572d7b2fbbf1b0662da7687c7d98db22f55063d753d0e59a9663 -832000 79353ddf61d1fd1c8930b19c8e2abf92382f86b7ec5d3de61a766952b465144d 2cfcfc5a17e8042417128b3e60f6c2f4acb4f980508c3d172e0530ef1322f55e -832500 15c4c20b6d16377134e683d2eb7d561d4276a32d61f2179b1ec4f6461ec4954b 8d2364c10cb39a2c74360fda5585ead678c0325656ee7e2803383cf5c9e94862 -833000 771fb7f8e60a4065f3977ce3397d58a58102e11111312bb8d61399be0774809a bb06d1ca6e8e92d34fa9f31c9e3332ee8b3b31e0a4bc3a1deacc6a9e0a24079b -833500 b9d939f1ccd4ee8a2b769a4b014dd932f2d51d765eb4a4cb45844e726ba26f7e 77a9c4bdc03d8413b3600eece8b0593804b58afc41204063c3ab92b4c70d2478 -834000 c7bf6a274ef1f46d5faec1bb73cea0d5873fd15340b0ed103b0551213bd0b168 89deddbe651ce60767e84fcaf8419a7146cd8128f439436cd9c5edeea0c0262b -834500 614d3beaadffc9dd3765a68108e9f2e01c33a9c440438163970be6883f71b68f b8cc0eca95d7f827ab45bcba1eb5640f883f803c6635d09eefae1ab30558872a -835000 9a9f3c4367e50c24b3210a0650dbcab4ca0762018f41110fd7d45e70a0270e7e d827e1af0280be63e64f467a81e39404d3798234593ed89f03619354cd4dd7a5 -835500 cbbc70202da7cdb4cde6059eda7529609c9781e534661c44a1f61e5fab4de31f 9640b254c6bf22f95f94b10ee1263d475d76ec7ffc8d8813c2a7f73a7ca77a28 -836000 63d55fcaa4b84b7278dc98564a5955756f3ecf915b231cd6f2399ec836537a34 be4ab8603457a5c080f6d4f451702426b19f87ade3869565c41aa9aa1cdb6b16 -836500 a0a1ad507cecde4069df4dcd3ff6b0e44b917e732cded5fb86d50acbae0009eb 09c9ddd16cdd8ee68faa85a59b8547b9d07b19ef08ad42fc9d98f9d85ae7f54a -837000 4236b2466078279f38a8df0df56bbdf71da7a184f750d439aae1b7b9b6a0e217 1b7b95d0f01cc0dda255ea389572d8d66be622054e9913e6471347d83070da7f -837500 975034c8d678099a6afeff9e8e37d1ee524f64a851ce07def65676c0ee189b4b 2dbd86bbab192ae7e44609388bd9036e20d6496962b2ced1b23eb764d4eeb3b4 -838000 05228288f4e87f9283efa2e6547316fb61f8a6c9a1c4b3dd1b919d02c4beff88 8bb8421d901f05fcb5b476b8d5aa66f4c380fb7b00f65833f6b0bdd6ca93f62e -838500 f165d6b92e8b15b8a276e7aa3682e61c44e6729a39111e1883cc8bcc78cf9b30 55e669d31736fed4be07280a142594c8f283e7a427f0630f9ee7f0b06411b948 -839000 e7b73701d281fab70e7279cc3406b961db9c7d89643139882ccc269515bfb8ce 44e7b9087a0f031995a963ba2c3d4d59a2856ddf3e822d0944fa472768990ddf -839500 a0e9976acd9fc6b93cedeaac38938156409b74d9192f1eb4d614d4af4072d67d 774aeb086be488987a9ff3d9d80fe11d7815c1061754431fe3ec2ff387a4e2bd -840000 85f4bef924671af404c377269d655812da734608007a1e43c7e2c974ff1a7f26 a7c27c2f0b37677d61314ca1a510aef72e2a7149c0dfb3e314c47ff151a7589f -840500 9a3f8a90c257352934919ba5678d710e02abeb3f8c9b609f00827147d2f7cf81 c9234118875f5ff26dd4c37d0f498911d1caba96dee4d33a50c7ce378a9a0749 -841000 51b45385204a2bec9cfb32ccd8677bb9fce49c7c5fcb6a53c452e9b36cdb0bde 07ed169f164ef448a9a828d17a6c3455f3a11dd6c2bda1eb38a5100b8817e04c -841500 92f53759b018613ada40999270e66657ae1026e4997862ed0d5e5560b917d6d2 37b8239afbb1d59bb35fd5696404860f47dd31163981e62738867af4d1d13c85 -842000 a1202ffaaa1bef1c9c95e11f9b2f1e1b03e69f535628130df12635ed9a3fc297 ff3835e7e4cb8e4514adddc8fdcce0466170f3062e57d9abd9599da0fd0ae1dc -842500 fcaf836bba0923b8d887f619a0ecd298a94f04a1127f82773a531d8951326582 7fd60c91ddf7611c5d0200f3f5adffda13a651c5bc71929b0724a3ef0c178463 -843000 37827f08056c92edc0a941127d96f9f4f481d70cf2cb6c8c0212bbca042ea04d 863b61ceff5d6d3314fb420c17bb16c00b220833a634f53d24f7fb6c9ec7f7eb -843500 5dae3f790ecdfda5bd46aa1005cdf1170b25daa976dfe3f83f07cddd47747f86 3d352565915c9634066580e57621f6682cc147cc92fa1e7f0112af699a2a09fe -844000 b3b067a2be410c5b04cbc3088bcff2678204f31c734440fa5ce28a43e61f6e20 dd379efdd80ed38f855dc2fed11db6947ffecca2c6d78c3b13d9e42de618eb95 -844500 d8ec90a7f602aa58fe31112ed0917f4597352ffbfb186524253bd4a88a283efe b8684b9b13ead86b6620d8c6cb1b4e3ae9891ad53c74a5ed93bb547b05d1a8df -845000 66ca29da4d604a893f7a56ebd96f365b3853ac2de6b38b71db898ed7226fb49c 2a671d1a790cf390618793e3a9e2995de070c431014e9b1c88c9c587cc12708a -845500 b735fe850f31101901fe04a4207e15ccae72039895ae0f149593dee3e6cf8a47 fde7269beb8e5c3ea60f2b30d1d43ed52319787b1d9363aa67c53e6beb187d6d -846000 b526a9a73f37f20c6ae046ec9b131f6354e90a4596cec60cce1414285c838df4 fd42d265ac2d194a94732500fcdaa7f4f2e629793fb220a871459880c0cd000f -846500 761bbfd7f554b81cd153149a73641b567685b60914402dba0ee171d8dd0237e1 2d9ea683992b346008f860b330b15ba6ea707338daba431103b2a444542f9870 -847000 375dd44f3bb80150df686ae8f3813999d60507c6e9ac4750686b5d182adcec3d e4ad131095150cdc0a23d0d7948bf3c870e01ed0b4a6f9950457ecfbb254b342 -847500 0539f76c06c311da93887c10f65904de31c72a00a2c0ee1bc66a46c50433c0b7 2ce4000e6e36145f7c0711f53a8b20144a69599490a7da79726938926685c5dd -848000 c6e8ae1f92209bde14bb652bc8478d5592d0f6741c3d2f2f232c037494d81f70 b7c0aedb71b645f0501319a9842e1fac4873184f50a0c5b758fd9f2cc2547a1e -848500 d302c73e4d2ce3e318afb5cc773b089956501f00f64de08073bde92b2f3a99f3 0a8901df9a3d00b66ed1bd0b117645237b61fd34c63fc45a0604daf2ac932bea -849000 0ad8844c1a45d6846464c00e9c6853719f80056b6f0fb70821536a133432ba1b 6478dd9c136dd28bbc4a49eacb7909c179abfef94618dc6da67adb4ffe69c6dd -849500 8ddd724ab7ab24e5ce2f5355c2c4bea780fe7a2b4a01fd04d6a0be5bbcf6059f a8ac1fba940445cb8dc5f6eec18d1546f36bc441db187b088b1054ce8236d17b -850000 b5e0c35c2d33ac37932b6d187a8839f1bf846817dbf5f4c58b73418e9a93941e e9f2c9230ca20ec14c17a35fa24d9eecf9119c5a38809c420ef099d9cd4ac61c -850500 7c1ea7bb106ee4a55d64930589f44b2e9fe63ab9846eb3caa545fd3b5597ac0b 9b2b304003bc1746f27de0d9a7cadc9dca7d6c87b6cd5c88da09f45282298480 -851000 78c3131d573b6a70a648b111fa904b99707c622bc56f842297953968e50bb804 9dcd68f3d2c985c324ae53f03582ffce484a70724e2c13602f84099737641cd8 -851500 e470491ea5d0631653c6200effed322f6696614bd98109f9f1c90c2cfc72f211 5dfdf81aae36a8b8aada229a8ddfba138552fb9e101f4faa56bc76d3860e7738 -852000 528590bfc01e4b7f567aa786f0de29c2b7aeb8dc3042114b087f761a5e6b161c a96175b5107c4129f6512d54adc38ebe2f236ed6c3f362f885cd4a96c6651e0d -852500 a286a106373a8e32cbc0b3df7ac65b0720c04cae34a07cf070bbf652474d8c56 205a7977e413da822705095027abd2edbe7c5e34c9afb7225721dd18b700454c -853000 a2d7a0b916cf5aff1d6cd5150b034448c58dbd104c5f88e9b18a692d4a8e98e3 d91fce318de2b273cbff6891c8ab29c769d7dd2f09b302937493a38488ce1446 -853500 794d93de5f3d5c39ad05ee77658de33f094880b037da8d2c124f4257f7360164 3f94598f08e53b436df3517458172624b710f4f9c108c463a39b2b816e511a0b -854000 886b8b0cae2d1c914ab6748d636d5553dde505c655102ccb384a5c9a2b864516 308dae1dc6e58335096c15c90fc276e9cfc6639289c25a9a748ebe226f37604d -854500 78d0ac66bbe4ed7830eb9025fb934514035d9440e2dfa75d4046410185235755 e2976153d1e9c4253528b84741fbf9d8bc73e85089d63a59b29d5c847e336c02 -855000 be6a06e20a33be8f7e0c96318ffc3ad202215dcc9124c06ec678a6a775c8f67c 4ce675eafc85e0f8d54f8281fecef780e98677534b3dbc3b1e9e7f7a529aa3dc -855500 ac409e08616a1e06ddc3e14a2b1f6bd947840932fc6e8b007246de280a6b66bc ebb67251598e38254f9327ff1dc2336da5269cfc209a5476260da523cdfee0ab -856000 62a624ad49bb1908d25d7190f363019b1cb5f1a1dfb849bb50226561b3c60218 ba4fef7924ee2e26f271a49319726894894497685b1c81ea84e0bb62246c24c5 -856500 f02dd187e61db50768a596177bf62878130d15910ced1f4bed2d5aaebcf4960e 8e9e38e2a88d1a24151ea08cd82c2debc7034d5fa21e75f926d9a6c0df18d6ab -857000 b2ea7f0e6a51ea74155d6964d732dcc4fc8a0b71c4e6837d1f17030d026da89c 8ceccd983eb05888198163e6a0ea44261e44876289a9effdcf3d377ccf62ef67 -857500 f99e644cfa949f806ea938b97d5232d9430ca11a51ecb0ed30ded90e6d4f120d fd26d9ef2f463304bb2839e8bdb3b5b0f48592e2cdfd043ad809292e22391623 -858000 9dfed199b5f19ad984111f21fdaad2d5d1779a317ba5982a93e14e37e21a2eb0 3da6db23d0fbcdc02c440eb755828b4a5c02fe77c75b153055eb25362399216d -858500 daf47ce2ce33b9db10011f6bd963bca3abe9b8b27e6101394d5516555e8e7bc2 4fecbb4ea28d764bd3dfdcb6571a7c6400c76c1e7f21a1c1407d057fbc6feb62 -859000 f6cbc9c86ebcd2832f2d0db57e47b611d187189a37f33f7588c7c24e2f2174fe e85af2f0bf8bae60e417cc65de17bcdac486348b40eb55da41a51e98b5c148e9 -859500 11102fd852576a361c4c9a3050eb8d605f317f82ee78200d2a2820d8a3ff76ae e70ce2ca1c2e9b818d276254f46f0d6156003a8421ffa99fa8499a09a982e1dc -860000 b0689ff799ad43c8123c38f815e8a5dfcb4fa2b2cc1d59dd08f6d6e6f260ccbe 60815a438a372d41ec3439f8b21cd8cbea71b090758260b1920dfdba4558f235 -860500 6298a42b99734a2702bcc358dcf100321fca31a1cc547ef0c168fa83a50eb132 2881b992eca478a15c1d505d3b021e2f589d536832e98cbb90831b4d0daff767 -861000 9f8f6446a6df4ac6674a0639bc616fbf8955fbd7c5a6ae8743ae009340acc6cd b9c2b8a675ec2a9f1323f5391a81d5a2bcb83ff02fbfb94e1960eebb50033bfc -861500 c53640e61534d7de4001cc4f6547133d225ebaf607937c6ea99b3a92e0f1b445 7befef633b3eb72ac1897e3628b20540cb0cb51bc447fd69877d178705b165b7 -862000 1bb40c878bbe264e2fad6a6e523345390091bef9bf689f6860bd30fbd27ccece 66bf4703cd800c13edc3e67d0889df0c4694e2f6545c5f71bb0d43d80adaaaf3 -862500 464bf61e9afcf7f9418661d069ebb015bed143a3c53449e9ca98013c624c0d01 b858f8d0afefa1f199f3434b656587228c659429a9b29876139cbcde4a66d36a -863000 0dee780a99a58bfd60c05f95db7ecf49c8ca8380b7a5b8ccb4c7c26229966441 4555335383dd8dc416b36cfdd110d6da87faee63fd0461dbacdb6cf9dc61fd1e -863500 98a57cc44810adfffccb2f42f93455e1124e3297a8dd4e176b6367bcf864fa6c b16bc478ec16263bc8995541eeb0cfc6640074c65853989f7619f1094b48f17e -864000 516c8212c055b610d7295dd1dd14e797a2b4ac025f1fd2aa7b3d26488f260a60 e221eacebb459d180c743666d691c11997995f6f4d75dd21613b75eed2be2425 -864500 2e8ffca67b4cf71272e42d524e1427b794a8e663b437c156cce8f9ad39d28b58 7237d3868b25d2fb9801de887b7c2071cf24952719c6170a6e550773a61a2170 -865000 995bc313381ad5d7799cccbcfbc18876582f5a82e25dc4a6bfd299facb83adba 3ea758c944b2f0be32fa7fb541e18f683734df6197ba711285bedad4f17d1c8f -865500 dc2fb63083a52596b814426dc2577b6eca27f5e80b08b83776c93adb0b913324 007ae746a4a5b901f91e51014eefab59c84dbec3a3e784711d1a16df0aa04ac5 -866000 a1a4a61f9e30b4ac585c2777dcb066e543a3ff03ddc20b67aadb9fe8842080b8 953ff29441259817927e36e3a89db69fafe11d253509c36a2bd00805563ec4a5 -866500 44fff17033fa5e2f48afd1313484e62ecb1bfaeaa0b19b1973514abe18381d2a 1bee0d01001a576776d0e6113954449de228bd3f69feea67a11769f2626176cb -867000 77d6f737b4c7b493657ef08c7f28b5dc43e3a7194b2e3193a37d1a931daca9a9 a9f847fa150f5881ffade66584ad6b5a741f8dcf9310eb808181c9c3e4724a8b -867500 98da2413dbd1bf3e2d3d6254f849e3a971ff9579e78a4bb1ba192f61a1ca1bf7 55a4bc913aa643d798a0d9d29b5c31bd38db0051ccedef30bf4bfb2ae6210159 -868000 1e33271126faa909e8b77bfe4431587ac68d50716e3ddee70f18f4ba56509c98 6b3ceb03adfc3ed05acb7ca6a2c9822e0b183c1359826f2714d26fedcc8b779a -868500 b4bc5ab2d0f52588e8e154a831e92f9bb249bb30c4b6a4e379d529d9c916508f e1810b871f581727fa81164f7ba37242a0376aa7870f897547fa032efef248a1 -869000 9db0fa91a26eb2c05272e50cfff46c7c9faa4d72938f14f03736c7084c4b2d20 e80a050a8dfd6c5d2ecf765f43222b8aec1a85232641c32583487753ab3107ae -869500 ca4ed5b1069fe42bcf42af8fb065aaa98db119b2e98c23c8ee9dc823c46a0bc1 1f45046c69978e3a13a013d995a469a2a6583b18cabe3e48c5735a1bbe88f1f0 -870000 02da00fc2fa6bfb0027e8c85a1b92e919495b84e763dd57afe758df11635956c 8ff1ef73ea14756b421192b3f936ed06cc5a8f016c33a4bb8c3eb94a0a4afb6b -870500 04cc97d0004ba00a8211986f0fa13bad1cb0e7cd17e302242128ba5bc923bbeb d4dce041cd8b2c51cfb7a50864de5d72a627a93ea5f5cc4d837004e9fac80691 -871000 8c46f91d61fa06dc47ef2715dd66a510f1eb909b275c85c0f8f914e8ef0e2ce8 a04657d974398377996f4584c23bf29a55085fd914b88fcc85bcfdee46c1f4cf -871500 285a13a25bf27fd974c9bd32ffda2796ba46e57044b4c282331cdf94ad55ce0a c701e8a240d4dce38b98c91b01c0b306ea6c8e72c345a2fcec704f4af6f880a9 -872000 0f474790eec84e0216b27a41df528a1037767792657a3aa79122dc31caf1e1bb 0774199988a33ae42d91de34cf2c1450aabd65b62e4792acdd67ee92c9d617fe -872500 4192751ee0a2c7b7bebe5e6a7c60dfb98f1527eb6dab97071b5ea89fb851215c 9e36875819fc969d8b5f971bce6d1610be7a012a520b317ce574c1e24f26c0dc -873000 34692e36b62fdc785dd9468d43a0a637aae66ea75c592d5c92e3b79245efe449 e97152bec752a6cda91c4153cf191e6a04135a2d824a6ef8ce6d64f640a97fab -873500 af2ef369df933f912140c7a4ba01d3e33ae803b7b2f4939f8a98405fa4127b90 3e30270cf39cf279ffcf99ad4b0cd55c85872bbf82654d03f6a9a40867ceaead -874000 7f1cd90d997b5a1da4daac3691082770bc7bad48acca998746980f0b57ccf21c d7cba24bf85848378fbc0f655a1795b9baea22b97a29b3bb1b74fcbdc25baec1 -874500 c15fe484c8c031d1327d24f1b563bae0c6ceb1f81b8c0b37c1a3a6d3ea9c12a4 532b3b617b128a1da69a7390fa37d292771bfbe039436bc7f34cc60d51ba1289 -875000 6d606825c8c4902999704cd9839f60f072743c33ef3cc8fe5b075e15ad6f521d 0f98e7eb858a741ea9b7f9260142cd07d98f3ef2fd0f5897f0dd1196506f28af -875500 8102b25248d5cc9fc5e8780fa7782a5f37113d5797ec544bcb6164d922d91ddc 5331a1c3f2f1e95e9acc0acb83ef4cbe04785dc7a319ce069d252cccaaa748b8 -876000 2a6d640eb47cbc93033640e4eece162640b36cf256a1cafb406e2c22f0c10fb0 34f34e19ede327aa5be14240436f18ead4abe6f226c1571429937380247402d4 -876500 61e5fae25c4f18e92e7adf64242dcbf6507a7ce4f1b0de6f2e614b8f1f5b33c9 3f421f95de7e2129353ef06a9f9a206639e0f5be018937dd02e4c39907b75702 -877000 46d077012ece5a31c29ba761425e6ef9d42501740db45016c8c5b7da1d216c7d d06c5c6aa3c05475f8a8649b9b6134e0c92301d47186f2c379e7b159bab2388b -877500 610a50c20c1661286355fad8c8d067e794b5ed61c14087d04976cf0f378e37fe 18141f4f7bed0308bddc68a7b897a035293fa9fdb074b6af3b271c2365a3d1a1 -878000 1742b73fe7c2d014484b21a1604b0a70dc7f12540d52b21ccfdc9f9ea72dc53a 90831e43dd3912ceefc00d3d544c3f26dbf358ff3b5d24041ba1f322be13d9f2 -878500 749fec5fbed9d5446533f22f0aa36c20b63b35116e6005ca519f7fe1ddc76b93 a13ee98f76ebaece600b0723a6ae7f7ebcabbb86e6beb5c4b9e5cf3e8170dd76 -879000 8c578dac00d2b6db2e1972886194a4be70dddbceeb457150cf1b74ff19022532 627f0854e663c40920d22d252b41ecb60a4bff1de055d1789727ff33eee14455 -879500 b31016513fc56e8df0eaa71197462492482734a9dacbb0d85838bf4253b70b30 854e8e0aca0625eda1261e56697d87244c1e386be8d6aa78f15de8de50a76169 -880000 e0764e8169753f7f532973ad4706e5f6a07e64b7ec10f64240c91f0d319f485c 4e1ebede695c7ee95e4442814a5d98539df2ba46757b95d8ba4f0e0e437bb535 -880500 b72623a454e91149046f522d60935871a1e5f098389d9cad4086119732b5e3f6 580082c91f04822d21265dcbbf8c3d3a0866171acf5564e982c8386ae5a3a40d -881000 b94687f79df272c2c5e85e21bff01136c5e99576571bbb8a635353aa9b331c81 8f383eea1f9a3014c27cc3c0a6196b0764c269a1f2f3effd31f4f6b76d2a33a7 -881500 5ed1eceeaeebe16a0c746f796507f6b0dde6da8c53f4e3502cf5a49f4ecdff18 901bbb467df17a499475e767cf7886763681deebd4bbb537a4bfc7f3dfb89774 -882000 bf12ffa015864c59f04c80d0141643c9de99f79b79c2b26ddf9bc398b9d8bf32 2b7b77da53ad2a19f61e3aa54ab5833bef79cb88700e51189ce7b1ecf001a2bc -882500 c8e8deff1d81c65f2b607cde0312982b03523aa76c6562c666c1dddf223e7432 ee0cfaf5a0a284a4e324c4725bc6ed5499cec94d170baff0b955ad6b2a2eb487 -883000 b12011d25c4c08da00b5acef266ab9e451d06c2fe9c65e4f149f7f0bc32b9c44 9b06de94a84c8e550c49947303d058d4a93d898970d50b8be9cea965ca656575 -883500 77b6c306c2410ce6e03c825d016aafeeaea3daa7172111085ebcc5806dcd3bd9 01d7719a498afa8051f872a3e8fc32cda3eba0e4151fc16722c0944d8715a6ee -884000 1fe3f4911ede2f37d7587640a80408092c044904f44900ce1bc41df2e0f887fa 8e9b706cdcdc53e77915c281b532f0589c649a80fb563bcedfa8fea8493d4a67 -884500 22d008aa6022144cf5b7070e91a056b437f105ee9ee3d343c2e1eb485afc55e5 90404898817c93e64a98b4919df62ae8a21e4dcc9bff13fb563a33d544b9a09b -885000 0d39372bb9bdadcd80ce022e52792bd5097a8235cc9a571cffa92805b0d875b5 92306cc62db985c495b43e84e2c4ee4c6310035952d4d52e4a13cbd1af0311b0 diff --git a/iguana/BTCD_peers.txt b/iguana/BTCD_peers.txt deleted file mode 100644 index a36595633..000000000 --- a/iguana/BTCD_peers.txt +++ /dev/null @@ -1,49 +0,0 @@ -78.47.58.62 -67.212.70.88 -94.102.50.69 -50.179.58.158 -194.135.94.30 -109.236.85.42 -104.236.127.154 -68.45.147.145 -37.59.14.7 -78.47.115.250 -188.40.138.8 -62.75.143.120 -82.241.71.230 -217.23.6.2 -73.28.172.128 -45.55.149.34 -192.0.242.54 -81.181.155.53 -91.66.185.97 -85.25.217.233 -144.76.239.66 -95.80.9.112 -80.162.193.118 -173.65.129.85 -2.26.173.58 -78.14.250.69 -188.226.253.77 -58.107.67.39 -124.191.37.212 -176.226.137.238 -69.145.25.85 -24.168.14.28 -73.201.180.47 -76.188.171.53 -63.247.147.166 -121.108.241.247 -36.74.36.125 -106.186.119.171 -188.166.91.37 -223.134.228.208 -89.248.160.244 -178.33.209.212 -71.53.156.38 -88.198.10.165 -24.117.221.0 -74.14.104.57 -158.69.27.82 -110.174.129.213 -75.130.163.51 diff --git a/iguana/BTC_hdrs.txt b/iguana/BTC_hdrs.txt deleted file mode 100644 index 374f793ec..000000000 --- a/iguana/BTC_hdrs.txt +++ /dev/null @@ -1,195 +0,0 @@ -386001 -0 000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f -2000 00000000dfd5d65c9d8561b4b8f60a63018fe3933ecb131fb37f905f87da951a -4000 00000000922e2aa9e84a474350a3555f49f06061fd49df50a9352f156692a842 -6000 00000000dbbb79792303bdd1c6c4d7ab9c21bba0667213c2eca955e11230c5a5 -8000 0000000094fbacdffec05aea9847000522a258c269ae37a74a818afb96fc27d9 -10000 0000000099c744455f58e6c6e98b671e1bf7f37346bfd4cf5d0274ad8ee660cb -12000 0000000011d1d9f1af3e1d038cebba251f933102dbe181d46a7966191b3299ee -14000 000000002d9050318ec8112057423e30b9570b39998aacd00ca648216525fce3 -16000 00000000679a1ab3af6da03f13a0bc96d7215e65458b2d2edfa030b5b431e8b3 -18000 00000000f914f0d0692e56bd06565ac4de668251b6a29fe0535d1e0031cfd0de -20000 00000000770ebe897270ca5f6d539d8afb4ea4f4e757761a34ca82e17207d886 -22000 000000004625a14242beccb38c63a1f770a76ee5788764e6c0abd4129bbc1b9d -24000 00000000f04fccc81f37002707e9501a3f7bdcf25f65531f386a2da8af20122e -26000 000000006d6c151db6d4d67356d590a897a11cd7d8111ee989de6f2f548410bf -28000 00000000172c5ed49d7dfc29bf9a18a53fa2d050fa37aa210d6d4080fd0c7e67 -30000 00000000de1250dc2df5cf4d877e055f338d6ed1ab504d5b71c097cdccd00e13 -32000 00000000049172ba3ec1b673cf13e3d0049c1c07bb103ed3fa300e3833480055 -34000 00000000495968d19210d3be15bd24fdc19805a0ef15026b0bb4482b04a9da3c -36000 0000000080c3deea35dc3df90a5fbe5f27db52f5e01018ae7d62f8b454c71335 -38000 000000002dfebce284d1e08b6cf04452530891579b7377669865889498de8f3f -40000 00000000504d5fa0ad2cb90af16052a4eb2aea70fa1cba653b90a4583c5193e4 -42000 000000000f80c09687893406279f62da437a6a0b95b8dc096b30c10ce088fc64 -44000 000000000122898b31073a770a97cf599c00672fc8d6ae15652235862f8b76d8 -46000 000000001dd39771dbe4f9fc6da07327f13f894dd2c1a46cdfcedf930fbbc52b -48000 000000000f3d40ea2bfa8d779010e52cff4720c072ec4b12ed576cf5cf93c947 -50000 000000001aeae195809d120b5d66a39c83eb48792e068f8ea1fea19d84a4278a -52000 00000000082bc4398c4aa5bd8d9fc452d60d533ef68baabf594c9e7d6649049f -54000 00000000144197f54afa21ae7db2bc93eee604432101fc0ebe7966a52bb27e61 -56000 000000000dfa452ea45e0426dd8914c35e24dfd4399037c5e6deb9f18f58d6d3 -58000 0000000013e3791d288d9db814c52fbdf240b2206eb8e19d7dc80013c60c0c00 -60000 000000000b554c46f8eb7264d7d5e334382c6fc3098dabf734de37962ccd7495 -62000 0000000006dd4bc72daabef992f860e703820de119af3e24a1ea6f6c81521011 -64000 0000000003d7055b51d7b9ab693de84c03201fe0396af61dbb30bf31445d3f55 -66000 00000000071d7e8a0f4895e60c1073df9311d65a85244be1ee6369c9506281af -68000 0000000000d991791fdfdbccbbc2a73d2f86ccf78e2d0a7ce7675f40b5986b3e -70000 00000000002b8cd0faa58444df3ba2a22af2b5838c7e4a5b687444f913a575c2 -72000 0000000000eb357d4c6fef6ad9a6fade126985ad36042a99cf215a4454545977 -74000 0000000000573993a3c9e41ce34471c079dcf5f52a0e824a81e7f953b8661a20 -76000 0000000000571138ff757a28ddf9b56f28c4a461e170660bb5ae79a556069bb6 -78000 00000000001f3fe62641b473673c9ababbe207046a109f0861af95c905a918fa -80000 000000000043a8c0fd1d6f726790caa2a406010d19efd2780db27bdbbd93baf6 -82000 00000000000c9d1c4acc114afb58d55db5ec44a963263cf6247220b7a3f85c5c -84000 00000000001385326e30864192ba84ed2f9cbfadf0698655b1c25f93c92f22ad -86000 000000000000ff4e1adb14f07774dad6b34968a5e19d1a2fe1fc9157e7c2b85d -88000 00000000000ae9e98b82b39a912cdc0ebed97c26376780ac996c84d9ec3264a4 -90000 0000000000071694daf735a6b5da101d77a04c7e6008c680e461f0025ba7b7af -92000 0000000000001df90b0c523a4d7e4731336b00cf4ba9d8e02d111523df80998c -94000 000000000002a4c42580d51f0ddfd867eaaa790781c484c633a69167d17b48ec -96000 000000000002c86b568cdd2d0f4b0430cccf42bcde3361f63a32e23b5d839e99 -98000 000000000002272a6dfb695d9db936d813bf0055ae92e920c2791d4c5f7290f1 -100000 000000000003ba27aa200b1cecaad478d2b00432346c3f1f3986da1afd33e506 -102000 00000000000335c47dd6ae953912d172a4d9839355f2083165043bb6f43c2f58 -104000 000000000000a9887c91956b638bb3c0651321fdb24715354c3fc6633f5a16a3 -106000 00000000000058d919f52d255f394ed0aa3a344432676fd30f1aab4e10c22fad -108000 00000000000167cea0b43ff7ce22f330d3e302832187eb31c61b15bb1511e118 -110000 000000000001bbda3f22ef8e476b470a2d3ae16821c23a6d22db77318d0799a9 -112000 0000000000001d69b3899a49f37799c375a7471829953d5470f468f48ff70432 -114000 0000000000003195a1e6dc48a540264d37e9ef79b552bd78ea4b93a3b6e7e449 -116000 00000000000007ff257fb2edd3fdbd7b00c127a66dae1288fc5e26c402d13bf7 -118000 000000000000774a7f8a7a12dc906ddb9e17e75d684f15e00f8767f9e8f36553 -120000 0000000000000e07595fca57b37fea8522e95e0f6891779cfd34d7e537524471 -122000 0000000000002fe5f29af38282ac1c8f4ea2bf8a0855946150130419491b6c05 -124000 00000000000023e9a0523cfac29afe07a07acf81e273cd892c51ff8318846620 -126000 000000000000166b7d480aada35af1e6f9a2835d68f9c2fbd272073dc6c9d5fb -128000 00000000000003b8ddd8692769e1965554a8bb030863e0566a28bc0dc952864e -130000 00000000000011906b491883ab0f16f0e690b133ca860b199b775c3cf6581c21 -132000 00000000000000a7a0483857f0d951983ff2834a47c38fdcc22563ac0f8f707b -134000 00000000000007e3e442ce1423496a064a7c34342ba98be164ac0c9f9b872213 -136000 00000000000004da0d6d69fd474fa08fe2ff3111ff1e9e01f72899dcd9d897f0 -138000 0000000000000044c7b6a5511c0b2ae64ec545abccac8053f31cf7bba23bb886 -140000 000000000000086e28cf4717a80066def0ec26c53d660582bd997221fef297db -142000 00000000000006379826f5f10cd23739b9c29f87ca10f199f9f4b72006311f85 -144000 0000000000000681a73f1bb50454cee419048d24e1091bcddadded89df53fd07 -146000 0000000000000188cbeebda87456f040370995dc11eb3a1e76b1577b6e0b588d -148000 00000000000008be94b219a94752bde6a6a1c5b9d72abf2aaab53df7d93c5fa6 -150000 0000000000000a3290f20e75860d505ce0e948a1d1d846bec7e39015d242884b -152000 0000000000000aca2b3a267dab498adc48afd15b60cbf21fa58dc26c86a6dc13 -154000 0000000000000a7446d1a63b8229670aa02d1d9fdfd729b89107fe5d88dacd8e -156000 00000000000002adfcffbd5f09744ae3b930597dd0ea684cd37b816783ba3762 -158000 00000000000000e50d56f13c7ce64183386abcac63462ca745b711be27568f52 -160000 000000000000066c6e629b2fb49c7fcc52b82fe9833f328e0c3943856facf231 -162000 00000000000001a83f5b20cd132f38f792fc02a17eb14d494c780ea9d1c82acc -164000 00000000000005a38f162cf308edea0a0a5d000bdb2073cba2386ebb1df7a2cf -166000 00000000000003b3402f35327d144a465f3768d6e6cb06cd8a2d8fc1328b2477 -168000 000000000000099e61ea72015e79632f216fe6cb33d7899acb35b75c8303b763 -170000 000000000000051f68f43e9d455e72d9c4e4ce52e8a00c5e24c07340632405cb -172000 0000000000000837e82c3a4ebe35a1d1d943e056234dba7c629922c6d4052d4c -174000 0000000000000504d3e701deb624eee4370f50c3d688fd1c27be5bbef07d76dd -176000 00000000000004659b5b8602b2132b62973994079a1c828df6ef8d6427e4686b -178000 00000000000009eae2697a7aaf57e730b707b9f4530449c16d924d534d41f297 -180000 00000000000004ff83b6c10460b239ef4a6aa320e5fffd6c7bcedefa8c78593c -182000 000000000000068dce12903c1447e4c5b60311b61e443a25d5fc82c77f4f9a8f -184000 000000000000060405a235c6b968ccb18fd6b3800ae9742c2524e28863367359 -186000 000000000000072ede9629fd1fd1af3cc2baa0e637f1959f34884be0e160dd1c -188000 000000000000004cf0c72d6dedfde88ca4c3dae129563210072ee68acded0ab1 -190000 0000000000000708bf3b261ffc963b6a768d915f9cfc9ec0a6c2a09969efad1a -192000 00000000000000af130d565291ba49208c546685c69b48a293aaf06387fc22ef -194000 000000000000046242d4984ecf2217e9afa113f2835bffbff118f2df4d80b216 -196000 00000000000006ae59396d4a289e83fe1b9967630752a5799f064620af7836a9 -198000 000000000000000f2ad431ff18ab1673d911395c8fa1f6801e054c5dcb54f8fb -200000 000000000000034a7dedef4a161fa058a2d67a173a90155f3a2fe6fc132e0ebf -202000 00000000000003282fe1d5533e4275fd9f51e6ba0352ec01f32914e9fbaeaf55 -204000 0000000000000423eb625dc140272ab97fea3ba6baf1dc56de77deabcc492872 -206000 0000000000000130b815d40fd6d8851438cd21ac9e428615ba03a1285ef1374c -208000 000000000000001db5a1515a5f8534c941b1628f60466e6b709b3b320254afff -210000 000000000000048b95347e83192f69cf0366076336c639f9b7228e9ba171342e -212000 00000000000003d906e4131c39f7655b72df40146d2967f5d75113a09610de61 -214000 00000000000003e6427f9fafa8b0e1af0859f15cea90d911f64445d296a2781a -216000 00000000000001f79a2db15d0ec6d951729e044749372caf504679bba5b1e65e -218000 0000000000000569070e338293af66258adba29dcdd5f33212314dff752ff458 -220000 000000000000002fdd2c741ed50bc3975a640ca419081711f30f553939641303 -222000 00000000000002c752a481ce0c45450ab046e640d38d6532178721e7700d8148 -224000 0000000000000107ee276d037218bf1780dbf6d4256bd7e05c66ca133bbc9ac5 -226000 000000000000012c614cf477c3b155d339f29d565c0258f9846c2f4dd402ff9b -228000 00000000000000efc4311c93fafbccedb6fdc682b566cba9519f1736b9788a67 -230000 000000000000012cfb19f5662707816e122ad60dd9b1cd646c6c9899be2c9667 -232000 000000000000018f47636e1c3a946db77624880ae484ffb0233f5aac6316b3bb -234000 00000000000000597f9263ea97bed4d3b10fbd55733a73bd1027f1a9b6c1451a -236000 00000000000000f2f5e55e89dde082cecc9b4a46a10bbb4197f5e35b16612db5 -238000 000000000000010014007d4b51ab60063684665401e448c6b0b1971a7398a442 -240000 000000000000000e7ad69c72afc00dc4e05fc15ae3061c47d3591d07c09f2928 -242000 00000000000000c95233d37a8c78dff10afecb14060347151b7eb7a04a2a5a3c -244000 000000000000006ded1526017d5b87ca22e1bd0da3921872cc99e9ec77ee5166 -246000 000000000000004c318a3ad2ebac28d140fada215b11f5b7d8e9151ff0b000af -248000 000000000000004d945017c14b75a3a58a2aa6772cacbfcaf907b3bee6d7f344 -250000 000000000000003887df1f29024b06fc2200b55f8af8f35453d7be294df2d214 -252000 00000000000000200e99940b296ded4ce16462bba1950453b29abf313ba7cc47 -254000 000000000000004753be91559a2c74c6cb8a5d2be6db1df2ca0b2385697e53ff -256000 00000000000000252b217c0ce5c4d96b825b90dacbe8e4dcf5f6a8ba6749f3c2 -258000 00000000000000159f682a983465761f471dd24300746efe8db5642411f1b631 -260000 000000000000001fb91fbcebaaba0e2d926f04908d798a8b598c3bd962951080 -262000 000000000000001002ac67e026c523c3779b1ff2e3b9e2b7bfa6022ee1afae2a -264000 000000000000000d05c31485c532503939ca0b88d7e322dff79900ee6cdd5ed4 -266000 0000000000000009d755c65d58c7c1fde9167ba632a85574de3bb11c8a862e35 -268000 000000000000000048974ba0669938f7f8463650cd5c48c027aafd88c00a46af -270000 0000000000000002a775aec59dc6a9e4bb1c025cf1b8c2195dd9dc3998c827c5 -272000 00000000000000050a89e2ffb28757d35e14615f23b981eca68906c8c71f65f2 -274000 0000000000000003fe2d3425e9f9b906f02f40b3db90d908ba0fbd1e44cf43f8 -276000 0000000000000004b8ed801f8a09ba8c1248a5b1dd1533a35124a80438573f59 -278000 0000000000000001bcadd1e4b4d01063a17347dfca126c63893d2aa37d82eb7f -280000 0000000000000001c091ada69f444dc0282ecaabe4808ddbb2532e5555db0c03 -282000 0000000000000002337ad25e6a9767420766309cfea79f13dd9c910bcf5ca063 -284000 0000000000000000eac86582f121e5431734e2ea36bf73347022c99c1adae37f -286000 00000000000000004388ae444347bde423f2f3aa6ef335b50909f5bc27d31ea3 -288000 00000000000000003c395f08779c3ac1301488b8a18c0999c008129a55610785 -290000 0000000000000000fa0b2badd05db0178623ebf8dd081fe7eb874c26e27d0b3b -292000 0000000000000000620671231acb6a68134a0396235dcb0e53f4fc82bbaa1184 -294000 0000000000000000cb2540b3f00ce422887904c75b24bf75b8a73817302a4138 -296000 00000000000000009570102278e59ecf045c16ec8c8a5ea85bf823d0ec72e3d0 -298000 000000000000000047d2f2eb7278e3f4aded9acaf502f5ec27bab5018b5871f2 -300000 000000000000000082ccf8f1557c5d40b21edabb18d2d691cfbf87118bac7254 -302000 0000000000000000072268c9bb18603566ed5012378c29bb4d37e34cead7448d -304000 00000000000000003558a1ceec3f5338c0e887b4171410195a7fa0a81bcaa628 -306000 00000000000000002bb3265a8bf67ec2aa436c297ac7e56fcedd4dbaecccacc0 -308000 00000000000000001d55aa114bddd81938d09e2dccd432dec59a4078ca0bc0f4 -310000 0000000000000000125a28cc9e9209ddb75718f599a8039f6c9e7d9f1fb021e0 -312000 00000000000000002bd1fa27964e31fe9861b40940e7ece2cfa359765b219a49 -314000 000000000000000008ae6cb20997f3c4aacc50ee2f0d08a0c3691907fe7357a3 -316000 00000000000000000d77a89ab1069e47d1213ae509de95ee0d9ab095a725f7d7 -318000 00000000000000002583a647dc5f084a312e12bb90a70c3fe1eb1e4d419f35b6 -320000 000000000000000015aab005b28a326ade60f07515c33517ea5cb598f28fb7ea -322000 0000000000000000177da809382f93ca1c4336811e4a910050689d317d62264e -324000 00000000000000000b9880c40075d763b2a5f04fc01444a6278c5d2d442cda0b -326000 00000000000000001e95e7216072cd53353b964054b592f7ce84d3743aab125a -328000 000000000000000009cb9a303d105e7b96b36546a3196f6f79ece4b43712cbb2 -330000 00000000000000000faabab19f17c0178c754dbed023e6c871dcaf74159c5f02 -332000 00000000000000001799255bc0c35f91f7d4fddfbf7e84dedf94fc59cde9b7f2 -334000 000000000000000008d1ff7b7673837e9d7e1324dc7ab8498405ea583f43f53d -336000 0000000000000000125e3e6f327edcd7163b486efc16e79b8a996270127b54df -338000 00000000000000001983dc4a87df627b63cdce28e5321cb867fbbb74c0e87e8e -340000 00000000000000000d9b2508615d569e18f00c034d71474fc44a43af8d4a5003 -342000 0000000000000000007220892af98a563a1c891c756e94be3f14edddcf637c3e -344000 000000000000000005f0a16f5a9f95eeb95c5eed0eb221e8f5dc5a9943a03aee -346000 0000000000000000068d33fd865621cb7eedbf05c6b235191fa1cb8ee2c797d7 -348000 00000000000000001598a651988bb3a45237c4f801cf8049be20f74aed8e827a -350000 0000000000000000053cf64f0400bb38e0c4b3872c38795ddde27acb40a112bb -352000 00000000000000001635a4b5f27d2ec458f7bca550d71f490b93e98e7a07cbca -354000 00000000000000000cf8af9be2709e9d7adf2c33b3789aeeff517987f4be22e8 -356000 0000000000000000138ce5493b612b0e90b66e2a76714088d6b3e6a4770215af -358000 0000000000000000073aceefab8c381c3c4edb4f87a6d5d2ae32184278218429 -360000 00000000000000000ca6e07cf681390ff888b7f96790286a440da0f2b87c8ea6 -362000 00000000000000000bfcad6c331dd152cfc713e9e0790978a10e0bfda3e030d5 -364000 00000000000000000e20bcf213a0bbd6be88d5fede6b060c737f7f8b7f1df504 -366000 0000000000000000138e108e780fdb71eb4cad533b46445ab6befbf9687f561f -368000 00000000000000000d39970aac12754eb89c2dcfda539b65562e5c3fec102c24 -370000 000000000000000002cad3026f68357229dd6eaa6bcef6fe5166e1e53b039b8c -372000 0000000000000000028093cc8035a6bc4e0d1b40932c2f8b50312a3fc86bf3da -374000 00000000000000001016aa3783721673bebbcd1efa49946b52cceb09a81465a6 -376000 0000000000000000106e9e99cf4fce4e8a4abc97f3e883956e26d76b3a1133ce -378000 00000000000000000516cd5b5f4b7e528d6e61c643595cc818f1d02f53da4281 -380000 00000000000000000b06cee3cee10d2617e2024a996f5c613f7d786b15a571ff -382000 000000000000000003cf98590769bde40ffcd6800733ab47dd406d8203e65a89 -384000 000000000000000005dc7ea53e2f6eeb09798cc9d2214f09d249661c36c288b3 -386000 00000000000000000d94c8c0b0ddec874d2a597e988154733d9ea614292c08bb diff --git a/iguana/BTC_peers.txt b/iguana/BTC_peers.txt deleted file mode 100644 index abb52b839..000000000 --- a/iguana/BTC_peers.txt +++ /dev/null @@ -1,137 +0,0 @@ -108.58.252.82 -74.207.233.193 -130.211.146.81 -71.193.19.234 -173.66.1.180 -104.158.113.201 -108.207.245.69 -107.4.134.66 -96.231.100.124 -209.6.208.31 -69.141.89.74 -82.20.129.167 -5.9.222.226 -149.210.234.41 -168.235.85.242 -52.91.247.30 -191.237.64.28 -173.236.101.34 -73.189.2.240 -106.186.113.184 -173.64.13.6 -73.166.27.56 -70.106.255.189 -168.62.188.213 -71.234.225.255 -24.41.10.204 -72.175.146.90 -184.107.155.82 -162.220.47.150 -12.23.127.150 -169.228.66.43 -192.227.137.5 -71.205.232.181 -207.182.151.130 -46.4.22.45 -198.50.238.171 -174.59.182.120 -66.172.10.4 -75.73.82.209 -91.121.108.61 -24.6.74.4 -37.187.78.27 -96.32.46.235 -107.170.13.184 -148.251.151.48 -178.62.70.16 -144.76.185.151 -144.76.92.199 -91.121.210.159 -76.105.242.7 -54.84.231.113 -89.187.134.220 -64.15.77.36 -212.51.147.153 -216.15.33.203 -74.100.90.30 -185.18.6.3 -104.131.65.197 -89.248.174.54 -128.8.124.7 -54.232.245.146 -67.205.101.120 -72.207.119.149 -192.95.27.144 -69.61.93.240 -209.91.190.202 -50.35.82.152 -66.175.220.212 -23.239.22.219 -73.229.104.201 -207.244.73.8 -78.129.251.170 -139.162.211.181 -172.245.5.156 -98.144.123.251 -177.238.90.180 -198.71.92.236 -73.254.38.48 -75.189.201.141 -52.24.104.64 -71.231.209.66 -87.224.35.189 -73.162.143.196 -82.204.103.94 -91.148.210.17 -94.242.229.158 -188.121.252.243 -70.39.8.97 -95.97.112.190 -109.228.152.9 -91.209.77.101 -217.76.121.251 -79.136.29.43 -178.212.136.92 -178.255.41.123 -84.212.200.24 -91.145.49.56 -162.220.246.101 -95.167.109.125 -153.163.32.61 -78.67.29.111 -92.247.229.163 -210.195.201.103 -95.84.162.95 -106.38.234.67 -186.88.0.18 -121.208.106.80 -120.55.193.136 -124.171.128.201 -54.94.163.92 -98.217.125.225 -104.156.97.121 -162.255.117.230 -129.13.252.36 -79.120.12.63 -108.5.176.30 -69.144.244.229 -76.22.18.34 -115.29.186.22 -78.46.193.75 -213.91.211.17 -164.177.179.162 -134.249.141.40 -69.140.88.12 -178.212.136.108 -109.120.250.3 -154.127.61.55 -123.120.167.101 -73.210.74.120 -82.136.95.220 -124.122.212.150 -81.191.80.160 -96.58.196.51 -77.23.111.25 -14.175.245.51 -76.164.234.12 -92.156.214.192 diff --git a/iguana/InstantDEX/InstantDEX.c b/iguana/InstantDEX/InstantDEX.c new file mode 100755 index 000000000..49282dcbf --- /dev/null +++ b/iguana/InstantDEX/InstantDEX.c @@ -0,0 +1,582 @@ +/****************************************************************************** + * Copyright © 2014-2016 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. * + * * + ******************************************************************************/ + +#define _issue_curl(curl_handle,label,url) bitcoind_RPC(curl_handle,label,url,0,0,0) + +#define INSTANTDEX_MINVOL 75 +#define INSTANTDEX_MINVOLPERC ((double)INSTANTDEX_MINVOL / 100.) +#define INSTANTDEX_PRICESLIPPAGE 0.001 +#define FINISH_HEIGHT 7 + +#define INSTANTDEX_TRIGGERDEADLINE 120 +#define JUMPTRADE_SECONDS 100 +#define INSTANTDEX_ACCT "4383817337783094122" +#define INSTANTDEX_FEE ((long)(2.5 * SATOSHIDEN)) + +#include "../iguana777.h" +#include "InstantDEX_quote.h" + +#define INSTANTDEX_LOCALAPI "allorderbooks", "orderbook", "lottostats", "LSUM", "makebasket", "disable", "enable", "peggyrates", "tradesequence", "placebid", "placeask", "orderstatus", "openorders", "cancelorder", "tradehistory", "balance", "allexchanges", + + +typedef char *(*json_handler)(int32_t localaccess,int32_t valid,char *sender,cJSON **objs,int32_t numobjs,char *origargstr); + +queue_t InstantDEXQ,TelepathyQ,Pending_offersQ; +cJSON *InstantDEX_lottostats(); + +//#include "NXT_tx.h" +#include "trades.h" +#include "quotes.h" +#include "subatomic.h" + +#include "orderbooks.h" +#include "exchangeparse.h" +#include "exchange_trades.h" +#include "exchanges/poloniex.c" +#include "exchanges/bittrex.c" +#include "exchanges/btce.c" +#include "exchanges/bitfinex.c" +#include "exchanges/btc38.c" +#include "exchanges/huobi.c" +#include "exchanges/lakebtc.c" +#include "exchanges/quadriga.c" +#include "exchanges/okcoin.c" +#include "exchanges/coinbase.c" +#include "exchanges/bitstamp.c" + +// {"plugin":"InstantDEX","method":"orderbook","baseid":"8688289798928624137","rel":"USD","exchange":"active","allfields":1} + +// {"plugin":"InstantDEX","method":"orderbook","baseid":"17554243582654188572","rel":"12071612744977229797","exchange":"active","allfields":1} +// {"plugin":"InstantDEX","method":"orderbook","baseid":"6918149200730574743","rel":"XMR","exchange":"active","allfields":1} + +void idle() +{ + char *jsonstr,*str; cJSON *json; int32_t n = 0; uint32_t nonce; + /*printf("INSTANTDEX.readyflag.%d\n",INSTANTDEX.readyflag); + while ( INSTANTDEX.readyflag == 0 ) + sleep(1); + printf("INSTANTDEX.readyflag.%d\n",INSTANTDEX.readyflag);*/ + while ( 1 ) + { + if ( n == 0 ) + sleep(1); + n = 0; + if ( (jsonstr= queue_dequeue(&InstantDEXQ,1)) != 0 ) + { + printf("Dequeued InstantDEX.(%s)\n",jsonstr); + if ( (json= cJSON_Parse(jsonstr)) != 0 ) + { + //fprintf(stderr,"dequeued\n"); + if ( (str= busdata_sync(&nonce,jsonstr,"allnodes",0)) != 0 ) + { + //fprintf(stderr,"busdata.(%s)\n",str); + free(str); + } + free_json(json); + n++; + } else printf("error parsing (%s) from InstantDEXQ\n",jsonstr); + free_queueitem(jsonstr); + } + } +} + +uint32_t _get_NXTheight(uint32_t *firsttimep) +{ + static uint32_t last,lastheight,lastNXTtime; + cJSON *json; uint32_t height = 0; char cmd[256],*jsonstr; + if ( time(NULL) > last+10 ) + { + sprintf(cmd,"requestType=getState"); + if ( (jsonstr= issue_NXTPOST(cmd)) != 0 ) + { + //printf("(%s) -> (%s)\n",cmd,jsonstr); + if ( (json= cJSON_Parse(jsonstr)) != 0 ) + { + if ( firsttimep != 0 ) + lastNXTtime = *firsttimep = (uint32_t)get_cJSON_int(json,"time"); + height = (int32_t)get_cJSON_int(json,"numberOfBlocks"); + if ( height > 0 ) + height--; + lastheight = height; + free_json(json); + } + free(jsonstr); + } + last = (uint32_t)time(NULL); + } + else + { + height = lastheight; + if ( firsttimep != 0 ) + *firsttimep = lastNXTtime; + } + return(height); +} + +void idle2() +{ + static double lastmilli; + uint32_t NXTblock; + //while ( INSTANTDEX.readyflag == 0 ) + // sleep(1); + while ( 1 ) + { + if ( milliseconds() < (lastmilli + 5000) ) + sleep(1); + NXTblock = _get_NXTheight(0); + if ( 1 && NXTblock != prices777_NXTBLOCK ) + { + prices777_NXTBLOCK = NXTblock; + InstantDEX_update(IGUANA_NXTADDR,IGUANA_NXTACCTSECRET);//,SUPERNET.); + //fprintf(stderr,"done idle NXT\n"); + } + lastmilli = milliseconds(); + } +} + +cJSON *InstantDEX_lottostats() +{ + char cmdstr[1024],NXTaddr[64],buf[1024],*jsonstr; struct destbuf receiverstr; + cJSON *json,*array,*txobj; int32_t i,n,totaltickets = 0; uint64_t amount,senderbits; uint32_t timestamp = 0; + if ( timestamp == 0 ) + timestamp = 38785003; + sprintf(cmdstr,"requestType=getBlockchainTransactions&account=%s×tamp=%u&type=0&subtype=0",INSTANTDEX_ACCT,timestamp); + //printf("cmd.(%s)\n",cmdstr); + if ( (jsonstr= issue_NXTPOST(cmdstr)) != 0 ) + { + // printf("jsonstr.(%s)\n",jsonstr); + // mm string.({"requestProcessingTime":33,"transactions":[{"fullHash":"2a2aab3b84dadf092cf4cedcd58a8b5a436968e836338e361c45651bce0ef97e","confirmations":203,"signatureHash":"52a4a43d9055fe4861b3d13fbd03a42fecb8c9ad4ac06a54da7806a8acd9c5d1","transaction":"711527527619439146","amountNQT":"1100000000","transactionIndex":2,"ecBlockHeight":360943,"block":"6797727125503999830","recipientRS":"NXT-74VC-NKPE-RYCA-5LMPT","type":0,"feeNQT":"100000000","recipient":"4383817337783094122","version":1,"sender":"423766016895692955","timestamp":38929220,"ecBlockId":"10121077683890606382","height":360949,"subtype":0,"senderPublicKey":"4e5bbad625df3d536fa90b1e6a28c3f5a56e1fcbe34132391c8d3fd7f671cb19","deadline":1440,"blockTimestamp":38929430,"senderRS":"NXT-8E6V-YBWH-5VMR-26ESD","signature":"4318f36d9cf68ef0a8f58303beb0ed836b670914065a868053da5fe8b096bc0c268e682c0274e1614fc26f81be4564ca517d922deccf169eafa249a88de58036"}]}) + if ( (json= cJSON_Parse(jsonstr)) != 0 ) + { + if ( (array= cJSON_GetObjectItem(json,"transactions")) != 0 && is_cJSON_Array(array) != 0 && (n= cJSON_GetArraySize(array)) > 0 ) + { + for (i=0; i= 2*INSTANTDEX_FEE ) + totaltickets += 2; + } + } + } + } + free_json(json); + } + free(jsonstr); + } + sprintf(buf,"{\"result\":\"lottostats\",\"totaltickets\":\"%d\"}",totaltickets); + return(cJSON_Parse(buf)); +} + +void set_best_amounts(int64_t *baseamountp,int64_t *relamountp,double price,double volume) +{ + double checkprice,checkvol,distA,distB,metric,bestmetric = (1. / SMALLVAL); + uint64_t baseamount,relamount,bestbaseamount = 0,bestrelamount = 0; + int32_t i,j; + baseamount = volume * SATOSHIDEN; + relamount = ((price * volume) * SATOSHIDEN); + //*baseamountp = baseamount, *relamountp = relamount; + //return; + for (i=-1; i<=1; i++) + for (j=-1; j<=1; j++) + { + checkprice = prices777_price_volume(&checkvol,baseamount+i,relamount+j); + distA = (checkprice - price); + distA *= distA; + distB = (checkvol - volume); + distB *= distB; + metric = sqrt(distA + distB); + if ( metric < bestmetric ) + { + bestmetric = metric; + bestbaseamount = baseamount + i; + bestrelamount = relamount + j; + //printf("i.%d j.%d metric. %f\n",i,j,metric); + } + } + *baseamountp = bestbaseamount; + *relamountp = bestrelamount; +} + +int32_t bidask_parse(int32_t localaccess,struct destbuf *exchangestr,struct destbuf *name,struct destbuf *base,struct destbuf *rel,struct destbuf *gui,struct InstantDEX_quote *iQ,cJSON *json) +{ + uint64_t basemult,relmult,baseamount,relamount; double price,volume; int32_t exchangeid,keysize,flag; char key[1024],buf[64],*methodstr; + memset(iQ,0,sizeof(*iQ)); + iQ->s.baseid = j64bits(json,"baseid"); iQ->s.relid = j64bits(json,"relid"); + iQ->s.baseamount = j64bits(json,"baseamount"), iQ->s.relamount = j64bits(json,"relamount"); + iQ->s.vol = jdouble(json,"volume"); iQ->s.price = jdouble(json,"price"); + copy_cJSON(exchangestr,jobj(json,"exchange")); + if ( exchangestr->buf[0] == 0 || find_exchange(&exchangeid,exchangestr->buf) == 0 ) + exchangeid = -1; + iQ->exchangeid = exchangeid; + copy_cJSON(base,jobj(json,"base")); + copy_cJSON(rel,jobj(json,"rel")); + copy_cJSON(name,jobj(json,"name")); + methodstr = jstr(json,"method"); + if ( methodstr != 0 && (strcmp(methodstr,"placeask") == 0 || strcmp(methodstr,"ask") == 0) ) + iQ->s.isask = 1; + if ( iQ->s.vol < 0. ) + { + iQ->s.vol = -iQ->s.vol; + iQ->s.isask ^= 1; + } + if ( methodstr != 0 && strcmp(exchangestr->buf,"wallet") == 0 && (iQ->s.baseid == NXT_ASSETID || strcmp(base->buf,"NXT") == 0) ) + { + flag = 1; + if ( strcmp(methodstr,"placeask") == 0 ) + methodstr = "placebid"; + else if ( strcmp(methodstr,"placebid") == 0 ) + methodstr = "placeask"; + else if ( strcmp(methodstr,"ask") == 0 ) + methodstr = "bid"; + else if ( strcmp(methodstr,"bid") == 0 ) + methodstr = "ask"; + else flag = 0; + if ( flag != 0 ) + { + iQ->s.baseid = iQ->s.relid, iQ->s.relid = NXT_ASSETID; + strcpy(base->buf,rel->buf), strcpy(rel->buf,"NXT"); + baseamount = iQ->s.baseamount; + iQ->s.baseamount = iQ->s.relamount, iQ->s.relamount = baseamount; + name->buf[0] = 0; + if ( iQ->s.vol > SMALLVAL && iQ->s.price > SMALLVAL ) + { + iQ->s.vol *= iQ->s.price; + iQ->s.price = 1. / iQ->s.price; + } + iQ->s.isask ^= 1; + printf("INVERT\n"); + } + } + if ( (iQ->s.timestamp= juint(json,"timestamp")) == 0 ) + iQ->s.timestamp = (uint32_t)time(NULL); + copy_cJSON(gui,jobj(json,"gui")), strncpy(iQ->gui,gui->buf,sizeof(iQ->gui)-1); + iQ->s.automatch = juint(json,"automatch"); + iQ->s.minperc = juint(json,"minperc"); + if ( (iQ->s.duration= juint(json,"duration")) == 0 || iQ->s.duration > ORDERBOOK_EXPIRATION ) + iQ->s.duration = ORDERBOOK_EXPIRATION; + InstantDEX_name(key,&keysize,exchangestr->buf,name->buf,base->buf,&iQ->s.baseid,rel->buf,&iQ->s.relid); + //printf(">>>>>>>>>>>> BASE.(%s) REL.(%s)\n",base->buf,rel->buf); + iQ->s.basebits = stringbits(base->buf); + iQ->s.relbits = stringbits(rel->buf); + safecopy(iQ->base,base->buf,sizeof(iQ->base)); + safecopy(iQ->rel,rel->buf,sizeof(iQ->rel)); + iQ->s.offerNXT = j64bits(json,"offerNXT"); + iQ->s.quoteid = j64bits(json,"quoteid"); + if ( strcmp(exchangestr->buf,"jumblr") == 0 || strcmp(exchangestr->buf,"pangea") == 0 ) + { + if ( strcmp(exchangestr->buf,"pangea") == 0 ) + { + if ( juint(json,"rakemillis") != 0 ) + iQ->s.minperc = juint(json,"rakemillis"); + if ( j64bits(json,"bigblind") != 0 ) + { + iQ->s.baseamount = j64bits(json,"bigblind"); + iQ->s.vol = ((double)iQ->s.baseamount / SATOSHIDEN); + } + if ( j64bits(json,"ante") != 0 ) + iQ->s.relamount = j64bits(json,"ante"); + iQ->s.minbuyin = juint(json,"minbuyin"); + iQ->s.maxbuyin = juint(json,"maxbuyin"); + /*if ( (iQ->s.maxrake= j64bits(json,"maxrake")) != 0 ) + { + if ( strcmp(base->buf,"BTC") == 0 && iQ->s.maxrake < SATOSHIDEN/10 ) + iQ->s.maxrake = SATOSHIDEN/10; + else if ( iQ->s.maxrake < 10*SATOSHIDEN ) + iQ->s.maxrake = 10*SATOSHIDEN; + }*/ + } + if ( iQ->s.price == 0. ) + iQ->s.price = 1.; + if ( iQ->s.vol == 0. ) + iQ->s.vol = 1.; + if ( iQ->s.baseamount == 0 ) + iQ->s.baseamount = iQ->s.vol * SATOSHIDEN; + if ( localaccess != 0 && strcmp(exchangestr->buf,"jumblr") == 0 ) + { +#ifdef later + struct coin777 *coin; int32_t maxamount; + if ( (coin= coin777_find(base->buf,0)) != 0 ) + { + if ( coin->jvin == 0 && coin->jvinaddr[0] == 0 ) + { + coin->jvin = -1; + printf("initial state for jumblr.%s detected\n",coin->name); + sleep(5); + } + if ( coin->jvin < 0 ) + { + printf("no %s unspents available for jumblr/pangea jvin.%d %.8f\n",coin->name,coin->jvin,dstr(coin->junspent)); + return(-1); + } + maxamount = coin->junspent - coin->mgw.txfee*2 - (coin->junspent>>10); + if ( iQ->s.baseamount > maxamount ) + iQ->s.baseamount = maxamount; + else if ( iQ->s.baseamount < coin->mgw.txfee ) + { + printf("jumblr/pangea amount %.8f less than txfee %.8f\n",dstr(iQ->s.baseamount),dstr(coin->mgw.txfee)); + return(-1); + } + } + else + { + printf("%s not initialized for jumblr\n",base->buf); + return(-1); + } +#endif + } + } + else + { + if ( iQ->s.baseamount == 0 || iQ->s.relamount == 0 ) + { + if ( iQ->s.price <= SMALLVAL || iQ->s.vol <= SMALLVAL ) + return(-1); + set_best_amounts(&iQ->s.baseamount,&iQ->s.relamount,iQ->s.price,iQ->s.vol); + } + } + if ( iQ->s.quoteid == 0 ) + iQ->s.quoteid = calc_quoteid(iQ); + else if ( iQ->s.quoteid != calc_quoteid(iQ) ) + { + printf("bidask_parse quoteid.%llu != calc.%llu\n",(long long)iQ->s.quoteid,(long long)calc_quoteid(iQ)); + return(-1); + } + if ( iQ->s.price > SMALLVAL && iQ->s.vol > SMALLVAL && iQ->s.baseid != 0 && iQ->s.relid != 0 ) + { + buf[0] = 0, _set_assetname(&basemult,buf,0,iQ->s.baseid); + printf("baseid.%llu -> %s mult.%llu\n",(long long)iQ->s.baseid,buf,(long long)basemult); + buf[0] = 0, _set_assetname(&relmult,buf,0,iQ->s.relid); + printf("relid.%llu -> %s mult.%llu\n",(long long)iQ->s.relid,buf,(long long)relmult); + //basemult = get_assetmult(iQ->baseid), relmult = get_assetmult(iQ->relid); + baseamount = (iQ->s.baseamount + basemult/2) / basemult, baseamount *= basemult; + relamount = (iQ->s.relamount + relmult/2) / relmult, relamount *= relmult; + if ( iQ->s.price != 0. && iQ->s.vol != 0 ) + { + price = prices777_price_volume(&volume,baseamount,relamount); + if ( fabs(iQ->s.price - price)/price > 0.001 ) + { + printf("cant create accurate price ref.(%f %f) -> (%f %f)\n",iQ->s.price,iQ->s.vol,price,volume); + return(-1); + } + } + } + return(0); +} + +char *InstantDEX(char *jsonstr,char *remoteaddr,int32_t localaccess) +{ + char *prices777_allorderbooks(); + char *InstantDEX_tradehistory(cJSON *json,int32_t firsti,int32_t endi); + char *InstantDEX_cancelorder(cJSON *json,char *activenxt,char *secret,uint64_t sequenceid,uint64_t quoteid); + struct destbuf exchangestr,method,gui,name,base,rel; double balance; + char *retstr = 0,key[512],retbuf[1024],*activenxt,*secret,*coinstr; struct InstantDEX_quote iQ; struct exchange_info *exchange; + cJSON *json; uint64_t assetbits,sequenceid; uint32_t maxdepth; int32_t invert=0,keysize,allfields; struct prices777 *prices = 0; + //printf("INSTANTDEX.(%s)\n",jsonstr); + //if ( INSTANTDEX.readyflag == 0 ) + // return(0); + if ( jsonstr != 0 && (json= cJSON_Parse(jsonstr)) != 0 ) + { + // test: asset/asset, asset/external, external/external, autofill and automatch + // peggy integration + if ( bidask_parse(localaccess,&exchangestr,&name,&base,&rel,&gui,&iQ,json) < 0 && (strcmp(exchangestr.buf,"jumblr") == 0 || strcmp(exchangestr.buf,"pangea") == 0) ) + { + //return(clonestr("{\"error\":\"invalid parameters\"}")); + } + if ( iQ.s.offerNXT == 0 ) + iQ.s.offerNXT = IGUANA_MY64BITS; +printf("isask.%d base.(%s) rel.(%s)\n",iQ.s.isask,base.buf,rel.buf); + copy_cJSON(&method,jobj(json,"method")); + if ( (sequenceid= j64bits(json,"orderid")) == 0 ) + sequenceid = j64bits(json,"sequenceid"); + allfields = juint(json,"allfields"); + if ( (maxdepth= juint(json,"maxdepth")) <= 0 ) + maxdepth = MAX_DEPTH; + if ( exchangestr.buf[0] == 0 ) + { + if ( iQ.s.baseid != 0 && iQ.s.relid != 0 ) + strcpy(exchangestr.buf,"nxtae"); + else strcpy(exchangestr.buf,"basket"); + } + assetbits = InstantDEX_name(key,&keysize,exchangestr.buf,name.buf,base.buf,&iQ.s.baseid,rel.buf,&iQ.s.relid); + //printf("2nd isask.%d base.(%s) rel.(%s)\n",iQ.s.isask,base.buf,rel.buf); + exchange = exchange_find(exchangestr.buf); + secret = jstr(json,"secret"), activenxt = jstr(json,"activenxt"); + if ( secret == 0 ) + { + secret = IGUANA_NXTACCTSECRET; + activenxt = IGUANA_NXTADDR; + } + if ( strcmp(method.buf,"exit") == 0 ) + { + printf("getchar and then exit\n"); + getchar(); + exit(0); + } + if ( strcmp(method.buf,"orderstatus") == 0 ) + retstr = InstantDEX_orderstatus(json,sequenceid,iQ.s.quoteid); + else if ( strcmp(method.buf,"cancelorder") == 0 ) + retstr = InstantDEX_cancelorder(json,jstr(json,"activenxt"),jstr(json,"secret"),sequenceid,iQ.s.quoteid); + else if ( strcmp(method.buf,"openorders") == 0 ) + retstr = InstantDEX_openorders(json,IGUANA_NXTADDR,juint(json,"allorders")); + else if ( strcmp(method.buf,"tradehistory") == 0 ) + retstr = InstantDEX_tradehistory(json,juint(json,"firsti"),juint(json,"endi")); + else if ( strcmp(method.buf,"withdraw") == 0 ) + retstr = InstantDEX_withdraw(json); + else if ( strcmp(method.buf,"balance") == 0 ) + { + if ( exchange != 0 && exchange->issue.trade != 0 ) + { + if ( exchange->issue.balances != 0 ) + { + if ( exchange->balancejson != 0 ) + free_json(exchange->balancejson), exchange->balancejson = 0; + exchange->lastbalancetime = (uint32_t)time(NULL); + if ( (exchange->balancejson= (*exchange->issue.balances)(&exchange->cHandle,exchange)) != 0 ) + { + if ( (coinstr= jstr(json,"base")) != 0 ) + retstr = (*exchange->issue.parsebalance)(exchange,&balance,coinstr); + else retstr = jprint(exchange->balancejson,0); + } else retstr = clonestr("{\"error\":\"balances null return\"}"); + } else retstr = clonestr("{\"error\":\"no balances function\"}"); + } else retstr = clonestr("{\"error\":\"cant find exchange trade or balances function\"}"); + printf("%s ptr.%p trade.%p\n",exchangestr.buf,exchange,exchange!=0?exchange->issue.trade:0); + } + else if ( strcmp(method.buf,"allorderbooks") == 0 ) + retstr = prices777_allorderbooks(); + else if ( strcmp(method.buf,"allexchanges") == 0 ) + retstr = jprint(exchanges_json(),1); + else if ( strcmp(method.buf,"lottostats") == 0 ) + retstr = jprint(InstantDEX_lottostats(),1); + /* else if ( strcmp(method.buf,"tradesequence") == 0 ) + { + //printf("call tradesequence.(%s)\n",jsonstr); + int32_t dotrade,numtrades; struct prices777_order trades[256]; struct pending_trade *pend; + dotrade = juint(json,"dotrade"); + retstr = InstantDEX_tradesequence(0,0,0,&numtrades,trades,(int32_t)(sizeof(trades)/sizeof(*trades)),dotrade,activenxt,secret,json); + if ( dotrade != 0 ) + { + pend = calloc(1,sizeof(*pend)); + pend->dir = iQ.s.isask == 0 ? 1 : -1, pend->price = iQ.s.price, pend->volume = iQ.s.vol, pend->orderid = iQ.s.quoteid; + pend->tradesjson = json; + pend->type = 'S'; + pend->timestamp = (uint32_t)time(NULL); + //InstantDEX_history(0,pend,0); + queue_enqueue("PendingQ",&Pending_offersQ.pingpong[0],&pend->DL,0); + } + }*/ + else if ( strcmp(method.buf,"makebasket") == 0 ) + { + if ( (prices= prices777_makebasket(0,json,1,"basket",0,0)) != 0 ) + retstr = clonestr("{\"result\":\"basket made\"}"); + else retstr = clonestr("{\"error\":\"couldnt make basket\"}"); + } + else if ( strcmp(method.buf,"peggyrates") == 0 ) + { + //if ( SUPERNET.peggy != 0 ) + // retstr = peggyrates(juint(json,"timestamp"),jstr(json,"name")); + //else retstr = clonestr("{\"error\":\"peggy disabled\"}"); + } + else if ( strcmp(method.buf,"LSUM") == 0 ) + { + sprintf(retbuf,"{\"result\":\"%s\",\"amount\":%d}",(rand() & 1) ? "BUY" : "SELL",(rand() % 100) * 100000); + retstr = clonestr(retbuf); + } + else if ( strcmp(method.buf,"placebid") == 0 || strcmp(method.buf,"placeask") == 0 ) + return(InstantDEX_placebidask(0,sequenceid,exchangestr.buf,name.buf,base.buf,rel.buf,&iQ,jstr(json,"extra"),secret,activenxt,json)); + else if ( strcmp(exchangestr.buf,"active") == 0 && strcmp(method.buf,"orderbook") == 0 ) + retstr = prices777_activebooks(name.buf,base.buf,rel.buf,iQ.s.baseid,iQ.s.relid,maxdepth,allfields,strcmp(exchangestr.buf,"active") == 0 || juint(json,"tradeable")); + else if ( (prices= prices777_find(&invert,iQ.s.baseid,iQ.s.relid,exchangestr.buf)) == 0 ) + { + if ( (prices= prices777_poll(exchangestr.buf,name.buf,base.buf,iQ.s.baseid,rel.buf,iQ.s.relid)) != 0 ) + { + if ( prices777_equiv(prices->baseid) == prices777_equiv(iQ.s.baseid) && prices777_equiv(prices->relid) == prices777_equiv(iQ.s.relid) ) + invert = 0; + else if ( prices777_equiv(prices->baseid) == prices777_equiv(iQ.s.relid) && prices777_equiv(prices->relid) == prices777_equiv(iQ.s.baseid) ) + invert = 1; + else invert = 0, printf("baserel not matching (%s %s) %llu %llu vs (%s %s) %llu %llu\n",prices->base,prices->rel,(long long)prices->baseid,(long long)prices->relid,base.buf,rel.buf,(long long)iQ.s.baseid,(long long)iQ.s.relid); + } + } + if ( retstr == 0 && prices != 0 ) + { + if ( strcmp(method.buf,"disablequotes") == 0 ) + { + if ( prices != 0 ) + { + if ( strcmp(prices->exchange,"unconf") == 0 ) + return(clonestr("{\"error\":\"cannot disable unconf\"}")); + prices->disabled = 1; + return(clonestr("{\"result\":\"success\"}")); + } + else return(clonestr("{\"error\":\"no prices to disable\"}")); + } + else if ( strcmp(method.buf,"enablequotes") == 0 ) + { + if ( prices != 0 ) + { + prices->disabled = 0; + return(clonestr("{\"result\":\"success\"}")); + } + else return(clonestr("{\"error\":\"no prices to enable\"}")); + } + else if ( strcmp(method.buf,"orderbook") == 0 ) + { + if ( maxdepth < MAX_DEPTH ) + return(prices777_orderbook_jsonstr(invert,IGUANA_MY64BITS,prices,&prices->O,maxdepth,allfields)); + else if ( (retstr= prices->orderbook_jsonstrs[invert][allfields]) == 0 ) + { + retstr = prices777_orderbook_jsonstr(invert,IGUANA_MY64BITS,prices,&prices->O,MAX_DEPTH,allfields); + portable_mutex_lock(&prices->mutex); + if ( prices->orderbook_jsonstrs[invert][allfields] != 0 ) + free(prices->orderbook_jsonstrs[invert][allfields]); + prices->orderbook_jsonstrs[invert][allfields] = retstr; + portable_mutex_unlock(&prices->mutex); + if ( retstr == 0 ) + retstr = clonestr("{}"); + } + if ( retstr != 0 ) + retstr = clonestr(retstr); + } + //else if ( strcmp(method.buf,"tradebot") == 0 ) + // retstr = InstantDEX_tradebot(prices,json,&iQ,invert); + } + //if ( Debuglevel > 2 ) + printf("(%s) %p exchange.(%s) base.(%s) %llu rel.(%s) %llu | name.(%s) %llu\n",retstr!=0?retstr:"",prices,exchangestr.buf,base.buf,(long long)iQ.s.baseid,rel.buf,(long long)iQ.s.relid,name.buf,(long long)assetbits); + } + return(retstr); +} + +char *bidask_func(int32_t localaccess,int32_t valid,char *sender,cJSON *json,char *origargstr) +{ + struct destbuf gui,exchangestr,name,base,rel,offerNXT; struct InstantDEX_quote iQ; + copy_cJSON(&offerNXT,jobj(json,"offerNXT")); +//printf("got (%s)\n",origargstr); + if ( strcmp(IGUANA_NXTADDR,offerNXT.buf) != 0 ) + { + if ( bidask_parse(localaccess,&exchangestr,&name,&base,&rel,&gui,&iQ,json) == 0 ) + return(InstantDEX_placebidask(sender,j64bits(json,"orderid"),exchangestr.buf,name.buf,base.buf,rel.buf,&iQ,jstr(json,"extra"),jstr(json,"secret"),jstr(json,"activenxt"),json)); + else printf("error with incoming bidask\n"); + } else fprintf(stderr,"got my bidask from network (%s)\n",origargstr); + return(clonestr("{\"result\":\"got loopback bidask\"}")); +} + diff --git a/iguana/InstantDEX/InstantDEX_quote.h b/iguana/InstantDEX/InstantDEX_quote.h new file mode 100755 index 000000000..5239dd941 --- /dev/null +++ b/iguana/InstantDEX/InstantDEX_quote.h @@ -0,0 +1,223 @@ +// +// sha256.h +// crypto777 +// +// Created by James on 4/9/15. +// Copyright (c) 2015 jl777. All rights reserved. +// + +#ifndef crypto777_InstantDEX_quote_h +#define crypto777_InstantDEX_quote_h + +#include +#include "../includes/uthash.h" + +#define NXT_ASSETID ('N' + ((uint64_t)'X'<<8) + ((uint64_t)'T'<<16)) // 5527630 +#define MAX_BUYNXT 10 +#define MIN_NQTFEE 100000000 +#define NXT_TOKEN_LEN 160 + +#define GENESISACCT "1739068987193023818" // NXT-MRCC-2YLS-8M54-3CMAJ +#define GENESISPUBKEYSTR "1259ec21d31a30898d7cd1609f80d9668b4778e3d97e941044b39f0c44d2e51b" +#define GENESISPRIVKEYSTR "1259ec21d31a30898d7cd1609f80d9668b4778e3d97e941044b39f0c44d2e51b" +#define GENESIS_SECRET "It was a bright cold day in April, and the clocks were striking thirteen." +#define GENESISBLOCK "2680262203532249785" + +#define NXT_GENESISTIME 1385294400 + +#define DEFAULT_NXT_DEADLINE 720 +#define issue_curl(cmdstr) bitcoind_RPC(0,"curl",cmdstr,0,0,0) +#define issue_NXT(cmdstr) bitcoind_RPC(0,"NXT",cmdstr,0,0,0) +#define issue_NXTPOST(cmdstr) bitcoind_RPC(0,"curl",NXTAPIURL,0,0,cmdstr) +#define fetch_URL(url) bitcoind_RPC(0,"fetch",url,0,0,0) + +#define INSTANTDEX_TRIGGERDEADLINE 120 +#define _issue_curl(curl_handle,label,url) bitcoind_RPC(curl_handle,label,url,0,0,0) + +#define ORDERBOOK_EXPIRATION 3600 +#define INSTANTDEX_MINVOL 75 +#define INSTANTDEX_MINVOLPERC ((double)INSTANTDEX_MINVOL / 100.) +#define INSTANTDEX_PRICESLIPPAGE 0.001 + +#define INSTANTDEX_TRIGGERDEADLINE 120 +#define JUMPTRADE_SECONDS 100 +#define INSTANTDEX_ACCT "4383817337783094122" +#define INSTANTDEX_FEE ((long)(2.5 * SATOSHIDEN)) + +#define INSTANTDEX_NAME "InstantDEX" +#define INSTANTDEX_NXTAENAME "nxtae" +#define INSTANTDEX_NXTAEUNCONF "unconf" +#define INSTANTDEX_BASKETNAME "basket" +#define INSTANTDEX_ACTIVENAME "active" +#define INSTANTDEX_EXCHANGEID 0 +#define INSTANTDEX_UNCONFID 1 +#define INSTANTDEX_NXTAEID 2 +#define MAX_EXCHANGES 64 +#define ORDERBOOK_EXPIRATION 3600 + + +#define NXT_ASSETID ('N' + ((uint64_t)'X'<<8) + ((uint64_t)'T'<<16)) // 5527630 +#define BTC_ASSETID ('B' + ((uint64_t)'T'<<8) + ((uint64_t)'C'<<16)) // 4412482 +#define LTC_ASSETID ('L' + ((uint64_t)'T'<<8) + ((uint64_t)'C'<<16)) +#define PPC_ASSETID ('P' + ((uint64_t)'P'<<8) + ((uint64_t)'C'<<16)) +#define NMC_ASSETID ('N' + ((uint64_t)'M'<<8) + ((uint64_t)'C'<<16)) +#define DASH_ASSETID ('D' + ((uint64_t)'A'<<8) + ((uint64_t)'S'<<16) + ((uint64_t)'H'<<24)) +#define BTCD_ASSETID ('B' + ((uint64_t)'T'<<8) + ((uint64_t)'C'<<16) + ((uint64_t)'D'<<24)) + +#define USD_ASSETID ('U' + ((uint64_t)'S'<<8) + ((uint64_t)'D'<<16)) +#define CNY_ASSETID ('C' + ((uint64_t)'N'<<8) + ((uint64_t)'Y'<<16)) +#define EUR_ASSETID ('E' + ((uint64_t)'U'<<8) + ((uint64_t)'R'<<16)) +#define RUR_ASSETID ('R' + ((uint64_t)'U'<<8) + ((uint64_t)'R'<<16)) + +struct InstantDEX_shared +{ + double price,vol; + uint64_t quoteid,offerNXT,basebits,relbits,baseid,relid; int64_t baseamount,relamount; + uint32_t timestamp; + uint16_t duration:14,wallet:1,a:1,isask:1,expired:1,closed:1,swap:1,responded:1,matched:1,feepaid:1,automatch:1,pending:1,minperc:7; + uint16_t minbuyin,maxbuyin; +}; + +struct InstantDEX_quote +{ + UT_hash_handle hh; + struct InstantDEX_shared s; // must be here + char exchangeid,gui[9],base[8],rel[8]; + char walletstr[]; +}; + +struct InstantDEX_quote *delete_iQ(uint64_t quoteid); +struct InstantDEX_quote *find_iQ(uint64_t quoteid); +struct InstantDEX_quote *create_iQ(struct InstantDEX_quote *iQ,char *walletstr); +uint64_t calc_quoteid(struct InstantDEX_quote *iQ); +cJSON *set_walletstr(cJSON *walletitem,char *walletstr,struct InstantDEX_quote *iQ); +cJSON *InstantDEX_specialorders(uint64_t *quoteidp,uint64_t nxt64bits,char *base,char *special,uint64_t baseamount,int32_t addrtype); +int32_t bidask_parse(int32_t localaccess,struct destbuf *exchangestr,struct destbuf *name,struct destbuf *base,struct destbuf *rel,struct destbuf *gui,struct InstantDEX_quote *iQ,cJSON *json); + +int32_t coin777_addrtype(uint8_t *p2shtypep,char *coinstr); + +struct prices777_order +{ + struct InstantDEX_shared s; cJSON *retitem; struct prices777 *source; struct pending_trade *pend; + uint64_t id; double wt,ratio; uint16_t slot_ba; +}; +struct prices777_basket +{ + struct prices777 *prices; double wt; + int32_t groupid,groupsize,aski,bidi; + char base[64],rel[64]; +}; +struct prices777_orderentry { struct prices777_order bid,ask; }; +#define MAX_GROUPS 8 +#define _MAX_DEPTH 100 + +struct prices777_basketinfo +{ + int32_t numbids,numasks; uint32_t timestamp; + struct prices777_orderentry book[MAX_GROUPS+1][_MAX_DEPTH]; +}; + +struct NXTtx { uint64_t txid; char fullhash[MAX_JSON_FIELD],utxbytes[MAX_JSON_FIELD],utxbytes2[MAX_JSON_FIELD],txbytes[MAX_JSON_FIELD],sighash[MAX_JSON_FIELD]; }; + +struct pending_trade +{ + struct queueitem DL; + struct NXTtx trigger; struct prices777_order order; + uint64_t triggertxid,txid,quoteid,orderid,my64bits; + struct prices777 *prices; void *cHandlep; struct exchange_info *exchange; void *bot; + char *triggertx,*txbytes,extra[128]; uint8_t nxtsecret[2048]; cJSON *tradesjson,*item; + double price,volume; uint32_t timestamp,finishtime,expiration; + int32_t dir,type,version,size,dotrade,queueflag,*curlingp; +}; + +struct prices777 +{ + char url[512],exchange[64],base[64],rel[64],lbase[64],lrel[64],key[512],oppokey[512],contract[64],origbase[64],origrel[64]; + uint64_t contractnum,ap_mult,baseid,relid,basemult,relmult; double lastupdate,decay,oppodecay,lastprice,lastbid,lastask; + uint32_t pollnxtblock,exchangeid,numquotes,updated,lasttimestamp,RTflag,disabled,dirty; int32_t keysize,oppokeysize; + portable_mutex_t mutex; + char *orderbook_jsonstrs[2][2]; + struct prices777_basketinfo O,O2; double groupwts[MAX_GROUPS + 1]; + uint8_t changed,type; uint8_t **dependents; int32_t numdependents,numgroups,basketsize; double commission; + void *tradebot; + struct prices777_basket basket[]; +}; + +struct exchange_info; +struct exchange_funcs +{ + char *exchange; + double (*update)(struct prices777 *prices,int32_t maxdepth); + int32_t (*supports)(char *base,char *rel); + uint64_t (*trade)(void **cHandlep,int32_t dotrade,char **retstrp,struct exchange_info *exchange,char *base,char *rel,int32_t dir,double price,double volume); + char *(*orderstatus)(void **cHandlep,struct exchange_info *exchange,cJSON *argjson,uint64_t quoteid); + char *(*cancelorder)(void **cHandlep,struct exchange_info *exchange,cJSON *argjson,uint64_t quoteid); + char *(*openorders)(void **cHandlep,struct exchange_info *exchange,cJSON *argjson); + char *(*tradehistory)(void **cHandlep,struct exchange_info *exchange,cJSON *argjson); + cJSON *(*balances)(void **cHandlep,struct exchange_info *exchange); + char *(*parsebalance)(struct exchange_info *exchange,double *balancep,char *coinstr); + char *(*withdraw)(void **cHandlep,struct exchange_info *exchange,cJSON *argjson); +}; +#define EXCHANGE_FUNCS(xchg,name) { name, prices777_ ## xchg, xchg ## _supports, xchg ## _trade, xchg ## _orderstatus, xchg ## _cancelorder, xchg ## _openorders, xchg ## _tradehistory, xchg ## _balances, xchg ## _parsebalance, xchg ## _withdraw } + +struct exchange_info +{ + struct exchange_funcs issue; + char name[16],apikey[MAX_JSON_FIELD],apisecret[MAX_JSON_FIELD],userid[MAX_JSON_FIELD]; + cJSON *balancejson; + uint32_t num,exchangeid,pollgap,refcount,polling,lastbalancetime; + uint64_t nxt64bits,lastnonce; double lastupdate,commission; + void *cHandle; + portable_mutex_t mutex; +}; + +#define calc_predisplinex(startweekind,clumpsize,weekind) (((weekind) - (startweekind))/(clumpsize)) +#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)) + +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); +struct exchange_info *get_exchange(int32_t exchangeid); +char *exchange_str(int32_t exchangeid); +struct exchange_info *exchange_find(char *exchangestr); +void prices777_exchangeloop(void *ptr); +uint64_t InstantDEX_name(char *key,int32_t *keysizep,char *exchange,char *name,char *base,uint64_t *baseidp,char *rel,uint64_t *relidp); +struct prices777 *prices777_find(int32_t *invertedp,uint64_t baseid,uint64_t relid,char *exchange); +struct exchange_info *find_exchange(int32_t *exchangeidp,char *exchangestr); +double prices777_InstantDEX(struct prices777 *prices,int32_t maxdepth); +uint64_t prices777_equiv(uint64_t assetid); +char *prices777_trade(int32_t *curlingp,void *bot,struct pending_trade **pendp,void **cHandlep,int32_t dotrade,cJSON *item,char *activenxt,char *secret,struct prices777 *prices,int32_t dir,double price,double volume,struct InstantDEX_quote *iQ,struct prices777_order *order,uint64_t orderid,char *extra); +double prices777_price_volume(double *volumep,uint64_t baseamount,uint64_t relamount); +struct prices777 *prices777_poll(char *exchangestr,char *name,char *base,uint64_t refbaseid,char *rel,uint64_t refrelid); +void set_best_amounts(int64_t *baseamountp,int64_t *relamountp,double price,double volume); +int32_t _set_assetname(uint64_t *multp,char *buf,char *jsonstr,uint64_t assetid); +char *InstantDEX_withdraw(cJSON *argjson); +cJSON *exchanges_json(); +char *InstantDEX_tradesequence(int32_t curlings[],void *bot,void *cHandles[],int32_t *nump,struct prices777_order *trades,int32_t maxtrades,int32_t dotrade,char *activenxt,char *secret,cJSON *json); +struct prices777 *prices777_makebasket(char *basketstr,cJSON *_basketjson,int32_t addbasket,char *typestr,struct prices777 *ptrs[],int32_t num); +char *prices777_activebooks(char *name,char *_base,char *_rel,uint64_t baseid,uint64_t relid,int32_t maxdepth,int32_t allflag,int32_t tradeable); +char *prices777_orderbook_jsonstr(int32_t invert,uint64_t nxt64bits,struct prices777 *prices,struct prices777_basketinfo *OB,int32_t maxdepth,int32_t allflag); +int32_t get_assetname(char *name,uint64_t assetid); +int32_t is_mscoin(char *assetidstr); +uint32_t _get_NXTheight(uint32_t *firsttimep); +char *fill_nxtae(int32_t dotrade,uint64_t *txidp,uint64_t nxt64bits,char *secret,int32_t dir,double price,double volume,uint64_t baseid,uint64_t relid); +uint64_t get_assetmult(uint64_t assetid); +int32_t InstantDEX_verify(uint64_t destNXTaddr,uint64_t sendasset,uint64_t sendqty,cJSON *txobj,uint64_t recvasset,uint64_t recvqty); +int32_t verify_NXTtx(cJSON *json,uint64_t refasset,uint64_t qty,uint64_t destNXTbits); +uint64_t assetmult(char *assetidstr); +int64_t get_asset_quantity(int64_t *unconfirmedp,char *NXTaddr,char *assetidstr); +uint64_t calc_asset_qty(uint64_t *availp,uint64_t *priceNQTp,char *NXTaddr,int32_t checkflag,uint64_t assetid,double price,double vol); + +cJSON *InstantDEX_orderbook(struct prices777 *prices); +char *hmac_sha512_str(char dest[(512>>3)*2 + 1],char *key,unsigned int key_size,char *message); +char *hmac_sha384_str(char *dest,char *key,int32_t key_size,char *message); +char *hmac_sha1_str(char *dest,char *key,int32_t key_size,char *message); +char *hmac_sha256_str(char *dest,char *key,int32_t key_size,char *message); + +extern uint32_t MAX_DEPTH; +extern char NXTAPIURL[],IGUANA_NXTACCTSECRET[],IGUANA_NXTADDR[]; +extern int32_t FIRST_EXTERNAL,IGUANA_disableNXT,Debuglevel,prices777_NXTBLOCK; +extern uint64_t IGUANA_MY64BITS; +#endif diff --git a/iguana/InstantDEX/exchange_trades.h b/iguana/InstantDEX/exchange_trades.h new file mode 100755 index 000000000..f1e750ec4 --- /dev/null +++ b/iguana/InstantDEX/exchange_trades.h @@ -0,0 +1,1407 @@ +/****************************************************************************** + * Copyright © 2014-2016 The SuperNET Developers. * + * * + * See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at * + * the top-level directory of this distribution for the individual copyright * + * holder information and the developer policies on copyright and licensing. * + * * + * Unless otherwise agreed in a custom licensing agreement, no part of the * + * SuperNET software, including this file may be copied, modified, propagated * + * or distributed except according to the terms contained in the LICENSE file * + * * + * Removal or modification of this copyright notice is prohibited. * + * * + ******************************************************************************/ + + +#ifndef xcode_exchanges_h +#define xcode_exchanges_h + +#define SHA512_DIGEST_SIZE (512 / 8) +void *curl_post(void **cHandlep,char *url,char *userpass,char *postfields,char *hdr0,char *hdr1,char *hdr2,char *hdr3); + +char *exchange_would_submit(char *postreq,char *hdr1,char *hdr2,char *hdr3, char *hdr4) +{ + char *data; cJSON *json; + json = cJSON_CreateObject(); + jaddstr(json,"post",postreq); + if ( hdr1[0] != 0 ) + jaddstr(json,"hdr1",hdr1); + if ( hdr2[0] != 0 ) + jaddstr(json,"hdr2",hdr2); + if ( hdr3[0] != 0 ) + jaddstr(json,"hdr3",hdr3); + if ( hdr4[0] != 0 ) + jaddstr(json,"hdr4",hdr4); + data = jprint(json,1); + json = 0; + return(data); +} + +uint64_t exchange_nonce(struct exchange_info *exchange) +{ + uint64_t nonce; + nonce = time(NULL); + if ( nonce < exchange->lastnonce ) + nonce = exchange->lastnonce + 1; + exchange->lastnonce = nonce; + return(nonce); +} + +int32_t flip_for_exchange(char *pairstr,char *fmt,char *refstr,int32_t dir,double *pricep,double *volumep,char *base,char *rel) +{ + if ( strcmp(rel,refstr) == 0 ) + sprintf(pairstr,fmt,rel,base); + else + { + if ( strcmp(base,refstr) == 0 ) + { + sprintf(pairstr,fmt,base,rel); + dir = -dir; + *volumep *= *pricep; + *pricep = (1. / *pricep); + } + else sprintf(pairstr,fmt,rel,base); + } + return(dir); +} + +int32_t flipstr_for_exchange(struct exchange_info *exchange,char *pairstr,char *fmt,int32_t dir,double *pricep,double *volumep,char *_base,char *_rel) +{ + int32_t polarity; char base[64],rel[64]; + strcpy(base,_base), strcpy(rel,_rel); + tolowercase(base), tolowercase(rel); + polarity = (*exchange->issue.supports)(base,rel); + if ( dir > 0 ) + sprintf(pairstr,fmt,base,rel); + else if ( dir < 0 ) + { + *volumep *= *pricep; + *pricep = (1. / *pricep); + sprintf(pairstr,fmt,rel,base); + } + return(dir); +} + +int32_t cny_flip(char *market,char *coinname,char *base,char *rel,int32_t dir,double *pricep,double *volumep) +{ + char pairstr[512],lbase[16],lrel[16],*refstr=0; + strcpy(lbase,base), tolowercase(lbase), strcpy(lrel,rel), tolowercase(lrel); + if ( strcmp(lbase,"cny") == 0 || strcmp(lrel,"cny") == 0 ) + { + dir = flip_for_exchange(pairstr,"%s_%s","cny",dir,pricep,volumep,lbase,lrel); + refstr = "cny"; + } + else if ( strcmp(lbase,"btc") == 0 || strcmp(lrel,"btc") == 0 ) + { + dir = flip_for_exchange(pairstr,"%s_%s","btc",dir,pricep,volumep,lbase,lrel); + refstr = "btc"; + } + if ( market != 0 && coinname != 0 && refstr != 0 ) + { + strcpy(market,refstr); + if ( strcmp(lbase,"refstr") != 0 ) + strcpy(coinname,lbase); + else strcpy(coinname,lrel); + touppercase(coinname); + } + return(dir); +} + +char *exchange_extractorderid(int32_t historyflag,char *status,uint64_t quoteid,char *quoteid_field) +{ + cJSON *array,*item,*json; int32_t i,n; uint64_t txid; + if ( status != 0 ) + { + if ( (array= cJSON_Parse(status)) != 0 && is_cJSON_Array(array) != 0 && (n= cJSON_GetArraySize(array)) > 0 ) + { + for (i=0; iapikey,(long long)nonce); + else + { + dir = flip_for_exchange(pairstr,"%s-%s","BTC",dir,&price,&volume,base,rel); + sprintf(urlbuf,"https://bittrex.com/api/v1.1/market/%slimit?apikey=%s&nonce=%llu&market=%s&rate=%.8f&quantity=%.8f",dir>0?"buy":"sell",exchange->apikey,(long long)nonce,pairstr,price,volume); + } + if ( (sig = hmac_sha512_str(dest,exchange->apisecret,(int32_t)strlen(exchange->apisecret),urlbuf)) != 0 ) + sprintf(hdr,"apisign:%s",sig); + else hdr[0] = 0; + //printf("cmdbuf.(%s) h1.(%s)\n",urlbuf,hdr); + if ( (data= curl_post(&cHandle,urlbuf,0,0,hdr,0,0,0)) != 0 ) + { + //printf("cmd.(%s) [%s]\n",urlbuf,data); + if ( (json= cJSON_Parse(data)) != 0 ) + { + // { "success" : true, "message" : "", "result" : { "uuid" : "e606d53c-8d70-11e3-94b5-425861b86ab6" } } + if ( dir == 0 ) + { + //printf("got balances.(%s)\n",data); + } + else if ( is_cJSON_True(cJSON_GetObjectItem(json,"success")) != 0 && (resultobj= cJSON_GetObjectItem(json,"result")) != 0 ) + { + copy_cJSON(&uuidstr,cJSON_GetObjectItem(resultobj,"uuid")); + for (i=j=0; uuidstr.buf[i]!=0; i++) + if ( uuidstr.buf[i] != '-' ) + uuidstr.buf[j++] = uuidstr.buf[i]; + uuidstr.buf[j] = 0; + n = (int32_t)strlen(uuidstr.buf); + printf("-> uuidstr.(%s).%d\n",uuidstr.buf,n); + decode_hex(databuf,n/2,uuidstr.buf); + if ( n >= 16 ) + for (i=0; i<8; i++) + databuf[i] ^= databuf[8 + i]; + memcpy(&txid,databuf,8); + printf("-> %llx\n",(long long)txid); + } + free_json(json); + } + } + if ( retstrp != 0 ) + *retstrp = data; + else if ( data != 0 ) + free(data); + return(txid); +} + +uint64_t poloniex_trade(char **retstrp,struct exchange_info *exchange,char *base,char *rel,int32_t dir,double price,double volume) +{ + static CURL *cHandle; + char *sig,*data,*extra,*typestr,cmdbuf[8192],hdr1[4096],hdr2[4096],pairstr[512],dest[SHA512_DIGEST_SIZE*2 + 1]; cJSON *json; uint64_t nonce,txid = 0; + nonce = exchange_nonce(exchange); + if ( (extra= *retstrp) != 0 ) + *retstrp = 0; + if ( dir == 0 ) + sprintf(cmdbuf,"command=returnCompleteBalances&nonce=%llu",(long long)nonce); + else + { + dir = flip_for_exchange(pairstr,"%s_%s","BTC",dir,&price,&volume,base,rel); + if ( extra != 0 && strcmp(extra,"margin") == 0 ) + typestr = (dir > 0) ? "marginBuy":"marginSell"; + else typestr = (dir > 0) ? "buy":"sell"; + sprintf(cmdbuf,"command=%s&nonce=%ld¤cyPair=%s&rate=%.8f&amount=%.8f",typestr,(long)time(NULL),pairstr,price,volume); + } + if ( (sig= hmac_sha512_str(dest,exchange->apisecret,(int32_t)strlen(exchange->apisecret),cmdbuf)) != 0 ) + sprintf(hdr2,"Sign:%s",sig); + else hdr2[0] = 0; + sprintf(hdr1,"Key:%s",exchange->apikey); + //printf("cmdbuf.(%s) h1.(%s) h2.(%s)\n",cmdbuf,hdr2,hdr1); + if ( (data= curl_post(&cHandle,"https://poloniex.com/tradingApi",0,cmdbuf,hdr2,hdr1,0,0)) != 0 ) + { + //printf("cmd.(%s) [%s]\n",cmdbuf,data); + if ( (json= cJSON_Parse(data)) != 0 ) + { + txid = (get_API_nxt64bits(cJSON_GetObjectItem(json,"orderNumber")) << 32) | get_API_nxt64bits(cJSON_GetObjectItem(json,"tradeID")); + free_json(json); + } + } + if ( retstrp != 0 ) + *retstrp = data; + else if ( data != 0 ) + free(data); + return(txid); +} + +/*uint64_t bter_trade(char **retstrp,struct exchange_info *exchange,char *base,char *rel,int32_t dir,double price,double volume) +{ + static CURL *cHandle; + char *sig,*data,buf[512],cmdbuf[8192],hdr1[1024],hdr2[1024],pairstr[512],dest[SHA512_DIGEST_SIZE*2 + 1]; + cJSON *json; uint64_t txid = 0; + dir = cny_flip(0,0,base,rel,dir,&price,&volume); + sprintf(cmdbuf,"type=%s&nonce=%ld&pair=%s&rate=%.8f&amount=%.8f",dir>0?"BUY":"SELL",(long)time(NULL),pairstr,price,volume); + if ( (sig = hmac_sha512_str(dest,exchange->apisecret,(int32_t)strlen(exchange->apisecret),cmdbuf)) != 0 ) + sprintf(hdr2,"SIGN:%s",sig); + else hdr2[0] = 0; + sprintf(hdr1,"KEY:%s",exchange->apikey); + printf("cmdbuf.(%s) h1.(%s) h2.(%s)\n",cmdbuf,hdr2,hdr1); + if ( (data= curl_post(&cHandle,"https://bter.com/api/1/private/placeorder",0,cmdbuf,hdr2,hdr1,0)) != 0 ) + { + printf("cmd.(%s) [%s]\n",cmdbuf,data); + //{ "result":"true", "order_id":"123456", "msg":"Success" } + if ( (json= cJSON_Parse(data)) != 0 ) + { + copy_cJSON(buf,cJSON_GetObjectItem(json,"result")); + if ( strcmp(buf,"true") != 0 ) + { + copy_cJSON(buf,cJSON_GetObjectItem(json,"msg")); + if ( strcmp(buf,"Success") != 0 ) + txid = get_API_nxt64bits(cJSON_GetObjectItem(json,"order_id")); + } + free_json(json); + } + } + if ( retstrp != 0 ) + *retstrp = data; + else if ( data != 0 ) + free(data); + return(txid); +}*/ + +uint64_t btce_trade(char **retstrp,struct exchange_info *exchange,char *_base,char *_rel,int32_t dir,double price,double volume) +{ + /*Authentication is made by sending the following HTTP headers: + Key — API key. API key examples: 46G9R9D6-WJ77XOIP-XH9HH5VQ-A3XN3YOZ-8T1R8I8T + API keys are created in the Profile in the API keys section. + Sign — Signature. POST-parameters (?nonce=1¶m0=val0), signed with a Secret key using HMAC-SHA512*/ + static CURL *cHandle; + + char *sig,*data,base[64],rel[64],payload[8192],hdr1[4096],hdr2[4096],pairstr[512],dest[SHA512_DIGEST_SIZE*2 + 1]; cJSON *json,*resultobj; uint64_t nonce,txid = 0; + sprintf(hdr1,"Key:%s",exchange->apikey); + nonce = exchange_nonce(exchange); + if ( dir == 0 ) + sprintf(payload,"method=getInfo&nonce=%llu",(long long)nonce); + else + { + if ( (dir= flipstr_for_exchange(exchange,pairstr,"%s_%s",dir,&price,&volume,base,rel)) == 0 ) + { + printf("cant find baserel (%s/%s)\n",base,rel); + return(0); + } + sprintf(payload,"method=Trade&nonce=%ld&pair=%s&type=%s&rate=%.3f&amount=%.6f",(long)time(NULL),pairstr,dir>0?"buy":"sell",price,volume); + } + if ( (sig= hmac_sha512_str(dest,exchange->apisecret,(int32_t)strlen(exchange->apisecret),payload)) != 0 ) + sprintf(hdr2,"Sign:%s",sig); + else hdr2[0] = 0; + //printf("cmdbuf.(%s) h1.(%s) h2.(%s)\n",payload,hdr2,hdr1); + if ( (data= curl_post(&cHandle,"https://btc-e.com/tapi",0,payload,hdr2,hdr1,0,0)) != 0 ) + { + //printf("cmd.(%s) [%s]\n",payload,data); + //{ "success":1, "return":{ "received":0.1, "remains":0, "order_id":0, "funds":{ "usd":325, "btc":2.498, } } } + if ( (json= cJSON_Parse(data)) != 0 ) + { + if ( juint(json,"success") > 0 && (resultobj= cJSON_GetObjectItem(json,"return")) != 0 ) + { + if ( (txid= get_API_nxt64bits(cJSON_GetObjectItem(resultobj,"order_id"))) == 0 ) + { + if ( get_API_nxt64bits(cJSON_GetObjectItem(resultobj,"remains")) == 0 ) + txid = _crc32(0,payload,strlen(payload)); + } + } + free_json(json); + } + } + if ( retstrp != 0 ) + *retstrp = data; + else if ( data != 0 ) + free(data); + return(txid); +} + +uint64_t kraken_trade(char **retstrp,struct exchange_info *exchange,char *_base,char *_rel,int32_t dir,double price,double volume) +{ + //API-Key = API key + //API-Sign = Message signature using HMAC-SHA512 of (URI path + SHA256(nonce + POST data)) and base64 decoded secret API key + + static CURL *cHandle; + char *sig,*data,url[512],base[64],rel[64],buf[8192],postbuf[1024],payload[8192],sha256[65],hdr1[4096],hdr2[4096],encode64[4096],decode64[4096],dest[SHA512_DIGEST_SIZE*2 + 1]; + cJSON *json,*resultobj; uint8_t hash[32]; uint64_t nonce,txid = 0; int32_t n; + if ( _base != 0 && _rel != 0 ) + { + strcpy(base,_base), strcpy(rel,_rel); + touppercase(base), touppercase(rel); + if ( strcmp(base,"BTC") == 0 ) + strcpy(base,"XBT"); + if ( strcmp(rel,"BTC") == 0 ) + strcpy(rel,"XBT"); + if ( strcmp(base,"DOGE") == 0 ) + strcpy(base,"XDG"); + if ( strcmp(rel,"DOGE") == 0 ) + strcpy(rel,"XDG"); + } + sprintf(hdr1,"API-Key:%s",exchange->apikey); + n = nn_base64_decode((void *)exchange->apisecret,strlen(exchange->apisecret),(void *)decode64,sizeof(decode64)); + nonce = exchange_nonce(exchange); + if ( dir == 0 ) + { + sprintf(postbuf,"nonce=%llu",(long long)nonce); + sprintf(url,"https://api.kraken.com/0/private/Balance"); + } + else + { + /* + if ( (dir= flipstr_for_exchange(exchange,pairstr,"%s_%s",dir,&price,&volume,base,rel) == 0 ) + { + printf("cant find baserel (%s/%s)\n",base,rel); + return(0); + } + //dir = flip_for_exchange(pairstr,"%s_%s","BTC",dir,&price,&volume,base,rel); + sprintf(payload,"method=Trade&nonce=%ld&pair=%s&type=%s&rate=%.6f&amount=%.6f",(long)time(NULL),pairstr,dir>0?"buy":"sell",price,volume);*/ + } + sprintf(buf,"%s",postbuf); + calc_sha256(sha256,hash,(uint8_t *)buf,(int32_t)strlen(buf)); + sprintf(payload,"%s%s",url,sha256); + //memset(payload,0,sizeof(payload)); + //sprintf(payload,"%s",url); + //memcpy(payload+strlen(payload),hash,sizeof(hash)); + if ( (sig= hmac_sha512_str(dest,decode64,n,payload)) != 0 ) + { + n = nn_base64_encode((void *)sig,n,(void *)encode64,sizeof(encode64)); + sprintf(hdr2,"API-Sign:%s",encode64); + } + else hdr2[0] = 0; + //printf("cmdbuf.(%s) h1.(%s) h2.(%s)\n",postbuf,hdr2,hdr1); + if ( (data= curl_post(&cHandle,url,0,postbuf,hdr1,hdr2,0,0)) != 0 ) + { + //printf("cmd.(%s) [%s]\n",payload,data); + //{ "success":1, "return":{ "received":0.1, "remains":0, "order_id":0, "funds":{ "usd":325, "btc":2.498, } } } + if ( (json= cJSON_Parse(data)) != 0 ) + { + if ( juint(json,"success") > 0 && (resultobj= cJSON_GetObjectItem(json,"return")) != 0 ) + { + if ( (txid= get_API_nxt64bits(cJSON_GetObjectItem(resultobj,"order_id"))) == 0 ) + { + if ( get_API_nxt64bits(cJSON_GetObjectItem(resultobj,"remains")) == 0 ) + txid = _crc32(0,payload,strlen(payload)); + } + } + free_json(json); + } + } + if ( retstrp != 0 ) + *retstrp = data; + else if ( data != 0 ) + free(data); + return(txid); +} + +uint64_t bitfinex_trade(char **retstrp,struct exchange_info *exchange,char *_base,char *_rel,int32_t dir,double price,double volume) +{ + /* POST https://api.bitfinex.com/v1/order/new + void *curl_post(CURL **cHandlep,char *url,char *userpass,char *postfields,char *hdr0,char *hdr1,char *hdr2) + With a payload of + + { + "request": "/v1/order/new", + "nonce": "1234", + "option1": ... + } + The nonce provided must be strictly increasing. + + To authenticate a request, use the following: + + payload = parameters-dictionary -> JSON encode -> base64 + signature = HMAC-SHA384(payload, api-secret) as hexadecimal + send (api-key, payload, signature) + These are encoded as HTTP headers named: + + X-BFX-APIKEY + X-BFX-PAYLOAD + X-BFX-SIGNATURE + */ + /* POST /order/new + Request + Key Type Description + symbol [string] The name of the symbol (see `/symbols`). + amount [decimal] Order size: how much to buy or sell. + price [price] Price to buy or sell at. Must be positive. Use random number for market orders. + exchange [string] "bitfinex" + side [string] Either "buy" or "sell". + type [string] Either "market" / "limit" / "stop" / "trailing-stop" / "fill-or-kill" / "exchange market" / "exchange limit" / "exchange stop" / "exchange trailing-stop" / "exchange fill-or-kill". (type starting by "exchange " are exchange orders, others are margin trading orders) + is_hidden [bool] true if the order should be hidden. Default is false.*/ + + static CURL *cHandle; + char *sig,*data,hdr3[4096],url[512],*extra,*typestr,*method,req[4096],base[16],rel[16],payload[4096],hdr1[4096],hdr2[4096],pairstr[512],dest[1024 + 1]; + cJSON *json; uint64_t nonce,txid = 0; + if ( (extra= *retstrp) != 0 ) + *retstrp = 0; + memset(req,0,sizeof(req)); + nonce = exchange_nonce(exchange); + if ( dir == 0 ) + { + method = "balances"; + sprintf(req,"{\"request\":\"/v1/%s\",\"nonce\":\"%llu\"}",method,(long long)nonce); + } + else + { + if ( (dir= flipstr_for_exchange(exchange,pairstr,"%s%s",dir,&price,&volume,base,rel)) == 0 ) + { + printf("cant find baserel (%s/%s)\n",base,rel); + return(0); + } + method = "order/new"; + //Either "market" / "limit" / "stop" / "trailing-stop" / "fill-or-kill" / "exchange market" / "exchange limit" / "exchange stop" / "exchange trailing-stop" / "exchange fill-or-kill". (type starting by "exchange " are exchange orders, others are margin trading orders) + if ( (typestr= extra) == 0 ) + typestr = "exchange limit"; + sprintf(req,"{\"request\":\"/v1/%s\",\"nonce\":\"%llu\",\"exchange\":\"bitfinex\",\"side\":\"%s\",\"type\":\"%s\",\"price\":\"%.8f\",\"amount\":\"%.8f\",\"symbol\":\"%s\"}",method,(long long)nonce,dir>0?"buy":"sell",typestr,price,volume,pairstr); + } + nn_base64_encode((void *)req,strlen(req),payload,sizeof(payload)); + if ( (sig= hmac_sha384_str(dest,exchange->apisecret,(int32_t)strlen(exchange->apisecret),payload)) != 0 ) + { + sprintf(hdr1,"X-BFX-APIKEY:%s",exchange->apikey); + sprintf(hdr2,"X-BFX-PAYLOAD:%s",payload); + sprintf(hdr3,"X-BFX-SIGNATURE:%s",sig); + sprintf(url,"https://api.bitfinex.com/v1/%s",method); + //printf("bitfinex req.(%s) -> (%s) [%s %s %s]\n",req,payload,hdr1,hdr2,hdr3); + if ( (data= curl_post(&cHandle,url,0,req,hdr1,hdr2,hdr3,0)) != 0 ) + { + //printf("[%s]\n",data); + if ( (json= cJSON_Parse(data)) != 0 ) + { + if ( (txid= j64bits(json,"order_id")) == 0 ) + { + if ( dir != 0 ) + printf("bitfinex: no txid error\n"); + } + free_json(json); + } + } + if ( retstrp != 0 ) + *retstrp = data; + else if ( data != 0 ) + free(data); + } + return(txid); +} + +uint64_t btc38_trade(char **retstrp,struct exchange_info *exchange,char *_base,char *_rel,int32_t dir,double price,double volume) +{ + /* $ Stamp = $ date-> getTimestamp (); + type, 1 for the purchase of Entry, 2 entry order to sell, can not be empty / the type of the order + + $ Mdt = "_ public here to write here write here to write user ID_ private _" $ stamp.; + $ Mdt = md5 ($ mdt); + + $ Data = array ("key" => "here to write public", "time" => $ stamp, "md5" => $ mdt, "type" => 1, "mk_type" => "cny", + "Price" => "0.0001", "amount" => "100", "coinname" => "XRP"); + // $ Data_string = json_encode ($ data); + $ Ch = curl_init (); + curl_setopt ($ ch, CURLOPT_URL, 'http://www.btc38.com/trade/t_api/submitOrder.php'); + curl_setopt ($ ch, CURLOPT_POST, 1); + curl_setopt ($ ch, CURLOPT_POSTFIELDS, $ data); + curl_setopt ($ ch, CURLOPT_RETURNTRANSFER, 1); + curl_setopt ($ ch, CURLOPT_HEADER, 0); */ + + static CURL *cHandle; + char *data,*path,url[1024],cmdbuf[8192],buf[512],digest[33],market[16],base[64],rel[64],coinname[16],fmtstr[512],*pricefmt,*volfmt = "%.3f"; + cJSON *json,*resultobj; uint64_t nonce,txid = 0; + if ( _base != 0 && _rel != 0 ) + { + strcpy(base,_base), strcpy(rel,_rel); + touppercase(base), touppercase(rel); + if ( btc38_supports(base,rel) == 0 ) + { + *retstrp = clonestr("{\"error\":\"invalid contract pair\"}"); + return(0); + } + } + nonce = exchange_nonce(exchange); + sprintf(buf,"%s_%s_%s_%llu",exchange->apikey,exchange->userid,exchange->apisecret,(long long)nonce); + //printf("MD5.(%s)\n",buf); + calc_md5(digest,buf,(int32_t)strlen(buf)); + *retstrp = 0; + if ( dir == 0 ) + { + path = "getMyBalance.php"; + sprintf(cmdbuf,"key=%s&time=%llu&md5=%s",exchange->apikey,(long long)nonce,digest); + } + else + { + if ( (dir= cny_flip(market,coinname,base,rel,dir,&price,&volume)) == 0 ) + { + fprintf(stderr,"btc38_trade illegal base.(%s) or rel.(%s)\n",base,rel); + return(0); + } + if ( strcmp(market,"cny") == 0 ) + pricefmt = "%.5f"; + else pricefmt = "%.6f"; + sprintf(fmtstr,"key=%%s&time=%%llu&md5=%%s&type=%%s&mk_type=%%s&coinname=%%s&price=%s&amount=%s",pricefmt,volfmt); + sprintf(cmdbuf,fmtstr,exchange->apikey,(long long)nonce,digest,dir>0?"1":"2",market,coinname,price,volume); + path = "submitOrder.php"; + } + sprintf(url,"http://www.btc38.com/trade/t_api/%s",path); + if ( (data= curl_post(&cHandle,url,0,cmdbuf,0,0,0,0)) != 0 ) + { + //printf("submit cmd.(%s) [%s]\n",cmdbuf,data); + if ( (json= cJSON_Parse(data)) != 0 ) + { + if ( juint(json,"success") > 0 && (resultobj= cJSON_GetObjectItem(json,"return")) != 0 ) + { + if ( (txid= get_API_nxt64bits(cJSON_GetObjectItem(resultobj,"order_id"))) == 0 ) + { + if ( get_API_nxt64bits(cJSON_GetObjectItem(resultobj,"remains")) == 0 ) + txid = _crc32(0,cmdbuf,strlen(cmdbuf)); + } + } + free_json(json); + } + } else fprintf(stderr,"submit err cmd.(%s)\n",cmdbuf); + if ( retstrp != 0 && data != 0 ) + { + if ( (json= cJSON_Parse(data)) == 0 ) + { + json = cJSON_CreateObject(); + jaddstr(json,"result",data); + data = jprint(json,1); + } else free_json(json); + //printf("btc38 returning.(%s) in %p\n",data,data); + *retstrp = data; + } + else if ( data != 0 ) + free(data); + return(txid); +} + +uint64_t huobi_trade(char **retstrp,struct exchange_info *exchange,char *_base,char *_rel,int32_t dir,double price,double volume) +{ + static CURL *cHandle; + char *data,*extra,*method,pricestr[64],pairstr[64],base[64],rel[64],url[1024],cmdbuf[8192],buf[512],digest[33]; cJSON *json; uint64_t nonce,txid = 0; int32_t type; + nonce = exchange_nonce(exchange); + pricestr[0] = 0; + if ( (extra= *retstrp) != 0 ) + *retstrp = 0; + if ( dir == 0 ) + { + method = "get_account_info"; + sprintf(buf,"access_key=%s&created=%llu&method=%s&secret_key=%s",exchange->apikey,(long long)nonce,method,exchange->apisecret); + calc_md5(digest,buf,(int32_t)strlen(buf)); + sprintf(cmdbuf,"access_key=%s&created=%llu&method=%s&sign=%s",exchange->apikey,(long long)nonce,method,digest); + } + else + { + if ( (dir= flipstr_for_exchange(exchange,pairstr,"%s%s",dir,&price,&volume,base,rel)) == 0 ) + { + printf("cant find baserel (%s/%s)\n",base,rel); + return(0); + } + if ( extra != 0 && strcmp(extra,"market") == 0 ) + method = (dir > 0) ? "buy_market" : "sell_market"; + else method = (dir > 0) ? "buy" : "sell", sprintf(pricestr,"&price=%.2f",price); + if ( strcmp(pairstr,"btccny") == 0 ) + type = 1; + else if ( strcmp(pairstr,"ltccny") == 0 ) + type = 2; + else + { + printf("cant find baserel (%s/%s)\n",base,rel); + return(0); + } + sprintf(buf,"access_key=%s&amount=%.4f&coin_type=%d&created=%llu&method=%s%s&secret_key=%s",exchange->apikey,volume,type,(long long)nonce,method,pricestr,exchange->apisecret); + calc_md5(digest,buf,(int32_t)strlen(buf)); + sprintf(cmdbuf,"access_key=%s&amount=%.4f&coin_type=%d&created=%llu&method=%s%s&sign=%s",exchange->apikey,volume,type,(long long)nonce,method,pricestr,digest); + } + sprintf(url,"https://api.huobi.com/apiv3"); + if ( (data= curl_post(&cHandle,url,0,cmdbuf,"Content-Type:application/x-www-form-urlencoded",0,0,0)) != 0 ) + { + //printf("submit cmd.(%s) [%s]\n",cmdbuf,data); + if ( (json= cJSON_Parse(data)) != 0 ) + { + txid = j64bits(json,"order_id"); + free_json(json); + } + } else fprintf(stderr,"submit err cmd.(%s)\n",cmdbuf); + if ( retstrp != 0 ) + *retstrp = data; + else if ( data != 0 ) + free(data); + return(txid); +} + +uint64_t bityes_trade(char **retstrp,struct exchange_info *exchange,char *_base,char *_rel,int32_t dir,double price,double volume) +{ + static CURL *cHandle; + char *data,*extra,*method,pricestr[64],pairstr[64],base[64],rel[64],url[1024],cmdbuf[8192],buf[512],digest[33]; cJSON *json; uint64_t nonce,txid = 0; int32_t type; + nonce = exchange_nonce(exchange); + pricestr[0] = 0; + if ( (extra= *retstrp) != 0 ) + *retstrp = 0; + if ( dir == 0 ) + { + method = "get_account_info"; + sprintf(buf,"access_key=%s&created=%llu&method=%s&secret_key=%s",exchange->apikey,(long long)nonce,method,exchange->apisecret); + calc_md5(digest,buf,(int32_t)strlen(buf)); + sprintf(cmdbuf,"access_key=%s&created=%llu&method=%s&sign=%s",exchange->apikey,(long long)nonce,method,digest); + } + else + { + if ( (dir= flipstr_for_exchange(exchange,pairstr,"%s%s",dir,&price,&volume,base,rel)) == 0 ) + { + printf("cant find baserel (%s/%s)\n",base,rel); + return(0); + } + if ( extra != 0 && strcmp(extra,"market") == 0 ) + method = (dir > 0) ? "buy_market" : "sell_market"; + else method = (dir > 0) ? "buy" : "sell", sprintf(pricestr,"&price=%.2f",price); + if ( strcmp(pairstr,"btcusd") == 0 ) + type = 1; + else if ( strcmp(pairstr,"ltcusd") == 0 ) + type = 2; + else + { + printf("cant find baserel (%s/%s)\n",base,rel); + return(0); + } + /* access_key Required Access Key + amount Required Order Amount + coin_type Required Type 1 -BTC 2 -LTC + created Required Submit 10 digits timestamp + method Required Request method: buy_market + sign Required MD5 Signature + Encryption Instance sign=md5(access_key=xxxxxxxx-xxxxxxxx-xxxxxxxx-xxxxxxx&amount=10&coin_type=1&created=1386844119&method=buy_market&secret_key=xxxxxxxx-xxxxxxxx-xxxxxxxx-xxxxxxxx) + trade_password Optional No sign signature, payment password is required. + */ + sprintf(buf,"access_key=%s&amount=%.4f&coin_type=%d&created=%llu&method=%s%s&secret_key=%s",exchange->apikey,volume,type,(long long)nonce,method,pricestr,exchange->apisecret); + calc_md5(digest,buf,(int32_t)strlen(buf)); + sprintf(cmdbuf,"access_key=%s&amount=%.4f&coin_type=%d&created=%llu&method=%s%s&sign=%s",exchange->apikey,volume,type,(long long)nonce,method,pricestr,digest); + } + sprintf(url,"https://api.bityes.com/apiv2"); + if ( (data= curl_post(&cHandle,url,0,cmdbuf,"Content-Type:application/x-www-form-urlencoded",0,0,0)) != 0 ) + { + //printf("submit cmd.(%s) [%s]\n",cmdbuf,data); + if ( (json= cJSON_Parse(data)) != 0 ) + { + txid = j64bits(json,"order_id"); + free_json(json); + } + } else fprintf(stderr,"submit err cmd.(%s)\n",cmdbuf); + if ( retstrp != 0 ) + *retstrp = data; + else if ( data != 0 ) + free(data); + return(txid); +} + +uint64_t okcoin_trade(char **retstrp,struct exchange_info *exchange,char *_base,char *_rel,int32_t dir,double price,double volume) +{ + static CURL *cHandle; + char *data,*path,*typestr,*extra,pricestr[64],base[64],rel[64],pairstr[64],url[1024],cmdbuf[8192],buf[512],digest[33]; cJSON *json; uint64_t nonce,txid = 0; + nonce = exchange_nonce(exchange); + if ( (extra= *retstrp) != 0 ) + *retstrp = 0; + if ( dir == 0 ) + { + path = "userinfo.do"; + sprintf(buf,"api_key=%s&secret_key=%s",exchange->apikey,exchange->apisecret); + calc_md5(digest,buf,(int32_t)strlen(buf)); + touppercase(digest); + sprintf(cmdbuf,"api_key=%s&sign=%s",exchange->apikey,digest); + } + else + { + path = "trade.do"; + if ( (dir= flipstr_for_exchange(exchange,pairstr,"%s_%s",dir,&price,&volume,base,rel)) == 0 ) + { + printf("cant find baserel (%s/%s)\n",base,rel); + return(0); + } + if ( extra != 0 && strcmp(extra,"market") == 0 ) + typestr = (dir > 0) ? "buy_market" : "sell_market", sprintf(pricestr,"&price=%.2f",price); // docs say market orders put volume in price + else typestr = (dir > 0) ? "buy" : "sell", sprintf(pricestr,"&price=%.2f",price); + sprintf(buf,"amount=%.4f&api_key=%s%ssymbol=%s&type=%s&secret_key=%s",volume,exchange->apikey,pricestr,pairstr,typestr,exchange->apisecret); + calc_md5(digest,buf,(int32_t)strlen(buf)); + touppercase(digest); + sprintf(cmdbuf,"amount=%.4f&api_key=%s%s&symbol=%s&type=%s&sign=%s",volume,exchange->apikey,pricestr,pairstr,typestr,digest); + } + //printf("MD5.(%s)\n",buf); + sprintf(url,"https://www.okcoin.com/api/v1/%s",path); + if ( (data= curl_post(&cHandle,url,0,cmdbuf,0,0,0,0)) != 0 ) // "{\"Content-type\":\"application/x-www-form-urlencoded\"}","{\"User-Agent\":\"OKCoin Javascript API Client\"}" + { + //printf("submit cmd.(%s) [%s]\n",cmdbuf,data); + if ( (json= cJSON_Parse(data)) != 0 ) + { + txid = j64bits(json,"order_id"); + free_json(json); + } + } else fprintf(stderr,"submit err cmd.(%s)\n",cmdbuf); + if ( retstrp != 0 ) + *retstrp = data; + else if ( data != 0 ) + free(data); + return(txid); +} + +uint64_t lakebtc_trade(char **retstrp,struct exchange_info *exchange,char *_base,char *_rel,int32_t dir,double price,double volume) +{ + /* LakeBTC provides trading JSON-RPC API interface. HMAC (Hash-based Message Authentication Code) is employed as our authentication mechanisms. You need at 0.1 BTC in your account to retrieve your private key. + + Besides your private key, the client needs to prepare the following attributes + tonce (timestamp in microseconds, i.e., unixtime × 1000000, make sure your clock is correctly adjusted) + accesskey (your registered email address at LakeBTC) + requestmethod (post) + id (JSON-RPC request id, an integer) + method (JSON-RPC method) + params (JSON-RPC parameters) + Concatenate the above parameters with &, in that order. Parameters can be blank. For example, $signature = + tonce=1389067414466757&accesskey=foo@bar.com&requestmethod=post&id=123&method=ticker¶ms= + Create HMAC signature with your private key by using SHA1. $hash = + hash_hmac('sha1', $signature, $privatetkey) #php + Join your email and the hash signature with colon (:), and sign with Base64. $b64 = + base64_encode("foo@bar.com:") #php YXRjQHF3amlhbi5jb206ZmEzM2UzYzg5MDZjg5MzdiYzFiYw== + Set HTTP Header. Note tonce is the same as that in Step 2. + Json-Rpc-Tonce: 1389067414466757 #HTTP HEADER + Authorization: Basic YXRjQHF3amlhbi5jb206ZmEzM2UzYzg5MDZjg5MzdiYzFiYw== #HTTP HEADER + POST params data in JSON format to this url: + https://www.LakeBTC.com/api_v1 + API Methods + getAccountInfo + method=getAccountInfo + params= (i.e., blank)*/ + + static CURL *cHandle; + char *data,*method,buf64[4096],paramstr[128],jsonbuf[1024],base[64],rel[64],pairstr[64],params[1024],dest[512],url[1024],cmdbuf[8192],*sig,hdr1[4096],hdr2[4096],buf[4096]; cJSON *json; uint64_t tonce,nonce,txid = 0; + *retstrp = 0; + params[0] = 0; + nonce = exchange_nonce(exchange); + tonce = (nonce * 1000000 + ((uint64_t)milliseconds() % 1000) * 1000); + if ( dir == 0 ) + { + method = "getAccountInfo"; + sprintf(buf,"tonce=%llu&accesskey=%s&requestmethod=post&id=1&method=%s¶ms=",(long long)tonce,exchange->userid,method); + sprintf(jsonbuf,"{\"method\":\"%s\",\"params\":[\"%s\"],\"id\":1}",method,params); + } + else + { + if ( (dir= flipstr_for_exchange(exchange,pairstr,"%s_%s",dir,&price,&volume,base,rel)) == 0 ) + { + printf("cant find baserel (%s/%s)\n",base,rel); + return(0); + } + method = (dir > 0) ? "buyOrder" : "sellOrder"; + touppercase(rel); + sprintf(paramstr,"%.2f,%.4f,%s",price,volume,rel); + sprintf(buf,"tonce=%llu&accesskey=%s&requestmethod=post&id=1&method=%s¶ms=%s",(long long)tonce,exchange->userid,method,paramstr); + sprintf(jsonbuf,"{\"method\":\"%s\",\"params\":[\"%s\"],\"id\":1}",method,paramstr); + } + if ( (sig= hmac_sha1_str(dest,exchange->apisecret,(int32_t)strlen(exchange->apisecret),buf)) != 0 ) + { + sprintf(cmdbuf,"%s:%s",exchange->userid,sig); + nn_base64_encode((void *)cmdbuf,strlen(cmdbuf),buf64,sizeof(buf64)); + sprintf(url,"https://www.lakebtc.com/api_v1"); + sprintf(hdr1,"Authorization:Basic %s",buf64); + sprintf(hdr2,"Json-Rpc-Tonce: %llu",(long long)tonce); + if ( (data= curl_post(&cHandle,url,0,jsonbuf,hdr1,hdr2,0,0)) != 0 ) + { + //printf("submit cmd.(%s) [%s]\n",jsonbuf,data); + if ( (json= cJSON_Parse(data)) != 0 ) + { + txid = j64bits(json,"order_id"); + free_json(json); + } + } else fprintf(stderr,"submit err cmd.(%s)\n",cmdbuf); + if ( retstrp != 0 ) + *retstrp = data; + else if ( data != 0 ) + free(data); + } + return(txid); +} + +uint64_t quadriga_trade(char **retstrp,struct exchange_info *exchange,char *_base,char *_rel,int32_t dir,double price,double volume) +{ + /* You need to POST 3 fields as a JSON payload to the API in order to perform authentication. + + key – The API Key as shown above + nonce – an integer that must be unique for each API call (we recommend using a UNIX timestamp) + signature – HMAC_SHA256 encrypted string + Signature + + The signature has to be created using a concatenation of the nonce, your client id, the API key and using the MD5 hash of the API Secret as key. The pseudo-algorithm is shown below and you will find code examples in the Appendix. + + HMAC_SHA256 ( nonce + client + key, MD5 ( secret ) ) + Please note the HMAC_SHA256 and MD5 strings are both lower case. + + Using the API shown in Figure 2, the JSON payload will be: + + { + key: "JJHlXeDcFM", + nonce: 1391683499, + signature: "cdbf5cc64c70e1485fcf976cdf367960c2b28cfc28080973ce677cebb6db9681" + } + The signature being calculated using: + + HMAC_SHA256 ( 1391683499 + 3 + JJHlXeDcFM , MD5 ( *9q(;5]necq[otcCTfBeiI_Ug;ErCt]Ywjgg^G;t ) ) + HMAC_SHA256 ( 13916834993JJHlXeDcFM , 230664ae53cbe5a07c6c389910540729 ) + = cdbf5cc64c70e1485fcf976cdf367960c2b28cfc28080973ce677cebb6db9681 + + curl_setopt($ch, CURLOPT_POSTFIELDS, $data_string); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + curl_setopt($ch, CURLOPT_HTTPHEADER, array( + 'Content-Type: application/json; charset=utf-8', + 'Content-Length: ' . strlen($data_string)) + ); + + */ + static CURL *cHandle; + char *extra,*sig,*data,*path,pairstr[64],base[64],rel[64],hdr3[4096],url[512],md5secret[128],req[4096],payload[4096],hdr1[4096],hdr2[4096],dest[1024 + 1]; + cJSON *json; uint64_t nonce,txid = 0; + memset(payload,0,sizeof(payload)); + if ( (extra= *retstrp) != 0 ) + *retstrp = 0; + nonce = exchange_nonce(exchange); + sprintf(payload,"%llu%s%s",(long long)nonce,exchange->userid,exchange->apikey); + calc_md5(md5secret,exchange->apisecret,(int32_t)strlen(exchange->apisecret)); + if ( (sig= hmac_sha256_str(dest,md5secret,(int32_t)strlen(md5secret),payload)) != 0 ) + { + if ( dir == 0 ) + { + path = "balance"; + sprintf(req,"{\"key\":\"%s\",\"nonce\":%llu,\"signature\":\"%s\"}",exchange->apikey,(long long)nonce,sig); + } + else + { + if ( (dir= flipstr_for_exchange(exchange,pairstr,"%s_%s",dir,&price,&volume,base,rel)) == 0 ) + { + printf("cant find baserel (%s/%s)\n",base,rel); + return(0); + } + path = (dir > 0) ? "buy" : "sell"; + /*key - API key + signature - signature + nonce - nonce + amount - amount of major currency + price - price to buy at + book - optional, if not specified, will default to btc_cad*/ + sprintf(req,"{\"key\":\"%s\",\"amount\":%.6f,\"price\":%.3f,\"book\":\"%s_%s\",\"nonce\":%llu,\"signature\":\"%s\"}",exchange->apikey,volume,price,base,rel,(long long)nonce,sig); + + //dir = flip_for_exchange(pairstr,"%s_%s","BTC",dir,&price,&volume,base,rel); + } + sprintf(hdr1,"Content-Type:application/json"), sprintf(hdr2,"charset=utf-8"), sprintf(hdr3,"Content-Length:%ld",(long)strlen(req)); + printf("quadriga req.(%s) -> (%s) [%s %s sig.%s]\n",req,payload,md5secret,payload,sig); + sprintf(url,"https://api.quadrigacx.com/v2/%s",path); + if ( (data= curl_post(&cHandle,url,0,req,hdr1,hdr2,hdr3,0)) != 0 ) + { + printf("[%s]\n",data); + if ( (json= cJSON_Parse(data)) != 0 ) + { + free_json(json); + } + } + if ( retstrp != 0 ) + *retstrp = data; + else if ( data != 0 ) + free(data); + } + return(txid); +} + +uint64_t bitstamp_trade(char **retstrp,struct exchange_info *exchange,char *base,char *rel,int32_t dir,double price,double volume) +{ + /*signature is a HMAC-SHA256 encoded message containing: nonce, customer ID (can be found here) and API key. The HMAC-SHA256 code must be generated using a secret key that was generated with your API key. This code must be converted to it's hexadecimal representation (64 uppercase characters).Example (Python): + message = nonce + customer_id + api_key + signature = hmac.new(API_SECRET, msg=message, digestmod=hashlib.sha256).hexdigest().upper() + + key - API key + signature - signature + nonce - nonce + */ + + static CURL *cHandle; + char *sig,*data,*path,url[512],req[4096],payload[2048],dest[1024 + 1]; cJSON *json; uint64_t nonce,txid = 0; + memset(payload,0,sizeof(payload)); + nonce = exchange_nonce(exchange); + sprintf(payload,"%llu%s%s",(long long)nonce,exchange->userid,exchange->apikey); + if ( dir == 0 ) + path = "balance"; + else + { + //dir = flip_for_exchange(pairstr,"%s_%s","BTC",dir,&price,&volume,base,rel); + } + if ( (sig= hmac_sha256_str(dest,exchange->apisecret,(int32_t)strlen(exchange->apisecret),payload)) != 0 ) + { + touppercase(sig); + sprintf(req,"{\"key\":\"%s\",\"signature\":\"%s\",\"nonce\":%llu}",exchange->apikey,sig,(long long)nonce); + sprintf(url,"https://www.bitstamp.net/api/%s/",path); + printf("bitstamp.(%s) ->\n",req); + if ( (data= curl_post(&cHandle,url,0,req,0,0,0,0)) != 0 ) + { + printf("[%s]\n",data); + if ( (json= cJSON_Parse(data)) != 0 ) + { + free_json(json); + } + } + if ( retstrp != 0 ) + *retstrp = data; + else if ( data != 0 ) + free(data); + } + return(txid); +} + +uint64_t coinbase_trade(char **retstrp,struct exchange_info *exchange,char *base,char *rel,int32_t dir,double price,double volume) +{ + /*All REST requests must contain the following headers: + + CB-ACCESS-KEY The api key as a string. + CB-ACCESS-SIGN The base64-encoded signature (see Signing a Message). + CB-ACCESS-TIMESTAMP A timestamp for your request. + CB-ACCESS-PASSPHRASE The passphrase you specified when creating the API key. + All request bodies should have content type application/json and be valid JSON. + + Signing a Message + The CB-ACCESS-SIGN header is generated by creating a sha256 HMAC using the base64-decoded + secret key on the prehash string timestamp + method + requestPath + body (where + represents string concatenation) + and base64-encode the output. The timestamp value is the same as the CB-ACCESS-TIMESTAMP header. + + The body is the request body string or omitted if there is no request body (typically for GET requests). + + The method should be UPPER CASE + Remember to first base64-decode the alphanumeric secret string (resulting in 64 bytes) before using it as the key for HMAC. Also, base64-encode the digest output before sending in the header. + */ + static CURL *cHandle; + char *sig,*data,*path,sig64[1024],body[4096],method[64],prehash64[512],prehash[512],cmdbuf[8192],url[1024],decodedsecret[128],hdr1[4096],hdr2[4096],hdr3[4096],hdr4[4096],pairstr[512],dest[SHA512_DIGEST_SIZE*2 + 1]; cJSON *json; int32_t n; uint64_t nonce,txid = 0; + nonce = exchange_nonce(exchange); + cmdbuf[0] = 0; + body[0] = 0; + n = nn_base64_decode((void *)exchange->apisecret,strlen(exchange->apisecret),(void *)decodedsecret,sizeof(decodedsecret)); + if ( dir == 0 ) + path = "accounts", strcpy(method,"GET"); + else + { + path = "trade", strcpy(method,"POST"); + dir = flip_for_exchange(pairstr,"%s_%s","BTC",dir,&price,&volume,base,rel); + sprintf(cmdbuf,"method=Trade&nonce=%ld&pair=%s&type=%s&rate=%.6f&amount=%.6f",(long)time(NULL),pairstr,dir>0?"buy":"sell",price,volume); + } + touppercase(method); + sprintf(prehash,"%llu%s/%s%s",(long long)nonce,method,path,body); + nn_base64_encode((void *)prehash,strlen(prehash),prehash64,sizeof(prehash64)); + if ( (sig= hmac_sha256_str(dest,decodedsecret,n,prehash64)) != 0 ) + { + nn_base64_encode((void *)sig,strlen(sig),sig64,sizeof(sig64)); + } + //CB-ACCESS-KEY The api key as a string. + //CB-ACCESS-SIGN The base64-encoded signature (see Signing a Message). + //CB-ACCESS-TIMESTAMP A timestamp for your request. + //CB-ACCESS-PASSPHRASE The passphrase you specified when creating the API key. + sprintf(hdr1,"CB-ACCESS-KEY:%s",exchange->apikey); + sprintf(hdr2,"CB-ACCESS-SIGN:%s",sig64); + sprintf(hdr3,"CB-ACCESS-TIMESTAMP:%llu",(long long)nonce); + //sprintf(hdr4,"CB-ACCESS-PASSPHRASE:%s; content-type:application/json; charset=utf-8",exchange->userid); + sprintf(hdr4,"CB-ACCESS-PASSPHRASE:%s",exchange->userid); + sprintf(url,"https://api.exchange.coinbase.com/%s",path); + if ( (data= curl_post(&cHandle,url,0,cmdbuf,hdr1,hdr2,hdr3,hdr4)) != 0 ) + { + printf("cmd.(%s) prehash.(%s) n.%d [%s]\n",cmdbuf,prehash,n,data); + //{ "success":1, "return":{ "received":0.1, "remains":0, "order_id":0, "funds":{ "usd":325, "btc":2.498, } } } + if ( (json= cJSON_Parse(data)) != 0 ) + { + free_json(json); + } + } + if ( retstrp != 0 ) + *retstrp = data; + else if ( data != 0 ) + free(data); + return(txid); +} + +#ifdef enable_exmo +uint64_t exmo_trade(char **retstrp,struct exchange_info *exchange,char *base,char *rel,int32_t dir,double price,double volume) +{ + /* $req['nonce'] = $NONCE; + + // generate the POST data string + $post_data = http_build_query($req, '', '&'); + + $sign = hash_hmac('sha512', $post_data, $secret); + + // generate the extra headers + $headers = array( + 'Sign: ' . $sign, + 'Key: ' . $key, + ); + */ + static CURL *cHandle; + char *sig,*method,*data,url[512],cmdbuf[8192],hdr1[4096],hdr2[4096],pairstr[512],dest[SHA512_DIGEST_SIZE*2 + 1]; cJSON *json; uint64_t nonce,txid = 0; + nonce = exchange_nonce(exchange); + if ( dir == 0 ) + { + sprintf(cmdbuf,"nonce=%llu?method=get_info",(long long)nonce); + method = "get_info"; + } + else + { + method = "notyet"; + dir = flip_for_exchange(pairstr,"%s_%s","BTC",dir,&price,&volume,base,rel); + sprintf(cmdbuf,"method=Trade&nonce=%ld&pair=%s&type=%s&rate=%.6f&amount=%.6f",(long)time(NULL),pairstr,dir>0?"buy":"sell",price,volume); + //printf("cmdbuf.(%s) h1.(%s) h2.(%s)\n",cmdbuf,hdr2,hdr1); + } + if ( (sig= hmac_sha512_str(dest,exchange->apisecret,(int32_t)strlen(exchange->apisecret),cmdbuf)) != 0 ) + sprintf(hdr2,"Sign:%s",sig); + else hdr2[0] = 0; + sprintf(hdr1,"Key:%s",exchange->apikey); + sprintf(url,"https://api.exmo.com/api_v2/%s",method); + sprintf(cmdbuf,"{\"method\":\"get_info\"}"); + if ( (data= curl_post(&cHandle,url,0,cmdbuf,hdr1,hdr2,0,0)) != 0 ) + { + printf("cmd.(%s) [%s]\n",cmdbuf,data); + if ( (json= cJSON_Parse(data)) != 0 ) + { + free_json(json); + } + } + if ( retstrp != 0 ) + *retstrp = data; + else if ( data != 0 ) + free(data); + return(txid); +} +#endif +#endif + +uint64_t submit_triggered_nxtae(int32_t dotrade,char **retjsonstrp,int32_t is_MS,char *bidask,uint64_t nxt64bits,char *NXTACCTSECRET,uint64_t assetid,uint64_t qty,uint64_t NXTprice,char *triggerhash,char *comment,uint64_t otherNXT,uint32_t triggerheight) +{ + int32_t deadline = 1 + 20; uint64_t txid = 0; struct destbuf errstr; char cmd[4096],secret[8192],*jsonstr; cJSON *json; + if ( retjsonstrp != 0 ) + *retjsonstrp = 0; + if ( triggerheight != 0 ) + deadline = DEFAULT_NXT_DEADLINE; + escape_code(secret,NXTACCTSECRET); + if ( dotrade == 0 ) + strcpy(secret,""); + sprintf(cmd,"requestType=%s&secretPhrase=%s&feeNQT=%llu&deadline=%d",bidask,secret,(long long)MIN_NQTFEE,deadline); + sprintf(cmd+strlen(cmd),"&%s=%llu&%s=%llu",is_MS!=0?"units":"quantityQNT",(long long)qty,is_MS!=0?"currency":"asset",(long long)assetid); + if ( NXTprice != 0 ) + { + if ( is_MS != 0 ) + sprintf(cmd+strlen(cmd),"&rateNQT=%llu",(long long)NXTprice); + else sprintf(cmd+strlen(cmd),"&priceNQT=%llu",(long long)NXTprice); + } + if ( otherNXT != 0 ) + sprintf(cmd+strlen(cmd),"&recipient=%llu",(long long)otherNXT); + if ( triggerhash != 0 && triggerhash[0] != 0 ) + { + if ( triggerheight == 0 ) + sprintf(cmd+strlen(cmd),"&referencedTransactionFullHash=%s",triggerhash); + else sprintf(cmd+strlen(cmd),"&referencedTransactionFullHash=%s&phased=true&phasingFinishHeight=%u&phasingVotingModel=4&phasingQuorum=1&phasingLinkedFullHash=%s",triggerhash,triggerheight,triggerhash); + } + if ( comment != 0 && comment[0] != 0 ) + sprintf(cmd+strlen(cmd),"&message=%s",comment); + if ( dotrade == 0 ) + { + if ( retjsonstrp != 0 ) + { + json = cJSON_CreateObject(); + jaddstr(json,"submit",cmd); + *retjsonstrp = jprint(json,1); + } + return(0); + } + if ( (jsonstr= issue_NXTPOST(cmd)) != 0 ) + { + _stripwhite(jsonstr,' '); + if ( (json= cJSON_Parse(jsonstr)) != 0 ) + { + copy_cJSON(&errstr,cJSON_GetObjectItem(json,"error")); + if ( errstr.buf[0] == 0 ) + copy_cJSON(&errstr,cJSON_GetObjectItem(json,"errorDescription")); + if ( errstr.buf[0] != 0 ) + { + printf("submit_triggered_bidask.(%s) -> (%s)\n",cmd,jsonstr); + if ( retjsonstrp != 0 ) + *retjsonstrp = clonestr(errstr.buf); + } + else txid = get_API_nxt64bits(cJSON_GetObjectItem(json,"transaction")); + } + free(jsonstr); + } + return(txid); +} + +int32_t get_assettype(int32_t *numdecimalsp,char *assetidstr) +{ + cJSON *json; char name[64],*jsonstr; uint64_t assetid; int32_t ap_type = -1; //struct assethash *ap,A; + *numdecimalsp = -1; + name[0] = 0; + if ( is_native_crypto(name,calc_nxt64bits(assetidstr)) > 0 ) + { + //printf("found native crypto.(%s) name.(%s)\n",assetidstr,name); + ap_type = 0; + *numdecimalsp = 8; + return(0); + } + if ( (assetid= calc_nxt64bits(assetidstr)) == NXT_ASSETID ) + { + //printf("found NXT_ASSETID.(%s)\n",assetidstr); + ap_type = 0; + *numdecimalsp = 8; + return(0); + } + /*if ( (ap= find_asset(assetid)) != 0 ) + { + *numdecimalsp = ap->decimals; + return(ap->type); + }*/ + memset(name,0,sizeof(name)); + if ( (jsonstr= _issue_getAsset(assetidstr)) != 0 ) + { + if ( (json= cJSON_Parse(jsonstr)) != 0 ) + { + if ( get_cJSON_int(json,"errorCode") == 0 ) + { + //printf("assetstr.(%s)\n",jsonstr); + if ( extract_cJSON_str(name,16,json,"name") <= 0 ) + *numdecimalsp = -1; + else *numdecimalsp = (int32_t)get_cJSON_int(json,"decimals"); + ap_type = 2; + } //else printf("errorcode.%lld (%s)\n",(long long)get_cJSON_int(json,"errorCode"),jsonstr); + free_json(json); + } else printf("cant parse.(%s)\n",jsonstr); + free(jsonstr); + } else printf("couldnt getAsset.(%s)\n",assetidstr); + if ( ap_type < 0 ) + { + if ( (jsonstr= _issue_getCurrency(assetidstr)) != 0 ) + { + if ( (json= cJSON_Parse(jsonstr)) != 0 ) + { + if ( get_cJSON_int(json,"errorCode") == 0 ) + { + if ( extract_cJSON_str(name,16,json,"name") <= 0 ) + *numdecimalsp = -1; + else *numdecimalsp = (int32_t)get_cJSON_int(json,"decimals"); + ap_type = 5; + } + free_json(json); + } + free(jsonstr); + } + } + /*memset(&A,0,sizeof(A)); + A.assetid = assetid; + A.minvol = A.mult = calc_decimals_mult(*numdecimalsp); + A.decimals = *numdecimalsp; + A.type = ap_type; + strcpy(A.name,name); + create_asset(assetid,&A);*/ + return(ap_type); +} + +uint64_t assetmult(char *assetidstr) +{ + int32_t ap_type,decimals; uint64_t mult = 0; + ap_type = get_assettype(&decimals,assetidstr); + if ( decimals >= 0 && decimals <= 8 ) + mult = calc_decimals_mult(decimals); + return(mult); +} + +int32_t assetdecimals(char *assetidstr) +{ + int32_t ap_type,decimals = 0; + ap_type = get_assettype(&decimals,assetidstr); + if ( ap_type == 0 ) + return(8); + return(decimals); +} + +uint64_t min_asset_amount(uint64_t assetid) +{ + char assetidstr[64]; + if ( assetid == NXT_ASSETID ) + return(1); + expand_nxt64bits(assetidstr,assetid); + return(assetmult(assetidstr)); +} + +int32_t get_assetdecimals(uint64_t assetid) +{ + char assetidstr[64]; + if ( assetid == NXT_ASSETID ) + return(8); + expand_nxt64bits(assetidstr,assetid); + return(assetdecimals(assetidstr)); +} + +uint64_t get_assetmult(uint64_t assetid) +{ + char assetidstr[64]; + expand_nxt64bits(assetidstr,assetid); + return(assetmult(assetidstr)); +} + +double get_minvolume(uint64_t assetid) +{ + return(dstr(get_assetmult(assetid))); +} + +int64_t get_asset_quantity(int64_t *unconfirmedp,char *NXTaddr,char *assetidstr) +{ + char cmd[2*MAX_JSON_FIELD],*jsonstr; struct destbuf assetid; int32_t i,n,iter; cJSON *array,*item,*obj,*json; int64_t quantity,qty = 0; + uint64_t assetidbits = calc_nxt64bits(assetidstr); + quantity = *unconfirmedp = 0; + if ( assetidbits == NXT_ASSETID ) + { + sprintf(cmd,"requestType=getBalance&account=%s",NXTaddr); + if ( (jsonstr= issue_NXTPOST(cmd)) != 0 ) + { + //printf("(%s) -> (%s)\n",cmd,jsonstr); + if ( (json= cJSON_Parse(jsonstr)) != 0 ) + { + qty = get_API_nxt64bits(cJSON_GetObjectItem(json,"balanceNQT")); + *unconfirmedp = get_API_nxt64bits(cJSON_GetObjectItem(json,"unconfirmedBalanceNQT")); + printf("(%s)\n",jsonstr); + free_json(json); + } + free(jsonstr); + } + return(qty); + } + sprintf(cmd,"requestType=getAccount&account=%s",NXTaddr); + if ( (jsonstr= issue_NXTPOST(cmd)) != 0 ) + { + //printf("(%s) -> (%s)\n",cmd,jsonstr); + if ( (json= cJSON_Parse(jsonstr)) != 0 ) + { + for (iter=0; iter<2; iter++) + { + qty = 0; + array = cJSON_GetObjectItem(json,iter==0?"assetBalances":"unconfirmedAssetBalances"); + if ( is_cJSON_Array(array) != 0 ) + { + n = cJSON_GetArraySize(array); + for (i=0; i 0 ? "placeBidOrder" : "placeAskOrder",nxt64bits,secret,assetid,qty,priceNQT,0,0,0,0); + if ( errstr != 0 ) + sprintf(retbuf,"{\"error\":\"%s\"}",errstr), free(errstr); + else sprintf(retbuf,"{\"result\":\"success\",\"txid\":\"%llu\"}",(long long)txid); + if ( txidp != 0 ) + *txidp = txid; + return(clonestr(retbuf)); +} + +uint64_t submit_to_exchange(void **cHandlep,int32_t dotrade,int32_t exchangeid,char **jsonstrp,uint64_t assetid,uint64_t qty,uint64_t priceNQT,int32_t dir,uint64_t nxt64bits,char *NXTACCTSECRET,char *triggerhash,char *comment,uint64_t otherNXT,char *base,char *rel,double price,double volume,uint32_t triggerheight) +{ + uint64_t txid = 0; + char assetidstr[64],*cmd,*retstr = 0; + int32_t ap_type,decimals; + struct exchange_info *exchange; + *jsonstrp = 0; + expand_nxt64bits(assetidstr,assetid); + ap_type = get_assettype(&decimals,assetidstr); + if ( dir == 0 || priceNQT == 0 ) + cmd = (ap_type == 2 ? "transferAsset" : "transferCurrency"), priceNQT = 0; + else cmd = ((dir > 0) ? (ap_type == 2 ? "placeBidOrder" : "currencyBuy") : (ap_type == 2 ? "placeAskOrder" : "currencySell")), otherNXT = 0; + if ( exchangeid == INSTANTDEX_NXTAEID || exchangeid == INSTANTDEX_UNCONFID ) + { + if ( assetid != NXT_ASSETID && qty != 0 && (dir == 0 || priceNQT != 0) ) + { + printf("submit to exchange.%s (%s) dir.%d\n",Exchanges[exchangeid].name,comment,dir); + txid = submit_triggered_nxtae(dotrade,jsonstrp,ap_type == 5,cmd,nxt64bits,NXTACCTSECRET,assetid,qty,priceNQT,triggerhash,comment,otherNXT,triggerheight); + if ( *jsonstrp != 0 ) + txid = 0; + } + } + else if ( exchangeid < MAX_EXCHANGES && (exchange= &Exchanges[exchangeid]) != 0 && exchange->exchangeid == exchangeid && exchange->issue.trade != 0 ) + { + printf("submit_to_exchange.(%d) dir.%d price %f vol %f | inv %f %f (%s)\n",exchangeid,dir,price,volume,1./price,price*volume,comment); + if ( (txid= (*exchange->issue.trade)(cHandlep,dotrade,&retstr,exchange,base,rel,dir,price,volume)) == 0 ) + printf("error trading (%s/%s) dir.%d price %f vol %f ret.(%s)\n",base,rel,dir,price,volume,retstr!=0?retstr:""); + if ( jsonstrp != 0 ) + *jsonstrp = retstr; + } + return(txid); +} + +uint64_t InstantDEX_tradestub(void **cHandlep,int32_t dotrade,char **retstrp,struct exchange_info *exchange,char *base,char *rel,int32_t dir,double price,double volume) +{ + printf("this is just a InstantDEX_tradestub\n"); + return(0); +} + +uint64_t NXT_tradestub(void **cHandlep,int32_t dotrade,char **retstrp,struct exchange_info *exchange,char *base,char *rel,int32_t dir,double price,double volume) +{ + printf("this is just a NXT_tradestub\n"); + return(0); +} + +#endif diff --git a/iguana/InstantDEX/exchangeparse.h b/iguana/InstantDEX/exchangeparse.h new file mode 100755 index 000000000..1f1193867 --- /dev/null +++ b/iguana/InstantDEX/exchangeparse.h @@ -0,0 +1,1208 @@ +/****************************************************************************** + * Copyright © 2014-2016 The SuperNET Developers. * + * * + * See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at * + * the top-level directory of this distribution for the individual copyright * + * holder information and the developer policies on copyright and licensing. * + * * + * Unless otherwise agreed in a custom licensing agreement, no part of the * + * SuperNET software, including this file may be copied, modified, propagated * + * or distributed except according to the terms contained in the LICENSE file * + * * + * Removal or modification of this copyright notice is prohibited. * + * * + ******************************************************************************/ + + +#ifndef xcode_exchangeparse_h +#define xcode_exchangeparse_h + + +char *Supported_exchanges[] = { INSTANTDEX_NAME, INSTANTDEX_NXTAEUNCONF, INSTANTDEX_NXTAENAME, INSTANTDEX_BASKETNAME, "basketNXT", "basketUSD", "basketBTC", "basketCNY", INSTANTDEX_ACTIVENAME, "wallet", "jumblr", "pangea", "peggy", // peggy MUST be last of special exchanges + "bitfinex", "btc38", "bitstamp", "btce", "poloniex", "bittrex", "huobi", "coinbase", "okcoin", "lakebtc", "quadriga", + //"bityes", "kraken", "gatecoin", "quoine", "jubi", "hitbtc" // no trading for these exchanges yet +}; // "bter" <- orderbook is backwards and all entries are needed, later to support, "exmo" flakey apiservers + +void init_exchanges() +{ + int32_t i; + for (FIRST_EXTERNAL=0; FIRST_EXTERNAL %llu BTC -> %llu\n",(long long)stringbits("NXT"),(long long)stringbits("BTC")); + //INSTANTDEX.readyflag = 1; +} + +int32_t supported_exchange(char *exchangestr) +{ + int32_t i; + for (i=0; iname[0] == 0 ) + break; + cJSON_AddItemToObject(item,"name",cJSON_CreateString(exchange->name)); + memset(api,0,sizeof(api)); + n = 0; + if ( exchange->issue.trade != 0 ) + { + //printf("%s.(%s/%s/%s).%p\n",exchange->name,exchange->apikey,exchange->apisecret,exchange->userid,exchange); + if ( exchange->apikey[0] != 0 ) + api[n++] = 'K'; + if ( exchange->apisecret[0] != 0 ) + api[n++] = 'S'; + if ( exchange->userid[0] != 0 ) + api[n++] = 'U'; + api[n] = 0; + cJSON_AddItemToObject(item,"trade",cJSON_CreateString(api)); + } + cJSON_AddItemToArray(array,item); + } + return(array); +} + +int32_t is_exchange_nxt64bits(uint64_t nxt64bits) +{ + int32_t exchangeid; + struct exchange_info *exchange = 0; + for (exchangeid=0; exchangeidname,(long long)exchange->nxt64bits,(long long)nxt64bits); + if ( exchange->name[0] == 0 ) + return(0); + if ( exchange->nxt64bits == nxt64bits ) + return(1); + } + printf("no exchangebits match\n"); + return(0); +} + +struct exchange_info *get_exchange(int32_t exchangeid) { return(&Exchanges[exchangeid]); } +char *exchange_str(int32_t exchangeid) { return(Exchanges[exchangeid].name); } + +struct exchange_info *exchange_find(char *exchangestr) +{ + int32_t exchangeid; + struct exchange_info *exchange = 0; + for (exchangeid=0; exchangeidname) == 0 ) + return(exchange); + } + return(0); +} + +struct exchange_info *find_exchange(int32_t *exchangeidp,char *exchangestr) +{ + int32_t exchangeid; struct exchange_info *exchange = 0; + if ( supported_exchange(exchangestr) < 0 ) + { + if ( exchangeidp != 0 ) + *exchangeidp = -1; + return(0); + } + for (exchangeid=0; exchangeidname); + if ( exchange->name[0] == 0 ) + { + portable_mutex_init(&exchange->mutex); + strcpy(exchange->name,exchangestr); + exchange->exchangeid = exchangeid; + exchange->nxt64bits = stringbits(exchangestr); + printf("CREATE EXCHANGE.(%s) id.%d %llu\n",exchangestr,exchangeid,(long long)exchange->nxt64bits); + //if ( exchangestr[0] == 0 ) + // getchar(); + break; + } + if ( strcmp(exchangestr,exchange->name) == 0 ) + break; + } + if ( exchange != 0 && exchangeidp != 0 ) + *exchangeidp = exchange->exchangeid; + return(exchange); +} + +int32_t baserel_polarity(char *pairs[][2],int32_t n,char *_base,char *_rel) +{ + int32_t i; char base[16],rel[16]; + strcpy(base,_base), tolowercase(base); + strcpy(rel,_rel), tolowercase(rel); + for (i=0; i (%s)\n",url,jsonstr); + if ( (json= cJSON_Parse(jsonstr)) != 0 ) + { + hbla = prices777_json_orderbook(exchangestr,prices,maxdepth,json,field,"bids","asks",price,volume); + free_json(json); + } + free(jsonstr); + } + return(hbla); +} + +int32_t InstantDEX_supports(char *base,char *rel) { return(1); } + +int32_t NXT_supports(char *base,char *rel) +{ + if ( strcmp(rel,"NXT") == 0 ) + return(1); + else if ( strcmp(base,"NXT") == 0 ) + return(-1); + else return(0); +} + +#ifdef notnow +char *bittrex_parsebalance(struct exchange_info *exchange,double *balancep,char *coinstr) +{ + int32_t i,n; char *str,*itemstr = 0; cJSON *item,*array,*obj; double total,pending; + *balancep = 0.; + if ( exchange->balancejson != 0 && (array= jarray(&n,exchange->balancejson,"result")) != 0 ) + { + for (i=0; i 5 || strlen(rel) > 5 || strcmp(rel,"CNY") == 0 || strcmp(base,"CNY") == 0 || strcmp(rel,"USD") == 0 || strcmp(base,"USD") == 0 ) + return(0); + if ( strcmp(rel,"BTC") == 0 ) + return(1); + else if ( strcmp(base,"BTC") == 0 ) + return(-1); + else return(0); +} + +double prices777_bittrex(struct prices777 *prices,int32_t maxdepth) // "BTC-BTCD" +{ + cJSON *json,*obj; char *jsonstr,market[128]; double hbla = 0.; + if ( prices->url[0] == 0 ) + { + sprintf(market,"%s-%s",prices->rel,prices->base); + sprintf(prices->url,"https://bittrex.com/api/v1.1/public/getorderbook?market=%s&type=both&depth=%d",market,maxdepth); + } + jsonstr = issue_curl(prices->url); + if ( jsonstr != 0 ) + { + if ( (json = cJSON_Parse(jsonstr)) != 0 ) + { + if ( (obj= cJSON_GetObjectItem(json,"success")) != 0 && is_cJSON_True(obj) != 0 ) + hbla = prices777_json_orderbook("bittrex",prices,maxdepth,json,"result","buy","sell","Rate","Quantity"); + free_json(json); + } + free(jsonstr); + } + return(hbla); +} + +/*int32_t bter_supports(char *base,char *rel) +{ + return(0); + if ( strcmp(rel,"BTC") == 0 || strcmp(rel,"CNY") == 0 ) + return(1); + else if ( strcmp(base,"BTC") == 0 || strcmp(base,"CNY") == 0 ) + return(-1); + else return(0); + char *bterassets[][8] = { { "UNITY", "12071612744977229797" }, { "ATOMIC", "11694807213441909013" }, { "DICE", "18184274154437352348" }, { "MRKT", "134138275353332190" }, { "MGW", "10524562908394749924" } }; + uint64_t unityid = calc_nxt64bits("12071612744977229797"); + n = add_exchange_assetids(assetids,n,BTC_ASSETID,baseid,relid,exchangeid,bterassets,(int32_t)(sizeof(bterassets)/sizeof(*bterassets))); + if ( baseid == unityid || relid == unityid ) + { + n = add_exchange_assetid(assetids,n,unityid,BTC_ASSETID,exchangeid); + n = add_exchange_assetid(assetids,n,unityid,NXT_ASSETID,exchangeid); + n = add_exchange_assetid(assetids,n,unityid,CNY_ASSETID,exchangeid); + } + return(n); +} + +double prices777_bter(struct prices777 *prices,int32_t maxdepth) +{ + cJSON *json,*obj; char resultstr[MAX_JSON_FIELD],*jsonstr; double hbla = 0.; + if ( prices->url[0] == 0 ) + sprintf(prices->url,"http://data.bter.com/api/1/depth/%s_%s",prices->base,prices->rel); + jsonstr = issue_curl(prices->url); + //printf("(%s) -> (%s)\n",ep->url,jsonstr); + //{"result":"true","asks":[["0.00008035",100],["0.00008030",2030],["0.00008024",100],["0.00008018",643.41783554],["0.00008012",100] + if ( jsonstr != 0 ) + { + //printf("BTER.(%s)\n",jsonstr); + if ( (json = cJSON_Parse(jsonstr)) != 0 ) + { + if ( (obj= cJSON_GetObjectItem(json,"result")) != 0 ) + { + copy_cJSON(resultstr,obj); + if ( strcmp(resultstr,"true") == 0 ) + { + maxdepth = MAX_DEPTH;//1000; // since bter ask is wrong order, need to scan entire list + hbla = prices777_json_orderbook("bter",prices,maxdepth,json,0,"bids","asks",0,0); + } + } + free_json(json); + } + free(jsonstr); + } + return(hbla); +}*/ + +char *poloniex_parsebalance(struct exchange_info *exchange,double *balancep,char *coinstr) +{ + char *itemstr = 0; cJSON *item,*obj; double onorders,btcvalue; + *balancep = 0.; + if ( exchange->balancejson != 0 && (item= jobj(exchange->balancejson,coinstr)) != 0 ) + { + itemstr = jprint(item,0); + *balancep = jdouble(item,"available"); + onorders = jdouble(item,"onOrders"); + btcvalue = jdouble(item,"btcValue"); + if ( (obj= cJSON_Parse(itemstr)) != 0 ) + { + free(itemstr); + jaddstr(obj,"base",coinstr); + jaddnum(obj,"balance",*balancep); + jaddnum(obj,"onOrders",onorders); + jaddnum(obj,"btcvalue",btcvalue); + itemstr = jprint(obj,1); + } + } + if ( itemstr == 0 ) + return(clonestr("{\"error\":\"cant find coin balance\"}")); + return(itemstr); +} + +int32_t poloniex_supports(char *base,char *rel) +{ + if ( strlen(base) > 5 || strlen(rel) > 5 || strcmp(rel,"CNY") == 0 || strcmp(base,"CNY") == 0 || strcmp(rel,"USD") == 0 || strcmp(base,"USD") == 0 ) + return(0); + if ( strcmp(rel,"BTC") == 0 ) + return(1); + else if ( strcmp(base,"BTC") == 0 ) + return(-1); + else return(0); + //char *poloassets[][8] = { { "UNITY", "12071612744977229797" }, { "JLH", "6932037131189568014" }, { "XUSD", "12982485703607823902" }, { "LQD", "4630752101777892988" }, { "NXTI", "14273984620270850703" }, { "CNMT", "7474435909229872610", "6220108297598959542" } }; + //return(add_exchange_assetids(assetids,n,BTC_ASSETID,baseid,relid,exchangeid,poloassets,(int32_t)(sizeof(poloassets)/sizeof(*poloassets)))); +} + +double prices777_poloniex(struct prices777 *prices,int32_t maxdepth) +{ + char market[128]; + if ( prices->url[0] == 0 ) + { + sprintf(market,"%s_%s",prices->rel,prices->base); + sprintf(prices->url,"https://poloniex.com/public?command=returnOrderBook¤cyPair=%s&depth=%d",market,maxdepth); + } + return(prices777_standard("poloniex",prices->url,prices,0,0,maxdepth,0)); +} + +int32_t kraken_supports(char *_base,char *_rel) +{ + char *supports[] = { "BTC", "ETH", "LTC", "NMC", "STR", "DOGE", "XVN", "XRP", "USD", "CAD", "JPY", "GBP", "KRW" }; + int32_t i,j; char base[64],rel[64]; + strcpy(base,_base), strcpy(rel,_rel); + touppercase(base), touppercase(rel); + if ( strlen(base) > 5 || strlen(rel) > 5 ) + return(0); + for (i=0; ibase), strcpy(rel,prices->rel); + touppercase(base), touppercase(rel); + if ( strcmp(base,"BTC") == 0 ) + strcpy(base,"XBT"); + if ( strcmp(rel,"BTC") == 0 ) + strcpy(rel,"XBT"); + if ( strcmp(base,"DOGE") == 0 ) + strcpy(base,"XDG"); + if ( strcmp(rel,"DOGE") == 0 ) + strcpy(rel,"XDG"); + sprintf(field,"X%sZ%s",base,rel); + if ( prices->url[0] == 0 ) + { + sprintf(market,"%s%s",base,rel); + sprintf(prices->url,"https://api.kraken.com/0/public/Depth?pair=%s&count=%d",market,maxdepth); + } + if ( (jsonstr= issue_curl(prices->url)) != 0 ) + { +//{"error":[],"result":{"XXBTZUSD":{"asks":[["230.31677","1.438",1440886427],["230.31678","7.229",1440886068],["230.77732","0.012",1440876801],["230.77833","9.642",1440885707],["231.24081","9.719",1440884428]],"bids":[["228.04086","3.052",1440886443],["228.04085","0.590",1440886446],["228.04076","9.550",1440886434],["227.58559","10.214",1440800610],["227.56018","5.000",1440881811]]}}} + if ( (json= cJSON_Parse(jsonstr)) != 0 ) + { + //printf("got.(%s)\n",jsonstr); + hbla = prices777_json_orderbook("kraken",prices,maxdepth,jobj(json,"result"),field,"bids","asks",0,0); + free_json(json); + } + free(jsonstr); + } + return(hbla); +} + +char *bitfinex_parsebalance(struct exchange_info *exchange,double *balancep,char *coinstr) +{ + //[[{"type":"deposit","currency":"btc","amount":"0.0","available":"0.0"},{"type":"deposit","currency":"usd","amount":"0.0","available":"0.0"},{"type":"exchange","currency":"btc","amount":"0.01065851","available":"0.01065851"},{"type":"exchange","currency":"usd","amount":"23386.37278962","available":"0.00378962"},{"type":"trading","currency":"btc","amount":"0.0","available":"0.0"},{"type":"trading","currency":"usd","amount":"0.0","available":"0.0"}]] + int32_t i,n,ind; char field[64],*str,*typestr,*itemstr = 0; cJSON *item,*obj,*array; double amounts[3],avail[3],val0,val1; + *balancep = 0.; + strcpy(field,coinstr), tolowercase(field); + memset(amounts,0,sizeof(amounts)); + memset(avail,0,sizeof(avail)); + if ( exchange->balancejson != 0 && is_cJSON_Array(exchange->balancejson) != 0 && (n= cJSON_GetArraySize(exchange->balancejson)) > 0 ) + { + for (i=0; ibalancejson,i)) != 0 ) + { + if ( (str= jstr(item,"currency")) != 0 && strcmp(field,str) == 0 ) + { + val0 = jdouble(item,"amount"); + val1 = jdouble(item,"available"); + if ( (typestr= jstr(item,"type")) != 0 ) + { + if ( strcmp(typestr,"deposit") == 0 ) + ind = 0; + else if ( strcmp(typestr,"exchange") == 0 ) + ind = 1; + else if ( strcmp(typestr,"trading") == 0 ) + ind = 2; + else ind = -1; + if ( ind >= 0 ) + { + amounts[ind] = val0; + avail[ind] = val1; + } + } + } + } + } + if ( (obj= cJSON_CreateObject()) != 0 ) + { + touppercase(field); + *balancep = avail[0] + avail[1] + avail[2]; + jaddstr(obj,"base",field); + jaddnum(obj,"balance",*balancep); + jaddnum(obj,"total",amounts[0]+amounts[1]+amounts[2]); + array = cJSON_CreateArray(), jaddinum(array,avail[0]), jaddinum(array,amounts[0]), jadd(obj,"deposit",array); + array = cJSON_CreateArray(), jaddinum(array,avail[1]), jaddinum(array,amounts[1]), jadd(obj,"exchange",array); + array = cJSON_CreateArray(), jaddinum(array,avail[2]), jaddinum(array,amounts[2]), jadd(obj,"trading",array); + itemstr = jprint(obj,1); + } + } + if ( itemstr == 0 ) + return(clonestr("{\"error\":\"cant find coin balance\"}")); + return(itemstr); +} + +int32_t bitfinex_supports(char *base,char *rel) +{ + char *baserels[][2] = { {"btc","usd"}, {"ltc","usd"}, {"ltc","btc"} }; + return(baserel_polarity(baserels,(int32_t)(sizeof(baserels)/sizeof(*baserels)),base,rel)); +} + +double prices777_bitfinex(struct prices777 *prices,int32_t maxdepth) +{ + if ( prices->url[0] == 0 ) + sprintf(prices->url,"https://api.bitfinex.com/v1/book/%s%s",prices->base,prices->rel); + return(prices777_standard("bitfinex",prices->url,prices,"price","amount",maxdepth,0)); +} + +char *btce_parsebalance(struct exchange_info *exchange,double *balancep,char *coinstr) +{ + //btce.({"success":1,"return":{"funds":{"usd":73.02571846,"btc":0,"ltc":0,"nmc":0,"rur":0,"eur":0,"nvc":0.0000322,"trc":0,"ppc":0.00000002,"ftc":0,"xpm":2.28605349,"cnh":0,"gbp":0},"rights":{"info":1,"trade":1,"withdraw":0},"transaction_count":0,"open_orders":3,"server_time":1441918649}}) + char field[128],*itemstr = 0; cJSON *obj,*item; + *balancep = 0.; + strcpy(field,coinstr); + tolowercase(field); + if ( exchange->balancejson != 0 && (obj= jobj(exchange->balancejson,"return")) != 0 && (item= jobj(obj,"funds")) != 0 ) + { + *balancep = jdouble(item,field); + obj = cJSON_CreateObject(); + touppercase(field); + jaddstr(obj,"base",field); + jaddnum(obj,"balance",*balancep); + itemstr = jprint(obj,1); + } + if ( itemstr == 0 ) + return(clonestr("{\"error\":\"cant find coin balance\"}")); + return(itemstr); +} + +int32_t btce_supports(char *base,char *rel) +{ + char *baserels[][2] = { {"btc","usd"}, {"btc","rur"}, {"btc","eur"}, {"ltc","btc"}, {"ltc","usd"}, {"ltc","rur"}, {"ltc","eur"}, {"nmc","btc"}, {"nmc","usd"}, {"nvc","btc"}, {"nvc","usd"}, {"eur","usd"}, {"eur","rur"}, {"ppc","btc"}, {"ppc","usd"} }; + return(baserel_polarity(baserels,(int32_t)(sizeof(baserels)/sizeof(*baserels)),base,rel)); +} + +double prices777_btce(struct prices777 *prices,int32_t maxdepth) +{ + char field[64]; + sprintf(field,"%s_%s",prices->lbase,prices->lrel); + if ( prices->url[0] == 0 ) + sprintf(prices->url,"https://btc-e.com/api/3/depth/%s",field); + return(prices777_standard("btce",prices->url,prices,0,0,maxdepth,field)); +} + +char *bitstamp_parsebalance(struct exchange_info *exchange,double *balancep,char *coinstr) +{ + char field[128],*itemstr = 0; cJSON *obj,*item; + *balancep = 0.; + strcpy(field,coinstr); + tolowercase(field); + if ( exchange->balancejson != 0 && (obj= jobj(exchange->balancejson,"return")) != 0 && (item= jobj(obj,"funds")) != 0 ) + { + *balancep = jdouble(item,field); + obj = cJSON_CreateObject(); + touppercase(field); + jaddstr(obj,"base",field); + jaddnum(obj,"balance",*balancep); + itemstr = jprint(obj,1); + } + if ( itemstr == 0 ) + return(clonestr("{\"error\":\"cant find coin balance\"}")); + return(itemstr); +} + +int32_t bitstamp_supports(char *base,char *rel) +{ + if ( strcmp(base,"BTC") == 0 && strcmp(rel,"USD") == 0 ) + return(1); + else if ( strcmp(rel,"BTC") == 0 && strcmp(base,"USD") == 0 ) + return(-1); + else return(0); +} + +double prices777_bitstamp(struct prices777 *prices,int32_t maxdepth) +{ + if ( prices->url[0] == 0 ) + sprintf(prices->url,"https://www.bitstamp.net/api/order_book/"); + return(prices777_standard("bitstamp",prices->url,prices,0,0,maxdepth,0)); +} + +char *okcoin_parsebalance(struct exchange_info *exchange,double *balancep,char *coinstr) +{ + //okcoin.({"info":{"funds":{"asset":{"net":"0","total":"0"},"free":{"btc":"0","ltc":"0","usd":"0"},"freezed":{"btc":"0","ltc":"0","usd":"0"}}},"result":true}) + char field[128],*itemstr = 0; cJSON *obj,*item,*avail,*locked; double lockval = 0; + *balancep = 0.; + strcpy(field,coinstr); + tolowercase(field); + if ( exchange->balancejson != 0 && (obj= jobj(exchange->balancejson,"info")) != 0 && (item= jobj(obj,"funds")) != 0 ) + { + if ( (avail= jobj(item,"free")) != 0 ) + *balancep = jdouble(avail,field); + if ( (locked= jobj(item,"freezed")) != 0 ) + lockval = jdouble(locked,field); + obj = cJSON_CreateObject(); + touppercase(field); + jaddstr(obj,"base",field); + jaddnum(obj,"balance",*balancep); + jaddnum(obj,"locked",lockval); + itemstr = jprint(obj,1); + } + if ( itemstr == 0 ) + return(clonestr("{\"error\":\"cant find coin balance\"}")); + return(itemstr); +} + +int32_t okcoin_supports(char *base,char *rel) +{ + char *baserels[][2] = { {"btc","usd"}, {"ltc","usd"} }; + return(baserel_polarity(baserels,(int32_t)(sizeof(baserels)/sizeof(*baserels)),base,rel)); +} + +double prices777_okcoin(struct prices777 *prices,int32_t maxdepth) +{ + if ( prices->url[0] == 0 ) + sprintf(prices->url,"https://www.okcoin.com/api/v1/depth.do?symbol=%s_%s",prices->lbase,prices->lrel); + if ( strcmp(prices->rel,"USD") != 0 && strcmp(prices->rel,"BTC") != 0 ) + { + fprintf(stderr,">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> FATAL ERROR OKCOIN.(%s) only supports USD\n",prices->url); + printf(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> FATAL ERROR OKCOIN.(%s) only supports USD\n",prices->url); + exit(-1); + return(0); + } + return(prices777_standard("okcoin",prices->url,prices,0,0,maxdepth,0)); +} + +char *huobi_parsebalance(struct exchange_info *exchange,double *balancep,char *coinstr) +{ + char field[128],*itemstr = 0; cJSON *obj,*item; + *balancep = 0.; + strcpy(field,coinstr); + tolowercase(field); + if ( exchange->balancejson != 0 && (obj= jobj(exchange->balancejson,"return")) != 0 && (item= jobj(obj,"funds")) != 0 ) + { + *balancep = jdouble(item,field); + obj = cJSON_CreateObject(); + touppercase(field); + jaddstr(obj,"base",field); + jaddnum(obj,"balance",*balancep); + itemstr = jprint(obj,1); + } + if ( itemstr == 0 ) + return(clonestr("{\"error\":\"cant find coin balance\"}")); + return(itemstr); +} + +int32_t huobi_supports(char *base,char *rel) +{ + char *baserels[][2] = { {"btc","cny"}, {"ltc","cny"} }; + return(baserel_polarity(baserels,(int32_t)(sizeof(baserels)/sizeof(*baserels)),base,rel)); +} + +double prices777_huobi(struct prices777 *prices,int32_t maxdepth) +{ + if ( prices->url[0] == 0 ) + sprintf(prices->url,"http://api.huobi.com/staticmarket/depth_%s_json.js ",prices->lbase); + return(prices777_standard("huobi",prices->url,prices,0,0,maxdepth,0)); +} + +int32_t bityes_supports(char *base,char *rel) +{ + char *baserels[][2] = { {"btc","usd"}, {"ltc","usd"} }; + return(baserel_polarity(baserels,(int32_t)(sizeof(baserels)/sizeof(*baserels)),base,rel)); +} + +double prices777_bityes(struct prices777 *prices,int32_t maxdepth) +{ + //if ( prices->url[0] == 0 ) + sprintf(prices->url,"https://market.bityes.com/%s_%s/depth.js?time=%ld",prices->lrel,prices->lbase,(long)time(NULL)); + return(prices777_standard("bityes",prices->url,prices,0,0,maxdepth,0)); +} + +char *coinbase_parsebalance(struct exchange_info *exchange,double *balancep,char *coinstr) +{ + char field[128],*itemstr = 0; cJSON *obj,*item; + *balancep = 0.; + strcpy(field,coinstr); + tolowercase(field); + if ( exchange->balancejson != 0 && (obj= jobj(exchange->balancejson,"return")) != 0 && (item= jobj(obj,"funds")) != 0 ) + { + *balancep = jdouble(item,field); + obj = cJSON_CreateObject(); + touppercase(field); + jaddstr(obj,"base",field); + jaddnum(obj,"balance",*balancep); + itemstr = jprint(obj,1); + } + if ( itemstr == 0 ) + return(clonestr("{\"error\":\"cant find coin balance\"}")); + return(itemstr); +} + +int32_t coinbase_supports(char *base,char *rel) +{ + if ( strcmp(base,"BTC") == 0 && strcmp(rel,"USD") == 0 ) + return(1); + else if ( strcmp(rel,"BTC") == 0 && strcmp(base,"USD") == 0 ) + return(-1); + else return(0); +} + +double prices777_coinbase(struct prices777 *prices,int32_t maxdepth) +{ + if ( prices->url[0] == 0 ) + sprintf(prices->url,"https://api.exchange.coinbase.com/products/%s-%s/book?level=2",prices->base,prices->rel); + return(prices777_standard("coinbase",prices->url,prices,0,0,maxdepth,0)); +} + +char *lakebtc_parsebalance(struct exchange_info *exchange,double *balancep,char *coinstr) +{ + //lakebtc.({"balance":{"BTC":0.1},"locked":{"BTC":0.0},"profile":{"email":"jameslee777@yahoo.com","id":"U137561934","btc_deposit_addres":"1RyKrNJjezeFfvYaicnJEozHfhWfYzbuh"}}) + char field[128],*str,*itemstr = 0; cJSON *obj=0,*item=0,*prof=0; double locked = 0; + *balancep = 0.; + strcpy(field,coinstr); + touppercase(field); + if ( exchange->balancejson != 0 && (obj= jobj(exchange->balancejson,"balance")) != 0 && (item= jobj(exchange->balancejson,"locked")) != 0 && (prof= jobj(exchange->balancejson,"profile")) != 0 ) + { + *balancep = jdouble(obj,field); + locked = jdouble(item,field); + obj = cJSON_CreateObject(); + jaddstr(obj,"base",field); + jaddnum(obj,"balance",*balancep); + jaddnum(obj,"locked",locked); + if ( (str= jstr(prof,"btc_deposit_addres")) != 0 ) + jaddstr(obj,"deposit_address",str); + itemstr = jprint(obj,1); + } + if ( itemstr == 0 ) + return(clonestr("{\"error\":\"cant find coin balance\"}")); + return(itemstr); +} + +int32_t lakebtc_supports(char *base,char *rel) +{ + char *baserels[][2] = { {"btc","usd"}, {"btc","cny"} }; + return(baserel_polarity(baserels,(int32_t)(sizeof(baserels)/sizeof(*baserels)),base,rel)); +} + +double prices777_lakebtc(struct prices777 *prices,int32_t maxdepth) +{ + if ( prices->url[0] == 0 ) + { + if ( strcmp(prices->rel,"USD") == 0 ) + sprintf(prices->url,"https://www.LakeBTC.com/api_v1/bcorderbook"); + else if ( strcmp(prices->rel,"CNY") == 0 ) + sprintf(prices->url,"https://www.LakeBTC.com/api_v1/bcorderbook_cny"); + else printf("illegal lakebtc pair.(%s/%s)\n",prices->base,prices->rel); + } + return(prices777_standard("lakebtc",prices->url,prices,0,0,maxdepth,0)); +} + +#ifdef exmo_supported +int32_t exmo_supports(char *base,char *rel) +{ + if ( strcmp(base,"BTC") == 0 && (strcmp(rel,"USD") == 0 || strcmp(rel,"EUR") == 0 || strcmp(rel,"RUR") == 0) ) + return(1); + else if ( strcmp(rel,"BTC") == 0 && (strcmp(base,"USD") == 0 || strcmp(base,"EUR") == 0 || strcmp(base,"RUR") == 0) ) + return(-1); + else return(0); +} + +double prices777_exmo(struct prices777 *prices,int32_t maxdepth) +{ + if ( prices->url[0] == 0 ) + sprintf(prices->url,"https://api.exmo.com/api_v2/orders_book?pair=%s_%s",prices->base,prices->rel); + return(prices777_standard("exmo",prices->url,prices,0,0,maxdepth,0)); +} +#endif + +// "gatecoin", "quoine", "jubi", "hitbtc" + +char *btc38_parsebalance(struct exchange_info *exchange,double *balancep,char *coinstr) +{ + char field[128],*str,*itemstr = 0; cJSON *obj; double lockbalance,imma; + *balancep = 0.; + strcpy(field,coinstr); + tolowercase(field); + strcat(field,"_balance"); + if ( exchange->balancejson != 0 && (str= jstr(exchange->balancejson,field)) != 0 ) + { + *balancep = jdouble(exchange->balancejson,field); + strcpy(field,coinstr), tolowercase(field), strcat(field,"_balance_lock"); + lockbalance = jdouble(exchange->balancejson,field); + strcpy(field,coinstr), tolowercase(field), strcat(field,"_balance_imma"); + imma = jdouble(exchange->balancejson,field); + obj = cJSON_CreateObject(); + jaddnum(obj,"balance",*balancep); + jaddnum(obj,"locked_balance",lockbalance); + jaddnum(obj,"imma_balance",imma); + itemstr = jprint(obj,1); + } + if ( itemstr == 0 ) + return(clonestr("{\"error\":\"cant find coin balance\"}")); + return(itemstr); +} + +int32_t btc38_supports(char *_base,char *_rel) +{ + char *cnypairs[] = { "BTC", "LTC", "DOGE", "XRP", "BTS", "STR", "NXT", "BLK", "YBC", "BILS", "BOST", "PPC", "APC", "ZCC", "XPM", "DGC", "MEC", "WDC", "QRK", "BEC", "ANC", "UNC", "RIC", "SRC", "TAG" }; + char *btcpairs[] = { "TMC", "LTC", "DOGE", "XRP", "BTS", "STR", "NXT", "BLK", "XEM", "VPN", "BILS", "BOST", "WDC", "ANC", "XCN", "VOOT", "SYS", "NRS", "NAS", "SYNC", "MED", "EAC" }; + int32_t i; char base[64],rel[64]; + strcpy(base,_base), strcpy(rel,_rel); + touppercase(base), touppercase(rel); + if ( strlen(base) > 5 || strlen(rel) > 5 ) + return(0); + if ( strcmp(base,"BTC") == 0 && strcmp(rel,"CNY") == 0 ) + return(1); + else if ( strcmp(base,"CNY") == 0 && strcmp(rel,"BTC") == 0 ) + return(-1); + else if ( strcmp(base,"BTC") == 0 ) + { + for (i=0; iurl[0] == 0 ) + { + if ( strcmp(prices->lbase,"cny") == 0 && strcmp(prices->lrel,"btc") == 0 ) + sprintf(prices->url,"http://api.btc38.com/v1/depth.php?c=%s&mk_type=%s","btc","cny"); + else sprintf(prices->url,"http://api.btc38.com/v1/depth.php?c=%s&mk_type=%s",prices->lbase,prices->lrel); + } + return(prices777_standard("btc38",prices->url,prices,0,0,maxdepth,0)); +} + +char *quadriga_parsebalance(struct exchange_info *exchange,double *balancep,char *coinstr) +{ +//[{"btc_available":"0.00000000","btc_reserved":"0.00000000","btc_balance":"0.00000000","cad_available":"0.00","cad_reserved":"0.00","cad_balance":"0.00","usd_available":"0.00","usd_reserved":"0.00","usd_balance":"0.00","xau_available":"0.000000","xau_reserved":"0.000000","xau_balance":"0.000000","fee":"0.5000"}] + char field[128],*str,*itemstr = 0; cJSON *obj; double reserv,total; + *balancep = 0.; + strcpy(field,coinstr); + tolowercase(field); + strcat(field,"_available"); + if ( exchange->balancejson != 0 && (str= jstr(exchange->balancejson,field)) != 0 ) + { + *balancep = jdouble(exchange->balancejson,field); + strcpy(field,coinstr), tolowercase(field), strcat(field,"_reserved"); + reserv = jdouble(exchange->balancejson,field); + strcpy(field,coinstr), tolowercase(field), strcat(field,"_balance"); + total = jdouble(exchange->balancejson,field); + obj = cJSON_CreateObject(); + jaddnum(obj,"balance",*balancep); + jaddnum(obj,"locked_balance",reserv); + jaddnum(obj,"total",total); + itemstr = jprint(obj,1); + } + if ( itemstr == 0 ) + return(clonestr("{\"error\":\"cant find coin balance\"}")); + return(itemstr); +} + +int32_t quadriga_supports(char *base,char *rel) +{ + char *baserels[][2] = { {"btc","usd"}, {"btc","cad"} }; + return(baserel_polarity(baserels,(int32_t)(sizeof(baserels)/sizeof(*baserels)),base,rel)); +} + +double prices777_quadriga(struct prices777 *prices,int32_t maxdepth) +{ + if ( prices->url[0] == 0 ) + sprintf(prices->url,"https://api.quadrigacx.com/v2/order_book?book=%s_%s",prices->lbase,prices->lrel); + return(prices777_standard("quadriga",prices->url,prices,0,0,maxdepth,0)); +} + + +/*void prices777_kraken(struct prices777 *prices,int32_t maxdepth) + { + if ( prices->url[0] == 0 ) + sprintf(prices->url,"https://api.kraken.com/0/public/Depth"); // need POST + prices777_standard("kraken",prices->url,prices,0,0,maxdepth); + }*/ + +/*void prices777_itbit(struct prices777 *prices,int32_t maxdepth) + { + if ( prices->url[0] == 0 ) + sprintf(prices->url,"https://www.itbit.com/%s%s",prices->base,prices->rel); + prices777_standard("itbit",prices->url,prices,0,0,maxdepth); + }*/ +#endif + +uint64_t prices777_truefx(uint64_t *millistamps,double *bids,double *asks,double *opens,double *highs,double *lows,char *username,char *password,uint64_t idnum) +{ + char *truefxfmt = "http://webrates.truefx.com/rates/connect.html?f=csv&id=jl777:truefxtest:poll:1437671654417&c=EUR/USD,USD/JPY,GBP/USD,EUR/GBP,USD/CHF,AUD/NZD,CAD/CHF,CHF/JPY,EUR/AUD,EUR/CAD,EUR/JPY,EUR/CHF,USD/CAD,AUD/USD,GBP/JPY,AUD/CAD,AUD/CHF,AUD/JPY,EUR/NOK,EUR/NZD,GBP/CAD,GBP/CHF,NZD/JPY,NZD/USD,USD/NOK,USD/SEK"; + + // EUR/USD,1437569931314,1.09,034,1.09,038,1.08922,1.09673,1.09384 USD/JPY,1437569932078,123.,778,123.,781,123.569,123.903,123.860 GBP/USD,1437569929008,1.56,332,1.56,337,1.55458,1.56482,1.55538 EUR/GBP,1437569931291,0.69,742,0.69,750,0.69710,0.70383,0.70338 USD/CHF,1437569932237,0.96,142,0.96,153,0.95608,0.96234,0.95748 EUR/JPY,1437569932237,134.,960,134.,972,134.842,135.640,135.476 EUR/CHF,1437569930233,1.04,827,1.04,839,1.04698,1.04945,1.04843 USD/CAD,1437569929721,1.30,231,1.30,241,1.29367,1.30340,1.29466 AUD/USD,1437569931700,0.73,884,0.73,890,0.73721,0.74395,0.74200 GBP/JPY,1437569931924,193.,500,193.,520,192.298,193.670,192.649 + char url[1024],userpass[1024],buf[128],base[64],rel[64],*str; cJSON *array; int32_t jpyflag,i,c,n = 0; double pre,pre2,bid,ask,open,high,low; long millistamp; + //printf("truefx.(%s)(%s).%llu\n",username,password,(long long)idnum); + url[0] = 0; + if ( username[0] != 0 && password[0] != 0 ) + { + if ( idnum == 0 ) + { + sprintf(userpass,"http://webrates.truefx.com/rates/connect.html?f=csv&s=y&u=%s&p=%s&q=poll",username,password); + if ( (str= issue_curl(userpass)) != 0 ) + { + _stripwhite(str,0); + printf("(%s) -> (%s)\n",userpass,str); + sprintf(userpass,"%s:%s:poll:",username,password); + idnum = calc_nxt64bits(str + strlen(userpass)); + free(str); + printf("idnum.%llu\n",(long long)idnum); + } + } + if ( idnum != 0 ) + sprintf(url,truefxfmt,username,password,(long long)idnum); + } + if ( url[0] == 0 ) + sprintf(url,"http://webrates.truefx.com/rates/connect.html?f=csv&s=y"); + if ( (str= issue_curl(url)) != 0 ) + { + //printf("(%s) -> (%s)\n",url,str); + while ( str[n + 0] != 0 && str[n] != '\n' && str[n] != '\r' ) + { + for (i=jpyflag=0; str[n + i]!=' '&&str[n + i]!='\n'&&str[n + i]!='\r'&&str[n + i]!=0; i++) + { + if ( i > 0 && str[n+i] == ',' && str[n+i-1] == '.' ) + str[n+i-1] = ' ', jpyflag = 1; + else if ( i > 0 && str[n+i-1] == ',' && str[n+i] == '0' && str[n+i+1+2] == ',' ) + { + str[n+i] = ' '; + if ( str[n+i+1] == '0' ) + str[n+i+1] = ' ', i++; + } + } + memcpy(base,str+n,3), base[3] = 0; + memcpy(rel,str+n+4,3), rel[3] = 0; + str[n + i] = 0; + //printf("str.(%s) (%s/%s) %d n.%d i.%d\n",str+n,base,rel,str[n],n,i); + sprintf(buf,"[%s]",str+n+7+1); + n += i + 1; + if ( (array= cJSON_Parse(buf)) != 0 ) + { + if ( is_cJSON_Array(array) != 0 ) + { + millistamp = (uint64_t)get_API_float(jitem(array,0)); + pre = get_API_float(jitem(array,1)); + bid = get_API_float(jitem(array,2)); + pre2 = get_API_float(jitem(array,3)); + ask = get_API_float(jitem(array,4)); + open = get_API_float(jitem(array,5)); + high = get_API_float(jitem(array,6)); + low = get_API_float(jitem(array,7)); + if ( jpyflag != 0 ) + bid = pre + (bid / 1000.), ask = pre2 + (ask / 1000.); + else bid = pre + (bid / 100000.), ask = pre2 + (ask / 100000.); + if ( (c= prices777_contractnum(base,rel)) >= 0 ) + { + char name[64]; + strcpy(name,base), strcat(name,rel); + if ( BUNDLE.truefx[c] == 0 ) + BUNDLE.truefx[c] = prices777_initpair(0,"truefx",base,rel,0,name,stringbits(base),stringbits(rel),0); + millistamps[c] = millistamp,opens[c] = open, highs[c] = high, lows[c] = low, bids[c] = bid, asks[c] = ask; + if ( Debuglevel > 2 ) + { + if ( jpyflag != 0 ) + printf("%s%s.%-2d %llu: %.3f %.3f %.3f | %.3f %.3f\n",base,rel,c,(long long)millistamp,open,high,low,bid,ask); + else printf("%s%s.%-2d %llu: %.5f %.5f %.5f | %.5f %.5f\n",base,rel,c,(long long)millistamp,open,high,low,bid,ask); + } + } else printf("unknown basepair.(%s) (%s)\n",base,rel); + } + free_json(array); + } else printf("cant parse.(%s)\n",buf); + } + free(str); + } + return(idnum); +} + + +double prices777_fxcm(double lhlogmatrix[8][8],double logmatrix[8][8],double bids[64],double asks[64],double highs[64],double lows[64]) +{ + char name[64],*xmlstr,*str; cJSON *json,*obj; int32_t i,j,c,flag,k,n = 0; double bid,ask,high,low; struct destbuf numstr; + memset(bids,0,sizeof(*bids) * NUM_CONTRACTS), memset(asks,0,sizeof(*asks) * NUM_CONTRACTS); + if ( (xmlstr= issue_curl("http://rates.fxcm.com/RatesXML")) != 0 ) + { + _stripwhite(xmlstr,0); + //printf("(%s)\n",xmlstr); + i = 0; + if ( strncmp("'&&xmlstr[i]!=0; i++) + ; + if ( xmlstr[i] == '>' ) + i++; + for (j=0; xmlstr[i]!=0; i++) + { + if ( strncmp("",&xmlstr[i],strlen("")) == 0 ) + xmlstr[j++] = '[', i += strlen("")-1; + else if ( strncmp(" 1 ) + xmlstr[j++] = ','; + memcpy(&xmlstr[j],"{\"Symbol\":",strlen("{\"Symbol\":")), i += strlen("", "\"Bid\":" }, { "", "\"Ask\":" }, { "", "\"High\":" }, { "", "\"Low\":" }, { "", "\"Direction\":" }, { "", "\"Last\":\"" } }; + for (k=0; k", "", "", "", "", "", "", "", ">" }; + for (k=0; k",ends[k]) == 0 ) + xmlstr[j++] = '}'; + else if ( strcmp("",ends[k]) == 0 ) + xmlstr[j++] = ']'; + else if ( strcmp("",ends[k]) == 0 ) + xmlstr[j++] = '\"'; + else xmlstr[j++] = ','; + break; + } + if ( k == sizeof(ends)/sizeof(*ends) ) + xmlstr[j++] = xmlstr[i]; + } + } + } + xmlstr[j] = 0; + if ( (json= cJSON_Parse(xmlstr)) != 0 ) + { + /* + 123.763 + 123.786 + 123.956 + 123.562 + -1 + 08:49:15*/ + //printf("Parsed stupid XML! (%s)\n",xmlstr); + if ( is_cJSON_Array(json) != 0 && (n= cJSON_GetArraySize(json)) != 0 ) + { + for (i=0; i= 0 ) + { + bids[c] = bid, asks[c] = ask, highs[c] = high, lows[c] = low; + //printf("c.%d (%s) %f %f\n",c,name,bid,ask); + flag = 1; + if ( BUNDLE.fxcm[c] == 0 ) + { + //printf("max.%ld FXCM: not initialized.(%s) %d\n",sizeof(CONTRACTS)/sizeof(*CONTRACTS),name,c); + BUNDLE.fxcm[c] = prices777_initpair(0,"fxcm",name,0,0,name,peggy_basebits(name),peggy_relbits(name),0); + } + } else printf("cant find.%s\n",name);//, getchar(); + } + if ( flag == 0 ) + printf("FXCM: Error finding.(%s) c.%d (%s)\n",name,c,cJSON_Print(obj)); + } + } + free_json(json); + } else printf("couldnt parse.(%s)\n",xmlstr); + free(xmlstr); + } + calc_primary_currencies(lhlogmatrix,lows,highs); + return(calc_primary_currencies(logmatrix,bids,asks)); +} + +double prices777_instaforex(double logmatrix[8][8],uint32_t timestamps[NUM_COMBINED+1],double bids[128],double asks[128]) +{ + //{"NZDUSD":{"symbol":"NZDUSD","lasttime":1437580206,"digits":4,"change":"-0.0001","bid":"0.6590","ask":"0.6593"}, + char *jsonstr,*str; cJSON *json,*item; int32_t i,c; struct destbuf numstr; + memset(timestamps,0,sizeof(*timestamps) * (NUM_COMBINED + 1)), memset(bids,0,sizeof(*bids) * (NUM_COMBINED + 1)), memset(asks,0,sizeof(*asks) * (NUM_COMBINED + 1)); + if ( (jsonstr= issue_curl("https://quotes.instaforex.com/get_quotes.php?q=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,XAUUSD&m=json")) != 0 ) + { + // printf("(%s)\n",jsonstr); + if ( (json= cJSON_Parse(jsonstr)) != 0 ) + { + for (i=0; i<=NUM_CONTRACTS; i++) + { + if ( i < NUM_CONTRACTS ) + str = CONTRACTS[i], c = i; + else str = "XAUUSD", c = prices777_contractnum(str,0); + if ( (item= jobj(json,str)) != 0 ) + { + timestamps[c] = juint(item,"lasttime"); + copy_cJSON(&numstr,jobj(item,"bid")), bids[c] = atof(numstr.buf); + copy_cJSON(&numstr,jobj(item,"ask")), asks[c] = atof(numstr.buf); + //if ( c < NUM_CONTRACTS && Contract_rel[c] == JPY ) + // bids[i] /= 100., asks[i] /= 100.; + if ( Debuglevel > 2 ) + printf("%s.(%.6f %.6f) ",str,bids[c],asks[c]); + if ( BUNDLE.instaforex[c] == 0 ) + BUNDLE.instaforex[c] = prices777_initpair(0,"instaforex",str,0,0,str,peggy_basebits(str),peggy_relbits(str),0); + } + } + free_json(json); + } + free(jsonstr); + } + return(calc_primary_currencies(logmatrix,bids,asks)); +} + +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 2 ) + printf("%8.5f ",prices[MAX_CURRENCIES*basenum + i]); + } + if ( Debuglevel > 2 ) + printf("%s.%d %d\n",CURRENCIES[basenum],basenum,nonz); + } + } + } + return(count); +} + +#endif + diff --git a/iguana/InstantDEX/prices777.c b/iguana/InstantDEX/prices777.c new file mode 100755 index 000000000..5d65d706d --- /dev/null +++ b/iguana/InstantDEX/prices777.c @@ -0,0 +1,1812 @@ +/****************************************************************************** + * 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 +#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; inum-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 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=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; iutc32[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; inum+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 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= 0 ) + { + basemask |= (1L << c); + //printf("(%s %lx) ",CONTRACTS[c],1L<= 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; imetals[i]; + break; + } + sprintf(retbuf,"{\"result\":\"success\",\"contract\":\"%s\",\"base\":\"%s\",\"rel\":\"%s\"",contract,base,rel); + for (i=0; icontract,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; iissue = 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; iexchange,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; iissue = 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; inumdependents; 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; idisabled == 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; idisabled == 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; ipollgap = 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; irefcount > 0 || strcmp(exchangeptr->name,"unconf") == 0) )//&& strcmp(exchangeptr->name,"pangea") != 0 && strcmp(exchangeptr->name,"jumblr") != 0 ) + iguana_launch(iguana_coinadd("BTCD"),"exchangeloop",(void *)prices777_exchangeloop,exchangeptr,IGUANA_EXCHANGETHREAD); + } + 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); +} + +void prices777_btcprices(int32_t enddatenum,int32_t numdates) +{ + 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¤cyPair=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 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 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 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 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 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¤cyPair=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¤cyPair=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; ilbase,"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" : "zł"}, + "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¤cyPair=BTC_BTCD&start=1405699200&end=9999999999&period=86400 + + // https://poloniex.com/public?command=returnTradeHistory¤cyPair=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 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 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 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; ctbids[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 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 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 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; itmillistamps,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 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; jexchange,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); +} + diff --git a/iguana/InstantDEX/quotes.h b/iguana/InstantDEX/quotes.h new file mode 100755 index 000000000..19a1218a7 --- /dev/null +++ b/iguana/InstantDEX/quotes.h @@ -0,0 +1,880 @@ +/****************************************************************************** + * Copyright © 2014-2015 The SuperNET Developers. * + * * + * See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at * + * the top-level directory of this distribution for the individual copyright * + * holder information and the developer policies on copyright and licensing. * + * * + * Unless otherwise agreed in a custom licensing agreement, no part of the * + * SuperNET software, including this file may be copied, modified, propagated * + * or distributed except according to the terms contained in the LICENSE file * + * * + * Removal or modification of this copyright notice is prohibited. * + * * + ******************************************************************************/ + + +#ifndef xcode_quotes_h +#define xcode_quotes_h + +#ifdef oldway +int32_t make_jumpiQ(uint64_t refbaseid,uint64_t refrelid,int32_t flip,struct InstantDEX_quote *iQ,struct InstantDEX_quote *baseiQ,struct InstantDEX_quote *reliQ,char *gui,int32_t duration) +{ + uint64_t baseamount,relamount,frombase,fromrel,tobase,torel; + double vol; + char exchange[64]; + uint32_t timestamp; + frombase = baseiQ->baseamount, fromrel = baseiQ->relamount; + tobase = reliQ->baseamount, torel = reliQ->relamount; + if ( make_jumpquote(refbaseid,refrelid,&baseamount,&relamount,&frombase,&fromrel,&tobase,&torel) == 0. ) + return(0); + if ( (timestamp= reliQ->timestamp) > baseiQ->timestamp ) + timestamp = baseiQ->timestamp; + iQ_exchangestr(exchange,iQ); + create_InstantDEX_quote(iQ,timestamp,0,calc_quoteid(baseiQ) ^ calc_quoteid(reliQ),0.,0.,refbaseid,baseamount,refrelid,relamount,exchange,0,gui,baseiQ,reliQ,duration); + if ( Debuglevel > 2 ) + printf("jump%s: %f (%llu/%llu) %llu %llu (%f %f) %llu %llu\n",flip==0?"BID":"ASK",calc_price_volume(&vol,iQ->baseamount,iQ->relamount),(long long)baseamount,(long long)relamount,(long long)frombase,(long long)fromrel,calc_price_volume(&vol,frombase,fromrel),calc_price_volume(&vol,tobase,torel),(long long)tobase,(long long)torel); + iQ->isask = flip; + iQ->minperc = baseiQ->minperc; + if ( reliQ->minperc > iQ->minperc ) + iQ->minperc = reliQ->minperc; + return(1); +} +#else + +struct InstantDEX_quote *AllQuotes; + +void clear_InstantDEX_quoteflags(struct InstantDEX_quote *iQ) +{ + //duration:14,wallet:1,a:1,isask:1,expired:1,closed:1,swap:1,responded:1,matched:1,feepaid:1,automatch:1,pending:1,minperc:7; + iQ->s.a = iQ->s.expired = iQ->s.swap = iQ->s.feepaid = 0; + iQ->s.closed = iQ->s.pending = iQ->s.responded = iQ->s.matched = 0; +} +void cancel_InstantDEX_quote(struct InstantDEX_quote *iQ) { iQ->s.closed = 1; } + +int32_t InstantDEX_uncalcsize() { struct InstantDEX_quote iQ; return(sizeof(iQ.hh) + sizeof(iQ.s.quoteid) + sizeof(iQ.s.price) + sizeof(iQ.s.vol)); } + +int32_t iQcmp(struct InstantDEX_quote *iQA,struct InstantDEX_quote *iQB) +{ + if ( iQA->s.isask == iQB->s.isask && iQA->s.baseid == iQB->s.baseid && iQA->s.relid == iQB->s.relid && iQA->s.baseamount == iQB->s.baseamount && iQA->s.relamount == iQB->s.relamount ) + return(0); + else if ( iQA->s.isask != iQB->s.isask && iQA->s.baseid == iQB->s.relid && iQA->s.relid == iQB->s.baseid && iQA->s.baseamount == iQB->s.relamount && iQA->s.relamount == iQB->s.baseamount ) + return(0); + return(-1); +} + +uint64_t calc_txid(unsigned char *buf,int32_t len) +{ + bits256 hash; + vcalc_sha256(0,hash.bytes,buf,len); + return(hash.txid); +} + +uint64_t calc_quoteid(struct InstantDEX_quote *iQ) +{ + struct InstantDEX_quote Q; + if ( iQ == 0 ) + return(0); + if ( iQ->s.duration == 0 || iQ->s.duration > ORDERBOOK_EXPIRATION ) + iQ->s.duration = ORDERBOOK_EXPIRATION; + if ( iQ->s.quoteid == 0 ) + { + Q = *iQ; + clear_InstantDEX_quoteflags(&Q); + if ( Q.s.isask != 0 ) + { + Q.s.baseid = iQ->s.relid, Q.s.baseamount = iQ->s.relamount; + Q.s.relid = iQ->s.baseid, Q.s.relamount = iQ->s.baseamount; + Q.s.isask = Q.s.minperc = 0; + } + return(calc_txid((uint8_t *)((long)&Q + InstantDEX_uncalcsize()),sizeof(Q) - InstantDEX_uncalcsize())); + } return(iQ->s.quoteid); +} + +struct InstantDEX_quote *find_iQ(uint64_t quoteid) +{ + struct InstantDEX_quote *iQ; + HASH_FIND(hh,AllQuotes,"eid,sizeof(quoteid),iQ); + return(iQ); +} + +struct InstantDEX_quote *delete_iQ(uint64_t quoteid) +{ + struct InstantDEX_quote *iQ; + if ( (iQ= find_iQ(quoteid)) != 0 ) + { + HASH_DELETE(hh,AllQuotes,iQ); + } + return(iQ); +} + +struct InstantDEX_quote *findquoteid(uint64_t quoteid,int32_t evenclosed) +{ + struct InstantDEX_quote *iQ; + if ( (iQ= find_iQ(quoteid)) != 0 ) + { + if ( evenclosed != 0 || iQ->s.closed == 0 ) + { + if ( calc_quoteid(iQ) == quoteid ) + return(iQ); + else printf("calc_quoteid %llu vs %llu\n",(long long)calc_quoteid(iQ),(long long)quoteid); + } //else printf("quoteid.%llu closed.%d\n",(long long)quoteid,iQ->closed); + } else printf("couldnt find %llu\n",(long long)quoteid); + return(0); +} + +int32_t cancelquote(char *NXTaddr,uint64_t quoteid) +{ + struct InstantDEX_quote *iQ; + if ( (iQ= findquoteid(quoteid,0)) != 0 && iQ->s.offerNXT == calc_nxt64bits(NXTaddr) && iQ->exchangeid == INSTANTDEX_EXCHANGEID ) + { + cancel_InstantDEX_quote(iQ); + return(1); + } + return(0); +} + +struct InstantDEX_quote *create_iQ(struct InstantDEX_quote *iQ,char *walletstr) +{ + struct InstantDEX_quote *newiQ,*tmp; struct prices777 *prices; int32_t inverted; long len = 0; + if ( walletstr != 0 && (len= strlen(walletstr)) > 0 ) + iQ->s.wallet = 1, len++; + calc_quoteid(iQ); + printf("createiQ %llu/%llu %f %f quoteid.%llu offerNXT.%llu wallet.%d (%s)\n",(long long)iQ->s.baseid,(long long)iQ->s.relid,iQ->s.price,iQ->s.vol,(long long)iQ->s.quoteid,(long long)iQ->s.offerNXT,iQ->s.wallet,walletstr!=0?walletstr:""); + if ( (newiQ= find_iQ(iQ->s.quoteid)) != 0 ) + return(newiQ); + newiQ = calloc(1,sizeof(*newiQ) + len); + *newiQ = *iQ; + if ( len != 0 ) + memcpy(newiQ->walletstr,walletstr,len); + HASH_ADD(hh,AllQuotes,s.quoteid,sizeof(newiQ->s.quoteid),newiQ); + if ( (prices= prices777_find(&inverted,iQ->s.baseid,iQ->s.relid,INSTANTDEX_NAME)) != 0 ) + prices->dirty++; + { + struct InstantDEX_quote *checkiQ; + if ( (checkiQ= find_iQ(iQ->s.quoteid)) == 0 || iQcmp(iQ,checkiQ) != 0 )//memcmp((uint8_t *)((long)checkiQ + sizeof(checkiQ->hh) + sizeof(checkiQ->quoteid)),(uint8_t *)((long)iQ + sizeof(iQ->hh) + sizeof(iQ->quoteid)),sizeof(*iQ) - sizeof(iQ->hh) - sizeof(iQ->quoteid)) != 0 ) + { + int32_t i; + for (i=(sizeof(iQ->hh) - sizeof(iQ->s.quoteid)); ihh) - sizeof(iQ->s.quoteid); i++) + printf("%02x ",((uint8_t *)iQ)[i]); + printf("iQ\n"); + for (i=(sizeof(checkiQ->hh) + sizeof(checkiQ->s.quoteid)); ihh) - sizeof(checkiQ->s.quoteid); i++) + printf("%02x ",((uint8_t *)checkiQ)[i]); + printf("checkiQ\n"); + printf("error finding iQ after adding %llu vs %llu\n",(long long)checkiQ->s.quoteid,(long long)iQ->s.quoteid); + } + } + HASH_ITER(hh,AllQuotes,iQ,tmp) + { + if ( iQ->s.expired != 0 ) + { + printf("quoteid.%llu expired, purging\n",(long long)iQ->s.expired); + delete_iQ(iQ->s.quoteid); + } + } + return(newiQ); +} + +#ifdef later +cJSON *pangea_walletitem(cJSON *walletitem,struct coin777 *coin,int32_t rakemillis,int64_t bigblind,int64_t ante,int32_t minbuyin,int32_t maxbuyin) +{ + char *addr; struct destbuf pubkey; + if ( walletitem == 0 ) + walletitem = cJSON_CreateObject(); + //printf("call get_acct_coinaddr.%s (%s) (%s)\n",coin->name,coin->serverport,coin->userpass); + if ( coin->pangeapubkey[0] == 0 || coin->pangeacoinaddr[0] == 0 ) + { + if ( strcmp("NXT",coin->name) == 0 ) + { + } + else if ( (addr= get_acct_coinaddr(coin->pangeacoinaddr,coin->name,coin->serverport,coin->userpass,"pangea")) != 0 ) + { + //printf("get_pubkey\n"); + get_pubkey(&pubkey,coin->name,coin->serverport,coin->userpass,coin->pangeacoinaddr); + strcpy(coin->pangeapubkey,pubkey.buf); + } + } + jaddstr(walletitem,"pubkey",coin->pangeapubkey); + jaddstr(walletitem,"coinaddr",coin->pangeacoinaddr); + jaddnum(walletitem,"rakemillis",rakemillis); + jaddnum(walletitem,"minbuyin",minbuyin); + jaddnum(walletitem,"maxbuyin",maxbuyin); + jadd64bits(walletitem,"bigblind",bigblind); + jadd64bits(walletitem,"ante",ante); + return(walletitem); +} + +cJSON *set_walletstr(cJSON *walletitem,char *walletstr,struct InstantDEX_quote *iQ) +{ + char pubkeystr[128],pkhash[128],base[64],rel[64],fieldA[64],fieldB[64],fieldpkhash[64],*pubA,*pubB,*pkhashstr,*str,*exchangestr; + struct coin777 *coin; int32_t flip = 0; + if ( walletstr != 0 && walletitem == 0 ) + walletitem = cJSON_Parse(walletstr); + if ( walletitem == 0 ) + walletitem = cJSON_CreateObject(); + unstringbits(base,iQ->s.basebits), unstringbits(rel,iQ->s.relbits); + flip = (iQ->s.offerNXT != IGUANA_MY64BITS); + if ( strcmp(base,"NXT") != 0 ) + coin = coin777_find(base,1); + else if ( strcmp(rel,"NXT") != 0 ) + coin = coin777_find(rel,1), flip ^= 1; + else coin = 0; + if ( coin != 0 ) + { + if ( (exchangestr= exchange_str(iQ->exchangeid)) != 0 && strcmp(exchangestr,"pangea") == 0 ) + pangea_walletitem(walletitem,coin,iQ->s.minperc,iQ->s.baseamount,iQ->s.relamount,iQ->s.minbuyin,iQ->s.maxbuyin); + else + { + //printf("START.(%s)\n",jprint(walletitem,0)); + if ( (iQ->s.isask ^ flip) == 0 ) + { + sprintf(fieldA,"%spubA",coin->name); + if ( (pubA= jstr(walletitem,fieldA)) != 0 ) + cJSON_DeleteItemFromObject(walletitem,fieldA); + jaddstr(walletitem,fieldA,coin->atomicsendpubkey); + //printf("replaceA\n"); + } + else + { + sprintf(fieldB,"%spubB",coin->name); + if ( (pubB= jstr(walletitem,fieldB)) != 0 ) + cJSON_DeleteItemFromObject(walletitem,fieldB); + jaddstr(walletitem,fieldB,coin->atomicrecvpubkey); + sprintf(fieldpkhash,"%spkhash",coin->name); + if ( (pkhashstr= jstr(walletitem,fieldpkhash)) != 0 ) + cJSON_DeleteItemFromObject(walletitem,fieldpkhash); + subatomic_pubkeyhash(pubkeystr,pkhash,coin,iQ->s.quoteid); + jaddstr(walletitem,fieldpkhash,pkhash); + //printf("replaceB\n"); + } + } + str = jprint(walletitem,0); + strcpy(walletstr,str); + free(str); + return(walletitem); + } + return(0); +} +#endif + +char *InstantDEX_str(char *walletstr,char *buf,int32_t extraflag,struct InstantDEX_quote *iQ) +{ + cJSON *json; char _buf[4096],base[64],rel[64],*str; + unstringbits(base,iQ->s.basebits), unstringbits(rel,iQ->s.relbits); + if ( buf == 0 ) + buf = _buf; + sprintf(buf,"{\"quoteid\":\"%llu\",\"base\":\"%s\",\"baseid\":\"%llu\",\"baseamount\":\"%llu\",\"rel\":\"%s\",\"relid\":\"%llu\",\"relamount\":\"%llu\",\"price\":%.8f,\"volume\":%.8f,\"offerNXT\":\"%llu\",\"timestamp\":\"%u\",\"isask\":\"%u\",\"exchange\":\"%s\",\"gui\":\"%s\"}",(long long)iQ->s.quoteid,base,(long long)iQ->s.baseid,(long long)iQ->s.baseamount,rel,(long long)iQ->s.relid,(long long)iQ->s.relamount,iQ->s.price,iQ->s.vol,(long long)iQ->s.offerNXT,iQ->s.timestamp,iQ->s.isask,exchange_str(iQ->exchangeid),iQ->gui); + if ( extraflag != 0 ) + { + sprintf(buf + strlen(buf) - 1,",\"plugin\":\"relay\",\"destplugin\":\"InstantDEX\",\"method\":\"busdata\",\"submethod\":\"%s\"}",(iQ->s.isask != 0) ? "ask" : "bid"); + } + //printf("InstantDEX_str.(%s)\n",buf); + if ( (json= cJSON_Parse(buf)) != 0 ) + { +#ifdef later + char _buf[4096],_walletstr[256],base[64],rel[64],*exchange,*str; cJSON *walletitem,*json; struct coin777 *coin; + if ( walletstr == 0 ) + { + walletstr = _walletstr; + walletstr[0] = 0; + } + if ( (exchange= exchange_str(iQ->exchangeid)) != 0 ) + { + coin = coin777_find(base,0); + if ( strcmp(exchange,"wallet") == 0 ) + walletitem = set_walletstr(0,walletstr,iQ); + else if ( strcmp(exchange,"pangea") == 0 && walletstr[0] == 0 && coin != 0 ) + walletitem = pangea_walletitem(0,coin,iQ->s.minperc,iQ->s.baseamount,iQ->s.relamount,iQ->s.minbuyin,iQ->s.maxbuyin); + else walletitem = 0; + if ( walletitem != 0 ) + { + jadd(json,"wallet",walletitem); + strcpy(walletstr,jprint(walletitem,0)); + } +//printf("exchange.(%s) iswallet.%d (%s) base.(%s) coin.%p (%s)\n",exchange,iQ->s.wallet,walletstr,base,coin,jprint(json,0)); + } else printf("InstantDEX_str cant find exchangeid.%d\n",iQ->exchangeid); +#endif + str = jprint(json,1); + strcpy(buf,str); + //printf("str.(%s) %p\n",buf,buf); + free(str); + } else printf("InstantDEX_str cant parse.(%s)\n",buf); + if ( buf == _buf ) + return(clonestr(buf)); + else return(buf); +} + +uint64_t _get_AEquote(char *str,uint64_t orderid) +{ + cJSON *json; + uint64_t nxt64bits = 0; + char cmd[256],*jsonstr; + sprintf(cmd,"requestType=get%sOrder&order=%llu",str,(long long)orderid); + if ( (jsonstr= issue_NXTPOST(cmd)) != 0 ) + { + //printf("(%s) -> (%s)\n",cmd,jsonstr); + if ( (json= cJSON_Parse(jsonstr)) != 0 ) + { + nxt64bits = get_API_nxt64bits(cJSON_GetObjectItem(json,"account")); + free_json(json); + } + free(jsonstr); + } + return(nxt64bits); +} + +char *cancel_NXTorderid(char *NXTaddr,char *nxtsecret,uint64_t orderid) +{ + uint64_t nxt64bits; char cmd[1025],secret[8192],*str = "Bid",*retstr = 0; + if ( (nxt64bits= _get_AEquote(str,orderid)) == 0 ) + str = "Ask", nxt64bits = _get_AEquote(str,orderid); + if ( nxt64bits == calc_nxt64bits(NXTaddr) ) + { + escape_code(secret,nxtsecret); + sprintf(cmd,"requestType=cancel%sOrder&secretPhrase=%s&feeNQT=%lld&deadline=%d&order=%llu",str,secret,(long long)MIN_NQTFEE,DEFAULT_NXT_DEADLINE,(long long)orderid); + retstr = issue_NXTPOST(cmd); + //printf("(%s) -> (%s)\n",cmd,retstr); + } + return(retstr); +} + +char *InstantDEX_cancelorder(cJSON *argjson,char *activenxt,char *secret,uint64_t orderid,uint64_t quoteid) +{ + struct InstantDEX_quote *iQ; cJSON *json,*array,*item; char numstr[64],*retstr,*exchangestr; + uint64_t quoteids[256]; int32_t i,exchangeid,n=0; struct exchange_info *exchange; + if ( (exchangestr= jstr(argjson,"exchange")) != 0 && (exchange= find_exchange(&exchangeid,exchangestr)) != 0 ) + { + if ( exchange->issue.cancelorder != 0 ) + { + if ( (retstr= (*exchange->issue.cancelorder)(&exchange->cHandle,exchange,argjson,quoteid)) == 0 ) + retstr = clonestr("{\"result\":\"nothing returned from exchange\"}"); + return(retstr); + } + else return(clonestr("{\"error\":\"no cancelorder function\"}")); + } + memset(quoteids,0,sizeof(quoteids)); + json = cJSON_CreateObject(), array = cJSON_CreateArray(); + if ( quoteid != 0 ) + quoteids[n++] = quoteid; + //n += InstantDEX_quoteids(quoteids+n,orderid); + for (i=0; is.offerNXT == calc_nxt64bits(activenxt) ) + cancel_InstantDEX_quote(iQ); + if ( (item= cJSON_Parse(retstr)) != 0 ) + jaddi(array,item); + free(retstr); + } + cancelquote(activenxt,quoteid); + } + if ( orderid != 0 ) + { + if ( cancelquote(activenxt,orderid) != 0 ) + sprintf(numstr,"%llu",(long long)orderid), jaddstr(json,"ordercanceled",numstr); + } + return(jprint(json,1)); +} + +char *InstantDEX_orderstatus(cJSON *argjson,uint64_t orderid,uint64_t quoteid) +{ + struct InstantDEX_quote *iQ = 0; char *exchangestr,*str; struct exchange_info *exchange; int32_t exchangeid; + if ( (exchangestr= jstr(argjson,"exchange")) != 0 && (exchange= find_exchange(&exchangeid,exchangestr)) != 0 ) + { + if ( exchange->issue.orderstatus != 0 ) + { + if ( (str= (*exchange->issue.orderstatus)(&exchange->cHandle,exchange,argjson,quoteid)) == 0 ) + str = clonestr("{\"result\":\"nothing returned from exchange\"}"); + return(str); + } + else return(clonestr("{\"error\":\"no orderstatus function\"}")); + } + if ( (iQ= find_iQ(orderid)) != 0 || (iQ= find_iQ(quoteid)) != 0 ) + return(InstantDEX_str(0,0,0,iQ)); + return(clonestr("{\"error\":\"couldnt find orderid\"}")); +} + +char *InstantDEX_openorders(cJSON *argjson,char *NXTaddr,int32_t allorders) +{ + struct InstantDEX_quote *iQ,*tmp; char buf[4096],*exchangestr,*jsonstr,*str; uint32_t now,duration; + cJSON *json,*array,*item; uint64_t nxt64bits; struct exchange_info *exchange; int32_t exchangeid; + if ( (exchangestr= jstr(argjson,"exchange")) != 0 && (exchange= find_exchange(&exchangeid,exchangestr)) != 0 ) + { + if ( exchange->issue.openorders != 0 ) + { + if ( (str= (*exchange->issue.openorders)(&exchange->cHandle,exchange,argjson)) == 0 ) + str = clonestr("{\"result\":\"nothing returned from exchange\"}"); + return(str); + } + else return(clonestr("{\"error\":\"no orderstatus function\"}")); + } + nxt64bits = calc_nxt64bits(NXTaddr); + now = (uint32_t)time(NULL); + json = cJSON_CreateObject(), array = cJSON_CreateArray(); + HASH_ITER(hh,AllQuotes,iQ,tmp) + { + if ( (duration= iQ->s.duration) == 0 ) + duration = ORDERBOOK_EXPIRATION; + if ( iQ->s.timestamp > (now + duration) ) + iQ->s.expired = iQ->s.closed = 1; + if ( iQ->s.offerNXT == nxt64bits && (allorders != 0 || iQ->s.closed == 0) ) + { + if ( (jsonstr= InstantDEX_str(0,buf,0,iQ)) != 0 && (item= cJSON_Parse(jsonstr)) != 0 ) + jaddi(array,item); + } + } + jadd(json,"openorders",array); + return(jprint(json,1)); +} + +cJSON *InstantDEX_specialorders(uint64_t *quoteidp,uint64_t nxt64bits,char *base,char *special,uint64_t baseamount,int32_t addrtype) +{ + struct InstantDEX_quote *iQ,*tmp; int32_t exchangeid; uint32_t i,n,now,duration,ismine = 0; + uint64_t basebits; cJSON *item=0,*array = 0; char *coinaddr=0,*pubkey,checkaddr[128]; + now = (uint32_t)time(NULL); + basebits = stringbits(base); + if ( special == 0 || find_exchange(&exchangeid,special) == 0 ) + exchangeid = 0; + n = 0; + *quoteidp = 0; + HASH_ITER(hh,AllQuotes,iQ,tmp) + { + //printf("iter Q.%llu b.%llu\n",(long long)iQ->s.quoteid,(long long)iQ->s.basebits); + if ( (duration= iQ->s.duration) == 0 ) + duration = ORDERBOOK_EXPIRATION; + if ( iQ->s.timestamp > (now + duration) ) + { + iQ->s.expired = iQ->s.closed = 1; + printf("expire order %llu\n",(long long)iQ->s.quoteid); + continue; + } + if ( iQ->s.basebits == basebits && (exchangeid == 0 || iQ->exchangeid == exchangeid) ) + { + //printf("matched basebits\n"); + if ( strcmp(special,"pangea") == 0 ) + { + checkaddr[0] = 0; + if ( iQ->s.wallet != 0 && (item= cJSON_Parse(iQ->walletstr)) != 0 && (coinaddr= jstr(item,"coinaddr")) != 0 && coinaddr[0] != 0 && (pubkey= jstr(item,"pubkey")) != 0 && pubkey[0] != 0 ) + btc_coinaddr(coinaddr,addrtype,pubkey); + if ( item != 0 ) + free_json(item); + if ( coinaddr == 0 || strcmp(coinaddr,checkaddr) != 0 ) + { + printf("mismatched pangea coinaddr (%s) vs (%s) or baseamount %.8f vs %.8f\n",coinaddr,checkaddr,dstr(baseamount),dstr(iQ->s.baseamount)); + continue; + } + } + if ( n > 0 ) + { + for (i=0; is.offerNXT == j64bits(jitem(array,i),0) ) + break; + } + //printf("found duplicate\n"); + } else i = 0; + if ( i == n ) + { + if ( iQ->s.offerNXT == nxt64bits ) + { + ismine = 1; + if ( *quoteidp == 0 ) + *quoteidp = iQ->s.quoteid; + } + if ( array == 0 ) + array = cJSON_CreateArray(); + jaddi64bits(array,iQ->s.offerNXT); + //printf("add %llu\n",(long long)iQ->s.offerNXT); + } + } //else printf("quote.%llu basebits.%llu\n",(long long)iQ->s.quoteid,(long long)iQ->s.basebits); + } + if ( ismine == 0 ) + free_json(array), array = 0; + //printf("ismine.%d n.%d array.%d\n",ismine,n,array==0?0:cJSON_GetArraySize(array)); + return(array); +} + +int _decreasing_quotes(const void *a,const void *b) +{ +#define order_a ((struct InstantDEX_quote *)a) +#define order_b ((struct InstantDEX_quote *)b) + if ( order_b->s.price > order_a->s.price ) + return(1); + else if ( order_b->s.price < order_a->s.price ) + return(-1); + return(0); +#undef order_a +#undef order_b +} + +int _increasing_quotes(const void *a,const void *b) +{ +#define order_a ((struct InstantDEX_quote *)a) +#define order_b ((struct InstantDEX_quote *)b) + if ( order_b->s.price > order_a->s.price ) + return(-1); + else if ( order_b->s.price < order_a->s.price ) + return(1); + return(0); +#undef order_a +#undef order_b +} + +cJSON *prices777_orderjson(struct InstantDEX_quote *iQ) +{ + cJSON *item = cJSON_CreateArray(); + jaddinum(item,iQ->s.price); + jaddinum(item,iQ->s.vol); + jaddi64bits(item,iQ->s.quoteid); + return(item); +} + +cJSON *InstantDEX_orderbook(struct prices777 *prices) +{ + struct InstantDEX_quote *ptr,iQ,*tmp,*askvals=0,*bidvals=0; cJSON *json,*bids,*asks; uint32_t now,duration; + int32_t i,isask,iter,n,m,numbids,numasks,invert; + json = cJSON_CreateObject(), bids = cJSON_CreateArray(), asks = cJSON_CreateArray(); + now = (uint32_t)time(NULL); + for (iter=numbids=numasks=n=m=0; iter<2; iter++) + { + HASH_ITER(hh,AllQuotes,ptr,tmp) + { + iQ = *ptr; + if ( (duration= iQ.s.duration) == 0 ) + duration = ORDERBOOK_EXPIRATION; + if ( iQ.s.timestamp > (now + duration) ) + { + iQ.s.expired = iQ.s.closed = 1; + continue; + } + if ( Debuglevel > 2 ) + printf("iterate quote.%llu\n",(long long)iQ.s.quoteid); + if ( prices777_equiv(ptr->s.baseid) == prices777_equiv(prices->baseid) && prices777_equiv(ptr->s.relid) == prices777_equiv(prices->relid) ) + invert = 0; + else if ( prices777_equiv(ptr->s.relid) == prices777_equiv(prices->baseid) && prices777_equiv(ptr->s.baseid) == prices777_equiv(prices->relid) ) + invert = 1; + else continue; + if ( ptr->s.pending != 0 ) + continue; + isask = iQ.s.isask; + if ( invert != 0 ) + isask ^= 1; + if ( invert != 0 ) + { + if ( iQ.s.price > SMALLVAL ) + iQ.s.vol *= iQ.s.price, iQ.s.price = 1. / iQ.s.price; + else iQ.s.price = prices777_price_volume(&iQ.s.vol,iQ.s.relamount,iQ.s.baseamount); + } + else if ( iQ.s.price <= SMALLVAL ) + iQ.s.price = prices777_price_volume(&iQ.s.vol,iQ.s.baseamount,iQ.s.relamount); + if ( iter == 0 ) + { + if ( isask != 0 ) + numasks++; + else numbids++; + } + else + { + if ( isask == 0 && n < numbids ) + bidvals[n++] = iQ; + else if ( isask != 0 && m < numasks ) + askvals[m++] = iQ; + } + } + if ( iter == 0 ) + { + if ( numbids > 0 ) + bidvals = calloc(numbids,sizeof(*bidvals)); + if ( numasks > 0 ) + askvals = calloc(numasks,sizeof(*askvals)); + } + } + if ( numbids > 0 ) + { + if ( n > 0 ) + { + qsort(bidvals,n,sizeof(*bidvals),_decreasing_quotes); + for (i=0; i 0 ) + { + if ( m > 0 ) + { + qsort(askvals,m,sizeof(*askvals),_increasing_quotes); + for (i=0; i (refvol * INSTANTDEX_MINVOLPERC) )//&& refvol > (vol * iQ->s.minperc * .01) ) + { + if ( vol < refvol ) + metric = (vol / refvol); + else metric = 1.; + if ( dir > 0 && price < (refprice * (1. + INSTANTDEX_PRICESLIPPAGE) + SMALLVAL) ) + metric *= (1. + (refprice - price)/refprice); + else if ( dir < 0 && price > (refprice * (1. - INSTANTDEX_PRICESLIPPAGE) - SMALLVAL) ) + metric *= (1. + (price - refprice)/refprice); + else metric = 0.; + if ( metric != 0. ) + { + printf("price %.8f vol %.8f | %.8f > %.8f? %.8f > %.8f?\n",price,vol,vol,(refvol * INSTANTDEX_MINVOLPERC),refvol,(vol * INSTANTDEX_MINVOLPERC)); + printf("price %f against %f or %f\n",price,(refprice * (1. + INSTANTDEX_PRICESLIPPAGE) + SMALLVAL),(refprice * (1. - INSTANTDEX_PRICESLIPPAGE) - SMALLVAL)); + printf("metric %f\n",metric); + } + } + return(metric); +} + +char *autofill(char *remoteaddr,struct InstantDEX_quote *refiQ,char *NXTaddr,char *NXTACCTSECRET) +{ + double price,volume,revprice,revvol,metric,bestmetric = 0.; int32_t dir,inverted; uint64_t nxt64bits; char *retstr=0; + struct InstantDEX_quote *iQ,*tmp,*bestiQ; struct prices777 *prices; uint32_t duration,now = (uint32_t)time(NULL); +return(0); + nxt64bits = calc_nxt64bits(NXTaddr); + memset(&bestiQ,0,sizeof(bestiQ)); + dir = (refiQ->s.isask != 0) ? -1 : 1; + HASH_ITER(hh,AllQuotes,iQ,tmp) + { + if ( (duration= refiQ->s.duration) == 0 ) + duration = ORDERBOOK_EXPIRATION; + if ( iQ->s.timestamp > (now + duration) ) + iQ->s.expired = iQ->s.closed = 1; + if ( iQ->s.offerNXT == nxt64bits && iQ->s.closed == 0 && iQ->s.pending == 0 ) + { + if ( iQ->s.baseid == refiQ->s.baseid && iQ->s.relid == refiQ->s.relid && iQ->s.isask != refiQ->s.isask && (metric= ordermetric(iQ->s.price,iQ->s.vol,dir,refiQ->s.price,refiQ->s.vol)) > bestmetric ) + { + bestmetric = metric; + bestiQ = iQ; + } + else if ( iQ->s.baseid == refiQ->s.relid && iQ->s.relid == refiQ->s.baseid && iQ->s.isask == refiQ->s.isask && iQ->s.price > SMALLVAL ) + { + revvol = (iQ->s.price * iQ->s.vol), revprice = (1. / iQ->s.price); + if ( (metric= ordermetric(revprice,revvol,dir,refiQ->s.price,refiQ->s.vol)) > bestmetric ) + { + bestmetric = metric; + bestiQ = iQ; + } + } + } + } + if ( bestmetric > 0. ) + { + if ( (prices= prices777_find(&inverted,bestiQ->s.baseid,bestiQ->s.relid,exchange_str(bestiQ->exchangeid))) != 0 ) + { + printf("isask.%d %f %f -> bestmetric %f inverted.%d autofill dir.%d price %f vol %f\n",bestiQ->s.isask,bestiQ->s.price,bestiQ->s.vol,bestmetric,inverted,dir,refiQ->s.price,refiQ->s.vol); + if ( bestiQ->s.isask != 0 ) + dir = -1; + else dir = 1; + if ( inverted != 0 ) + { + dir *= -1; + volume = (bestiQ->s.price * bestiQ->s.vol); + price = 1. / bestiQ->s.price; + printf("price inverted (%f %f) -> (%f %f)\n",bestiQ->s.price,bestiQ->s.vol,price,volume); + } else price = bestiQ->s.price, volume = bestiQ->s.vol; + retstr = prices777_trade(0,0,0,0,1,0,NXTaddr,NXTACCTSECRET,prices,dir,price,volume,bestiQ,0,bestiQ->s.quoteid,0); + } + } + return(retstr); +} + +char *automatch(struct prices777 *prices,int32_t dir,double refprice,double refvol,char *NXTaddr,char *NXTACCTSECRET) +{ + int32_t i,n=0; struct prices777_order order,bestorder; char *retstr = 0; double metric,bestmetric = 0.; +return(0); + memset(&bestorder,0,sizeof(bestorder)); + if ( dir > 0 ) + n = prices->O.numasks; + else if ( dir < 0 ) + n = prices->O.numbids; + if ( n > 0 ) + { + for (i=0; i 0) ? prices->O.book[MAX_GROUPS][i].ask : prices->O.book[MAX_GROUPS][i].bid; + if ( (metric= ordermetric(order.s.price,order.s.vol,dir,refprice,refvol)) > bestmetric ) + { + bestmetric = metric; + bestorder = order; + } + } + } + //printf("n.%d\n",n); + if ( bestorder.source != 0 ) + retstr = prices777_trade(0,0,0,0,1,0,NXTaddr,NXTACCTSECRET,bestorder.source,bestorder.s.isask!=0?-1:1,bestorder.s.price,bestorder.s.vol,0,&bestorder,bestorder.s.quoteid,0); + return(retstr); +} + +int offer_checkitem(struct pending_trade *pend,cJSON *item) +{ + uint64_t quoteid; struct InstantDEX_quote *iQ; + if ( (quoteid= j64bits(item,"quoteid")) != 0 && (iQ= find_iQ(quoteid)) != 0 && iQ->s.closed != 0 ) + return(0); + return(-1); +} + +void trades_update() +{ +#ifdef later + int32_t iter; struct pending_trade *pend; + for (iter=0; iter<2; iter++) + { + while ( (pend= queue_dequeue(&Pending_offersQ.pingpong[iter],0)) != 0 ) + { + if ( time(NULL) > pend->expiration ) + { + printf("now.%ld vs timestamp.%u vs expiration %u | ",(long)time(NULL),pend->timestamp,pend->expiration); + printf("offer_statemachine %llu/%llu %d %f %f\n",(long long)pend->orderid,(long long)pend->quoteid,pend->dir,pend->price,pend->volume); + //InstantDEX_history(1,pend,retstr); + if ( pend->bot == 0 ) + free_pending(pend); + else pend->finishtime = (uint32_t)time(NULL); + } + else + { + printf("InstantDEX_update requeue %llu/%llu %d %f %f\n",(long long)pend->orderid,(long long)pend->quoteid,pend->dir,pend->price,pend->volume); + queue_enqueue("requeue",&Pending_offersQ.pingpong[iter ^ 1],&pend->DL,0); + } + } + } +#endif +} + +void InstantDEX_update(char *NXTaddr,char *NXTACCTSECRET) +{ + int32_t dir; double price,volume; uint32_t now; char *retstr = 0; + int32_t inverted; struct InstantDEX_quote *iQ,*tmp; struct prices777 *prices; uint64_t nxt64bits = calc_nxt64bits(NXTaddr); + now = (uint32_t)time(NULL); + HASH_ITER(hh,AllQuotes,iQ,tmp) + { + if ( iQ->s.timestamp > (now + ORDERBOOK_EXPIRATION) ) + iQ->s.expired = iQ->s.closed = 1; + if ( iQ->s.offerNXT == nxt64bits && iQ->s.closed == 0 && iQ->s.pending == 0 ) + { + if ( (prices= prices777_find(&inverted,iQ->s.baseid,iQ->s.relid,exchange_str(iQ->exchangeid))) != 0 ) + { + if ( iQ->s.isask != 0 ) + dir = -1; + else dir = 1; + if ( inverted != 0 ) + { + dir *= -1; + volume = (iQ->s.price * iQ->s.vol); + price = 1. / iQ->s.price; + printf("price inverted (%f %f) -> (%f %f)\n",iQ->s.price,iQ->s.vol,price,volume); + } else price = iQ->s.price, volume = iQ->s.vol; + if ( (retstr= automatch(prices,dir,price,volume,NXTaddr,NXTACCTSECRET)) != 0 ) + { + printf("automatched %s isask.%d %f %f (%s)\n",prices->contract,iQ->s.isask,iQ->s.price,iQ->s.vol,retstr); + free(retstr); + } + } + } + } + trades_update(); +} + +int32_t is_specialexchange(char *exchangestr) +{ + if ( strcmp(exchangestr,"InstantDEX") == 0 || strcmp(exchangestr,"jumblr") == 0 || strcmp(exchangestr,"pangea") == 0 || strcmp(exchangestr,"peggy") == 0 || strcmp(exchangestr,"wallet") == 0 || strcmp(exchangestr,"active") == 0 || strncmp(exchangestr,"basket",strlen("basket")) == 0 ) + return(1); + return(0); +} + +char *InstantDEX_placebidask(char *remoteaddr,uint64_t orderid,char *exchangestr,char *name,char *base,char *rel,struct InstantDEX_quote *iQ,char *extra,char *secret,char *activenxt,cJSON *origjson) +{ + struct exchange_info *exchange; cJSON *obj; + char walletstr[256],*str,*retstr = 0; int32_t inverted,dir; struct prices777 *prices; double price,volume; + if ( secret == 0 || activenxt == 0 ) + { + secret = IGUANA_NXTACCTSECRET; + activenxt = IGUANA_NXTADDR; + } +//printf("placebidask.(%s)\n",jprint(origjson,0)); + if ( (obj= jobj(origjson,"wallet")) != 0 ) + { + str = jprint(obj,1); + safecopy(walletstr,str,sizeof(walletstr)); + free(str), str = 0; + } + else walletstr[0] = 0; + if ( exchangestr != 0 && (exchange= exchange_find(exchangestr)) != 0 ) + iQ->exchangeid = exchange->exchangeid; + if ( iQ->exchangeid < 0 || (exchangestr= exchange_str(iQ->exchangeid)) == 0 ) + { + printf("exchangestr.%s id.%d\n",exchangestr,iQ->exchangeid); + return(clonestr("{\"error\":\"exchange not active, check SuperNET.conf exchanges array\"}\n")); + } + //printf("walletstr.(%s)\n",walletstr); + if ( (prices= prices777_find(&inverted,iQ->s.baseid,iQ->s.relid,exchangestr)) == 0 ) + prices = prices777_poll(exchangestr,name,base,iQ->s.baseid,rel,iQ->s.relid); + if ( prices != 0 ) + { + price = iQ->s.price, volume = iQ->s.vol; + if ( price < SMALLVAL || volume < SMALLVAL ) + { + printf("price %f volume %f error\n",price,volume); + return(clonestr("{\"error\":\"prices777_trade invalid price or volume\"}\n")); + } + if ( iQ->s.isask != 0 ) + dir = -1; + else dir = 1; + if ( inverted != 0 ) + { + dir *= -1; + volume *= price; + price = 1. / price; + printf("price inverted (%f %f) -> (%f %f)\n",iQ->s.price,iQ->s.vol,price,volume); + } +//printf("dir.%d price %f vol %f isask.%d remoteaddr.%p\n",dir,price,volume,iQ->s.isask,remoteaddr); + if ( remoteaddr == 0 ) + { + if ( is_specialexchange(exchangestr) == 0 ) + return(prices777_trade(0,0,0,0,1,0,activenxt,secret,prices,dir,price,volume,iQ,0,iQ->s.quoteid,extra)); + //printf("check automatch\n"); + //if ( strcmp(exchangestr,"wallet") != 0 && strcmp(exchangestr,"jumblr") != 0 && strcmp(exchangestr,"pangea") != 0 && iQ->s.automatch != 0 && (SUPERNET.automatch & 1) != 0 && (retstr= automatch(prices,dir,volume,price,activenxt,secret)) != 0 ) + // return(retstr); + if ( strcmp(IGUANA_NXTACCTSECRET,secret) != 0 ) + return(clonestr("{\"error\":\"cant do queued requests with non-default accounts\"}")); + retstr = InstantDEX_str(walletstr,0,1,iQ); + //printf("create_iQ.(%llu) quoteid.%llu walletstr.(%s) %p\n",(long long)iQ->s.offerNXT,(long long)iQ->s.quoteid,walletstr,walletstr); + iQ = create_iQ(iQ,walletstr); + printf("local got create_iQ.(%llu) quoteid.%llu wallet.(%s) baseamount %llu iswallet.%d\n",(long long)iQ->s.offerNXT,(long long)iQ->s.quoteid,walletstr,(long long)iQ->s.baseamount,iQ->s.wallet); + prices777_InstantDEX(prices,MAX_DEPTH); + queue_enqueue("InstantDEX",&InstantDEXQ,queueitem(retstr),0); + } + else + { + iQ = create_iQ(iQ,walletstr); + if ( (retstr= autofill(remoteaddr,iQ,activenxt,secret)) == 0 ) + { + //printf("create_iQ.(%llu) quoteid.%llu\n",(long long)iQ->s.offerNXT,(long long)iQ->s.quoteid); + if ( strcmp(IGUANA_NXTACCTSECRET,secret) != 0 ) + return(clonestr("{\"error\":\"cant do queued requests with non-default accounts\"}")); + prices777_InstantDEX(prices,MAX_DEPTH); + printf("remote got create_iQ.(%llu) quoteid.%llu wallet.(%s) baseamount %llu\n",(long long)iQ->s.offerNXT,(long long)iQ->s.quoteid,walletstr,(long long)iQ->s.baseamount); + } + return(retstr); + } + } else printf("cant find prices\n"); + if ( retstr == 0 ) + retstr = clonestr("{\"error\":\"cant get prices ptr\"}"); + return(retstr); +} + + +#endif +#endif diff --git a/iguana/InstantDEX/quotes777.c b/iguana/InstantDEX/quotes777.c new file mode 100755 index 000000000..36fd80d9f --- /dev/null +++ b/iguana/InstantDEX/quotes777.c @@ -0,0 +1,1016 @@ +/****************************************************************************** + * 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. * + * * + ******************************************************************************/ +#ifdef later + +#ifdef DEFINES_ONLY +#ifndef quotes777_h +#define quotes777_h + +#include +#include +#include +#include "../iguana777.h" +#include "serdes777.c" +#include "peggy777.c" + +#endif +#else +#ifndef quotes777_c +#define quotes777_c + +#ifndef quotes777_h +#define DEFINES_ONLY +#include "quotes777.c" +//#include "serdes777.c" +#undef DEFINES_ONLY +#endif + +//////////// must be consensus safe +#define PEGGY_GENESIS "6aef504158ec0014fee05dc20a0006048ed63e523f6d1062feb23622da928cf23ddcc3b53f23566bc6cab5ebd77cfbf8f0bccb34bff73c55d742dd232994bfbffe1cbab7119ab3d653a256b02d5b6f56c05b8817799f0d242f48c26d35c992ebfff14acdefbe253345d394e84d975334cd55f7d6cbad5a7bd9425b1d5db44944d40be5304b7b62ba0dbc20d3323d2b35f05f654bc95a5a2fdb5a30e46c6fd33b5ea078255f7cad9fd0dbd2fa5031ada4474cbba7b2ee64ef35df06bf3fd3eef6cd3f48339f3c0e080158a92862bbf20bc6702018effbaee525502eb463c74f7ca0dff4ae7cb55ee55ef7cb1c915e655649" + +//#define PEGGY_GENESIS "6aef504547ec00143e3028ba0a000604800d0560da5a55fbb56121b403e9dfbbd99f6b05c9af5683676bdda7f39636c579515174afebe5ad659c44567df9f02eb1dc5e30b4cc1a96a0dab18b2e55e5fd771032f2ee3d34de9313d9ea2813d70e6995a2fe7d7b2854a6032c9d022d676a9ae0ed573ab57e4887761a85688b20b417ad099686a67a2b82cca6104698a254c5ca5fe95ab874649513bae9e4bcbc7e868497c3a9d6da3ad82d625f12078d50c48a2e492bd6665e9f86e3fbe4bf6ee1758a9461fee35068851562b3b68082645c92a8f35a61a2de5652478b441fc53aa96aaf169feaedaef7bf1472fb3542ee04" +//#define PEGGY_GENESIS "6af2504547ef00147eb3ccb70a0006f49b65bed5a3b5f867565be8feb53b1c694b1bd8bcf1039696d8b968a7ae93168e745c6737fe9b6ab079152a3cabeee24e4d48f9ade6b1b41a39fc3abe2a5ae6f9254de6cbf679ad6e338cdfd7b1b4b1e2689c555648a4087cd94aa44869ab48a65b1295f6f75f8bf760a42966bbf2c1d8d6811379d17916e99abdb6c5246a2a192969f101ae3cc9679d98c5abedb64b6d9ea3a5ee485fe3ea467b77e5add9c1fa2d0d0dc781a5046b686b5c3bcdd91b8abb6ed33c8c556e05c4778b0e6b30bd6d6f41cc381d50e7f5a565bd64e78ff696de8a9517ee5ec79f531c594510abdd25ac44e62a" + +uint64_t peggy_smooth_coeffs[PEGGY_NUMCOEFFS] = // numprimes.13 +{ + 962714545, 962506087, 962158759, 961672710, 961048151, 960285354, 959384649, 958346426, 957171134, // x.8 + 955859283, 954411438, 952828225, 951110328, 949258485, 947273493, 945156207, 942907532, 940528434, // x.17 + 938019929, 935383089, 932619036, 929728945, 926714044, 923575608, 920314964, 916933485, 913432593, // x.26 + 909813756, 906078486, 902228342, 898264923, 894189872, 890004874, 885711650, 881311964, 876807614, // x.35 + 872200436, 867492300, 862685110, 857780804, 852781347, 847688737, 842505000, 837232189, 831872382, // x.44 + 826427681, 820900212, 815292123, 809605581, 803842772, 798005901, 792097186, 786118864, 780073180, // x.53 + 773962395, 767788778, 761554609, 755262175, 748913768, 742511686, 736058231, 729555707, 723006417, // x.62 + 716412665, 709776755, 703100984, 696387648, 689639036, 682857428, 676045100, 669204315, 662337327, // x.71 + 655446378, 648533696, 641601496, 634651978, 627687325, 620709702, 613721256, 606724115, 599720386, // x.80 + 592712154, 585701482, 578690411, 571680955, 564675105, 557674825, 550682053, 543698699, 536726645, // x.89 + 529767743, 522823816, 515896658, 508988029, 502099660, 495233249, 488390461, 481572928, 474782249, // x.98 + 468019988, 461287675, 454586804, 447918836, 441285195, 434687268, 428126409, 421603932, 415121117, // x.107 + 408679208, 402279408, 395922888, 389610779, 383344175, 377124134, 370951677, 364827785, 358753406, // x.116 + 352729449, 346756785, 340836251, 334968645, 329154729, 323395230, 317690838, 312042206, 306449955, // x.125 + 300914667, 295436891, 290017141, 284655897, 279353604, 274110676, 268927490, 263804394, 258741701, // x.134 + 253739694, 248798623, 243918709, 239100140, 234343077, 229647649, 225013957, 220442073, 215932043, // x.143 + 211483883, 207097585, 202773112, 198510404, 194309373, 190169909, 186091877, 182075118, 178119452, // x.152 + 174224676, 170390565, 166616873, 162903335, 159249664, 155655556, 152120688, 148644718, 145227287, // x.161 + 141868021, 138566528, 135322401, 132135218, 129004542, 125929924, 122910901, 119946997, 117037723, // x.170 + 114182582, 111381062, 108632643, 105936795, 103292978, 100700645, 98159238, 95668194, 93226942, // x.179 + 90834903, 88491495, 86196126, 83948203, 81747126, 79592292, 77483092, 75418916, 73399150, // x.188 + 71423178, 69490383, 67600142, 65751837, 63944844, 62178541, 60452305, 58765515, 57117547, // x.197 + 55507781, 53935597, 52400377, 50901505, 49438366, 48010349, 46616844, 45257246, 43930951, // x.206 + 42637360, 41375878, 40145912, 38946876, 37778185, 36639262, 35529533, 34448428, 33395384, // x.215 + 32369842, 31371249, 30399057, 29452725, 28531717, 27635503, 26763558, 25915365, 25090413, // x.224 + 24288196, 23508216, 22749980, 22013003, 21296806, 20600917, 19924870, 19268206, 18630475, // x.233 + 18011231, 17410035, 16826458, 16260073, 15710466, 15177224, 14659944, 14158231, 13671694, // x.242 + 13199950, 12742625, 12299348, 11869759, 11453500, 11050225, 10659590, 10281262, 9914910, // x.251 + 9560213, 9216856, 8884529, 8562931, 8251764, 7950739, 7659571, 7377984, 7105706, // x.260 + 6842471, 6588020, 6342099, 6104460, 5874861, 5653066, 5438844, 5231969, 5032221, // x.269 + 4839386, 4653254, 4473620, 4300287, 4133059, 3971747, 3816167, 3666139, 3521488, // x.278 + 3382043, 3247640, 3118115, 2993313, 2873079, 2757266, 2645728, 2538325, 2434919, // x.287 + 2335380, 2239575, 2147382, 2058677, 1973342, 1891262, 1812325, 1736424, 1663453, // x.296 + 1593311, 1525898, 1461118, 1398879, 1339091, 1281666, 1226519, 1173569, 1122736, // x.305 + 1073944, 1027117, 982185, 939076, 897725, 858065, 820033, 783568, 748612, // x.314 + 715108, 682999, 652233, 622759, 594527, 567488, 541597, 516808, 493079, // x.323 + 470368, 448635, 427841, 407948, 388921, 370725, 353326, 336692, 320792, // x.332 + 305596, 291075, 277202, 263950, 251292, 239204, 227663, 216646, 206130, // x.341 + 196094, 186517, 177381, 168667, 160356, 152430, 144874, 137671, 130806, // x.350 + 124264, 118031, 112093, 106437, 101050, 95921, 91039, 86391, 81968, // x.359 + 77759, 73755, 69945, 66322, 62877, 59602, 56488, 53528, 50716, // x.368 + 48043, 45505, 43093, 40803, 38629, 36564, 34604, 32745, 30980, // x.377 + 29305, 27717, 26211, 24782, 23428, 22144, 20927, 19774, 18681, // x.386 + 17646, 16665, 15737, 14857, 14025, 13237, 12491, 11786, 11118, // x.395 + 10487, 9890, 9325, 8791, 8287, 7810, 7359, 6933, 6531, // x.404 + 6151, 5792, 5453, 5133, 4831, 4547, 4278, 4024, 3785, // x.413 + 3560, 3347, 3147, 2958, 2779, 2612, 2454, 2305, 2164, // x.422 + 2032, 1908, 1791, 1681, 1577, 1480, 1388, 1302, 1221, // x.431 + 1145, 1073, 1006, 942, 883, 827, 775, 725, 679, // x.440 + 636, 595, 557, 521, 487, 456, 426, 399, 373, // x.449 + 348, 325, 304, 284, 265, 248, 231, 216, 202, // x.458 + 188, 175, 164, 153, 142, 133, 124, 115, 107, // x.467 + 100, 93, 87, 81, 75, 70, 65, 61, 56, // x.476 + 53, 49, 45, 42, 39, 36, 34, 31, 29, // x.485 + 27, 25, 23, 22, 20, 19, 17, 16, 15, // x.494 + 14, 13, 12, 11, 10, 9, 9, 8, 7, // x.503 + 7, 6, 6, 5, 5, 5, 4, 4, 4, // x.512 + 3, 3, 3, 3, 2, 2, 2, 2, 2, // x.521 + 2, 2, 1, 1, 1, 1, 1, 1, 1, // x.530 + 1, 1, 1, 1, 1, 1, 0, 0, // isum 100000000000 +}; + +int32_t Peggy_inds[539] = {289, 404, 50, 490, 59, 208, 87, 508, 366, 288, 13, 38, 159, 440, 120, 480, 361, 104, 534, 195, 300, 362, 489, 108, 143, 220, 131, 244, 133, 473, 315, 439, 210, 456, 219, 352, 153, 444, 397, 491, 286, 479, 519, 384, 126, 369, 155, 427, 373, 360, 135, 297, 256, 506, 322, 425, 501, 251, 75, 18, 420, 537, 443, 438, 407, 145, 173, 78, 340, 240, 422, 160, 329, 32, 127, 128, 415, 495, 372, 522, 60, 238, 129, 364, 471, 140, 171, 215, 378, 292, 432, 526, 252, 389, 459, 350, 233, 408, 433, 51, 423, 19, 62, 115, 211, 22, 247, 197, 530, 7, 492, 5, 53, 318, 313, 283, 169, 464, 224, 282, 514, 385, 228, 175, 494, 237, 446, 105, 150, 338, 346, 510, 6, 348, 89, 63, 536, 442, 414, 209, 216, 227, 380, 72, 319, 259, 305, 334, 236, 103, 400, 176, 267, 355, 429, 134, 257, 527, 111, 287, 386, 15, 392, 535, 405, 23, 447, 399, 291, 112, 74, 36, 435, 434, 330, 520, 335, 201, 478, 17, 162, 483, 33, 130, 436, 395, 93, 298, 498, 511, 66, 487, 218, 65, 309, 419, 48, 214, 377, 409, 462, 139, 349, 4, 513, 497, 394, 170, 307, 241, 185, 454, 29, 367, 465, 194, 398, 301, 229, 212, 477, 303, 39, 524, 451, 116, 532, 30, 344, 85, 186, 202, 517, 531, 515, 230, 331, 466, 147, 426, 234, 304, 64, 100, 416, 336, 199, 383, 200, 166, 258, 95, 188, 246, 136, 90, 68, 45, 312, 354, 184, 314, 518, 326, 401, 269, 217, 512, 81, 88, 272, 14, 413, 328, 393, 198, 226, 381, 161, 474, 353, 337, 294, 295, 302, 505, 137, 207, 249, 46, 98, 27, 458, 482, 262, 253, 71, 25, 0, 40, 525, 122, 341, 107, 80, 165, 243, 168, 250, 375, 151, 503, 124, 52, 343, 371, 206, 178, 528, 232, 424, 163, 273, 191, 149, 493, 177, 144, 193, 388, 1, 412, 265, 457, 255, 475, 223, 41, 430, 76, 102, 132, 96, 97, 316, 472, 213, 263, 3, 317, 324, 274, 396, 486, 254, 205, 285, 101, 21, 279, 58, 467, 271, 92, 538, 516, 235, 332, 117, 500, 529, 113, 445, 390, 358, 79, 34, 488, 245, 83, 509, 203, 476, 496, 347, 280, 12, 84, 485, 323, 452, 10, 146, 391, 293, 86, 94, 523, 299, 91, 164, 363, 402, 110, 321, 181, 138, 192, 469, 351, 276, 308, 277, 428, 182, 260, 55, 152, 157, 382, 121, 507, 225, 61, 431, 31, 106, 327, 154, 16, 49, 499, 73, 70, 449, 460, 187, 24, 248, 311, 275, 158, 387, 125, 67, 284, 35, 463, 190, 179, 266, 376, 221, 42, 26, 290, 357, 268, 43, 167, 99, 374, 242, 156, 239, 403, 339, 183, 320, 180, 306, 379, 441, 20, 481, 141, 77, 484, 69, 410, 502, 172, 417, 118, 461, 261, 47, 333, 450, 296, 453, 368, 359, 437, 421, 264, 504, 281, 270, 114, 278, 56, 406, 448, 411, 521, 418, 470, 123, 455, 148, 356, 468, 109, 204, 533, 365, 8, 345, 174, 370, 28, 57, 11, 2, 231, 310, 196, 119, 82, 325, 44, 342, 37, 189, 142, 222, 9, 54, }; + +char *peggy_contracts[64] = +{ + "BTCD", "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", + "BTCUSD", "NXTBTC", "SuperNET", "ETHBTC", "LTCBTC", "XMRBTC", "BTSBTC", "XCPBTC", // BTC priced + "XAUUSD", "XAGUSD", "XPTUSD", "XPDUSD", "Copper", "NGAS", "UKOil", "USOil", // USD priced + "Bund", "NAS100", "SPX500", "US30", "EUSTX50", "UK100", "JPN225", "GER30", "SUI30", "AUS200", "HKG33", "XAUUSD", "BTCRUB", "BTCCNY", "BTCUSD" // abstract +}; + +uint32_t peggy_mils(int32_t i) +{ + uint32_t minmils = 0; + if ( i == 0 ) + return(1000000); + else if ( i <= 32 ) + minmils = 10 * prices777_mindenomination(i-1); + else if ( i >= 64 ) + return(10000); + else if ( peggy_contracts[i] != 0 ) + { + if ( is_decimalstr(peggy_contracts[i]+strlen(peggy_contracts[i])-2) != 0 || strcmp(peggy_contracts[i],"BTCRUB") == 0 ) + minmils = 1; + else if ( strncmp(peggy_contracts[i],"XAU",3) == 0 || strcmp(peggy_contracts[i],"BTCCNY") == 0 || strcmp(peggy_contracts[i],"BTCUSD") == 0 || strncmp(peggy_contracts[i],"XPD",3) == 0 || strncmp(peggy_contracts[i],"XPT",3) == 0 ) + minmils = 10; + else if ( strcmp(peggy_contracts[i],"Bund") == 0 || strcmp(peggy_contracts[i],"UKOil") == 0 || strcmp(peggy_contracts[i],"USOil") == 0 ) + minmils = 100; + else if ( strncmp(peggy_contracts[i],"LTC",3) == 0 || strcmp(peggy_contracts[i],"SuperNET") == 0 || strncmp(peggy_contracts[i],"XAG",3) == 0 || strncmp(peggy_contracts[i],"ETH",3) == 0 || strncmp(peggy_contracts[i],"XCP",3) == 0 ) + minmils = 1000; + else if ( strncmp(peggy_contracts[i],"XMR",3) == 0 ) + minmils = 10000; + else if ( strncmp(peggy_contracts[i],"NXT",3) == 0 || strncmp(peggy_contracts[i],"BTS",3) == 0 ) + minmils = 1000000; + else if ( strncmp(peggy_contracts[i],"DOGE",3) == 0 ) + minmils = 100000000; + else minmils = 10000; + } + return(minmils); +} + +int32_t peggy_setprice(struct peggy *PEG,struct price_resolution price,int32_t minute) +{ + if ( PEG->name.hasprice != 0 ) + { + if ( price.Pval > PRICE_RESOLUTION_MAXPVAL ) + { + printf("peggy_setdayprice clip.%lld with %lld\n",(long long)price.Pval,(long long)PRICE_RESOLUTION_MAXPVAL); + price.Pval = PRICE_RESOLUTION_MAXPVAL; + } + else if ( price.Pval <= 0 ) + { + printf("peggy_setdayprice illegal negative of zeroprice %lld %s\n",(long long)price.Pval,PEG->name.name); + price.Pval = 0; + } + if ( PEG->baseprices[minute] != 0 ) + price.Pval = (uint32_t)(price.Pval + PEG->baseprices[minute]) >> 1; + else if ( minute > PEG->RTminute ) + PEG->RTminute = minute; + PEG->baseprices[minute] = (uint32_t)price.Pval; + while ( --minute > 0 && PEG->baseprices[minute] == 0 ) + PEG->baseprices[minute] = (uint32_t)price.Pval; + } + return(minute); +} + +struct price_resolution peggy_shortprice(struct peggy *PEG,struct price_resolution price) +{ + struct price_resolution shortprice; + memset(&shortprice,0,sizeof(shortprice)); + if ( price.Pval != 0 ) + shortprice.Pval = ((PRICE_RESOLUTION * PEG->genesisprice.Pval) / price.Pval); + return(shortprice); +} + +struct price_resolution peggy_price(struct peggy *PEG,int32_t minute) +{ + struct price_resolution relprice,price; + memset(&price,0,sizeof(price)); + if ( minute == PEG->RTminute ) + minute--; + while ( (price.Pval= PEG->baseprices[minute]) == 0 && minute >= 0 ) + minute--; + if ( PEG->name.hasprice == 0 ) + { + relprice.Pval = PEG->relprices[minute]; + if ( relprice.Pval != 0 ) + { + if ( price.Pval < PRICE_RESOLUTION_MAXPVAL ) + price.Pval = (PRICE_RESOLUTION * price.Pval) / relprice.Pval; + else price.Pval = PRICE_RESOLUTION_ROOT * ((PRICE_RESOLUTION_ROOT * price.Pval) / relprice.Pval); + } else price.Pval = 0; + } + return(price); +} + +struct price_resolution peggy_aveprice(struct peggy *PEG,int32_t day,int32_t width) +{ + int32_t i,n; struct price_resolution price,aveprice; + aveprice.Pval = 0; + for (i=n=0; idayprices[day]; + if ( price.Pval != 0 ) + aveprice.Pval += price.Pval, n++; + } + if ( n != 0 ) + aveprice.Pval /= n; + return(aveprice); +} + +// init time +void peggy_descriptions(struct peggy_info *PEGS,struct peggy_description *P,char *name,char *base,char *rel) +{ + int32_t emptyslot; + strcpy(P->name,name), strcpy(P->base,base); + if ( rel != 0 ) + strcpy(P->rel,rel); + P->assetbits = peggy_assetbits(name), P->basebits = stringbits(base), P->relbits = stringbits(P->rel); + P->baseid = add_uint64(PEGS->basebits,sizeof(PEGS->basebits)/sizeof(*PEGS->basebits),P->basebits); + P->relid = add_uint64(PEGS->basebits,sizeof(PEGS->basebits)/sizeof(*PEGS->basebits),P->relbits); + if ( find_uint64(&emptyslot,PEGS->basebits,sizeof(PEGS->basebits)/sizeof(*PEGS->basebits),P->basebits) != P->baseid ) + printf("(%s) (%s) (%s) error cant find baseid.%d for %llx\n",name,base,P->rel,P->baseid,(long long)P->basebits); + if ( P->relbits != 0 && find_uint64(&emptyslot,PEGS->basebits,sizeof(PEGS->basebits)/sizeof(*PEGS->basebits),P->relbits) != P->relid ) + printf("(%s) (%s) (%s) error cant find relid.%d for %llx\n",name,base,P->rel,P->relid,(long long)P->relbits); +} + +/*int32_t peggy_timeframes(struct peggy_limits *limits,int64_t *scales,uint32_t *timeframes,int32_t numtimeframes,uint64_t maxsupply,uint64_t maxnetbalance) +{ + int32_t i; + memset(limits,0,sizeof(*limits)); + limits->maxsupply = maxsupply, limits->maxnetbalance = maxnetbalance; + if ( limits->maxsupply < 0 || limits->maxnetbalance < 0 ) + { + printf("peggy_check_limits: maxnetbalance %lld > %d\n",(long long)limits->maxnetbalance,(int32_t)PRICE_RESOLUTION); + return(-1); + } + limits->numtimeframes = (numtimeframes <= MAX_TIMEFRAMES) ? numtimeframes : MAX_TIMEFRAMES; + for (i=0; inumtimeframes; i++) + { + limits->scales[i] = scales[i]; + if ( (limits->timeframes[i]= PEGGY_DAYTICKS * timeframes[i]) > MAX_TIMEFRAME || (i > 0 && limits->timeframes[i] <= limits->timeframes[i-1]) ) + { + printf("createpeg: illegal timeframe.%d: %d %d vs %d\n",i,timeframes[i],limits->timeframes[i],MAX_TIMEFRAME); + getchar(); return(-1); + } + } + limits->timeframes[0] = 0; + return(0); +}*/ + +int32_t peggy_lockparms(struct peggy_lock *dest,int32_t peg,struct peggy_lock *lockparms) +{ + if ( lockparms->minlockdays > lockparms->maxlockdays ) + { + printf("peggy_check_lockparms: minlockdays %d > %d maxlockdays\n",lockparms->minlockdays,lockparms->maxlockdays); + return(-1); + } + if ( lockparms->mixrange == 0 ) + lockparms->mixrange = PEGGY_MIXRANGE; + if ( lockparms->extralockdays < PEGGY_MINEXTRADAYS * 2 ) + lockparms->extralockdays = PEGGY_MINEXTRADAYS * 2; + *dest = *lockparms, dest->peg = peg; + return(0); +} + +int32_t peggy_setvars(struct peggy_info *PEGS,struct peggy *PEG,int16_t baseid,int16_t relid,int32_t peg,uint64_t maxsupply,uint64_t maxnetbalance,struct peggy_lock *lockparms,uint32_t unitincr,int32_t dailyrate,struct price_resolution *initialprices,int32_t numprices,int32_t hasprice) +{ + int32_t i; + PEG->name.id = peg, PEG->name.hasprice = hasprice; + //if ( peggy_timeframes(&PEG->limits,limits->scales,limits->timeframes,limits->numtimeframes,limits->maxsupply,limits->maxnetbalance) < 0 ) + // return(-1); + if ( peggy_lockparms(&PEG->lockparms,peg,lockparms) < 0 ) + return(-1); + PEG->unitincr = unitincr; + PEG->maxdailyrate = dailyrate; + PEG->maxsupply = maxsupply, PEG->maxnetbalance = maxnetbalance; + + if ( initialprices != 0 ) + { + if ( numprices > 0 ) + { + //if ( initialprices[0].Pval >= PRICE_RESOLUTION_MAXPVAL ) + // initialprices[0].Pval = PRICE_RESOLUTION_MAXPVAL; + PEG->genesisprice = PEG->dayprice = PEG->price = initialprices[0]; + for (i=0; imaincurrency, mainunitsize = PEGS->mainunitsize; + if ( lockparms == 0 ) + lockparms = &PEGS->default_lockparms; + //if ( limits == 0 ) + // limits = &PEGS->default_limits; + if ( (PEGS->numpegs == 0 && stringbits(base) != PEGS->mainbits) || maxmargin > PEGGY_MARGINMAX ) + { + printf("peggy_create: numpegs.%d mismatched maincurrency.(%s) || illegal maxmargin.%d vs %d\n",PEGS->numpegs,maincurrency,maxmargin,PEGGY_MARGINMAX); + return(0); + } + if ( firsttimestamp + (numprices-1)*PEGGY_DAYTICKS > time(NULL) ) + { + printf("peggy_createpair latest price must be in the past: 1st.%u + numprices.%d -> %u vs %u\n",firsttimestamp,numprices,firsttimestamp + (numprices-1)*PEGGY_DAYTICKS,(uint32_t)time(NULL)); + return(0); + } + if ( quorum == 0 ) + quorum = PEGS->quorum; + if ( decisionthreshold == 0 ) + decisionthreshold = PEGS->decisionthreshold; + assetbits = peggy_assetbits(name); + if ( PEGS->numpegs > 0 ) + { + for (i=0; inumpegs; i++) + if ( PEGS->contracts[i]->name.assetbits == assetbits ) + { + printf("peggy_create: cant create duplicate peggy.(%s) base.(%s) rel.(%s)\n",name,base,rel); + return(0); + } + } + if ( hasprice != 0 ) + PEG = &PEGS->pricedpegs[PEGS->numpricedpegs].PEG; + else PEG = &PEGS->pairedpegs[PEGS->numpairedpegs]; + memset(PEG,0,sizeof(*PEG)); + peggy_descriptions(PEGS,&PEG->name,name,base,rel); + PEG->pool.quorum = (quorum != 0) ? quorum : PEGS->quorum, PEG->pool.decisionthreshold = (decisionthreshold != 0) ? decisionthreshold : PEGS->decisionthreshold; + PEG->pool.mainunitsize = PEGS->mainunitsize, PEG->pool.mainbits = PEGS->mainbits; + PEG->genesistime = firsttimestamp, PEG->name.id = PEGS->numpegs; + PEG->spread = spread, PEG->lockparms.margin = maxmargin, PEG->mindenomination = mindenomination; + if ( hasprice == 0 ) + PEG->baseprices = PEGS->pricedpegs[PEG->name.baseid].prices, PEG->relprices = PEGS->pricedpegs[PEG->name.relid].prices; + else PEG->baseprices = PEGS->pricedpegs[PEG->name.id].prices, PEG->relprices = 0; + if ( peggy_setvars(PEGS,PEG,PEG->name.baseid,PEG->name.relid,PEGS->numpegs,maxsupply,maxnetbalance,lockparms,unitincr,maxdailyrate,initialprices,numprices,hasprice) < 0 ) + { + printf("peggy_create: error init peggy.(%s) base.(%s) rel.(%s)\n",name,base,rel); + return(0); + } + //printf("PEG.%p num.%d priced.%d paired.%d\n",PEG,PEGS->numpegs,PEGS->numpricedpegs,PEGS->numpairedpegs); + if ( hasprice != 0 ) + PEGS->numpricedpegs++; + else PEGS->numpairedpegs++; + PEGS->contracts[PEGS->numpegs++] = PEG; + PEG->peggymils = peggymils; + PEG->name.enabled = 1; + return(PEG); +} + +struct peggy_info *peggy_init(char *path,int32_t maxdays,char *maincurrency,uint64_t maincurrencyunitsize,uint64_t quorum,uint64_t decisionthreshold,struct price_resolution spread,uint32_t dailyrate,int32_t interesttenths,int32_t posboost,int32_t negpenalty,int32_t feediv,int32_t feemult,uint32_t firsttimestamp,uint32_t BTCD_price0) +{ + //struct peggy_limits limits = { { PERCENTAGE(10), PERCENTAGE(25), PERCENTAGE(33), PERCENTAGE(50) }, SATOSHIDEN * 10000, SATOSHIDEN * 1000, { 0, 30, 90, 180 }, 4 }; + struct peggy_lock default_lockparms = { 7, 365, 7, 0, 180, 0, -1 }; + struct price_resolution mindenom,price; struct peggy_info *PEGS = calloc(1,sizeof(*PEGS)); + //if ( default_limits != 0 ) + // limits = *default_limits; + spread.Pval = PERCENTAGE(1); + ensure_directory(path); + strcpy(PEGS->maincurrency,maincurrency); + PEGS->mainbits = stringbits(maincurrency), PEGS->mainunitsize = maincurrencyunitsize, PEGS->quorum = quorum, PEGS->decisionthreshold = decisionthreshold; + PEGS->default_lockparms = default_lockparms, PEGS->default_lockparms.maxlockdays = maxdays; + //PEGS->default_limits = limits, + PEGS->default_spread = spread, PEGS->default_dailyrate = dailyrate; + PEGS->interesttenths = interesttenths, PEGS->posboost = posboost, PEGS->negpenalty = negpenalty, PEGS->feediv = feediv, PEGS->feemult = feemult; + mindenom.Pval = PRICE_RESOLUTION; + PEGS->genesistime = firsttimestamp; + price.Pval = PEGS->BTCD_price0 = BTCD_price0; + printf("set genesistime.%u BTCD0.%u\n",firsttimestamp,BTCD_price0); + peggy_createpair(PEGS,0,0,"BTCD","BTCD",0,SATOSHIDEN*1000000,SATOSHIDEN*100000,0,SATOSHIDEN,PEGGY_RATE_777,firsttimestamp,&price,1,spread,0,mindenom,0,1,peggy_mils(0)); + PEGS->accts = accts777_init(path,0); + return(PEGS); +} +//////////// end of consensus safe + +int32_t peggy_prices(struct price_resolution prices[64],double btcusd,double btcdbtc,char *contracts[],int32_t num,double *cprices,double *basevals) +{ + int32_t prices777_contractnum(char *base,char *rel); + double btcdusd,price_in_btcd,dprice,usdcny,usdrub,btccny,btcrub,xauusd,usdprice=0.,usdval,btcprice=0.; int32_t contractnum,base,nonz = 0; + if ( btcusd > SMALLVAL && btcdbtc > SMALLVAL && (usdval= basevals[0]) > SMALLVAL ) + { + xauusd = usdcny = usdrub = btccny = btcrub = 0.; + for (contractnum=0; contractnum SMALLVAL ) + { + usdcny = (basevals[0] * peggy_mils(8)) / (basevals[8] * peggy_mils(0)); + btccny = 1000 * btcusd * usdcny; + } + if ( basevals[9] > SMALLVAL ) + { + usdrub = (basevals[0] * peggy_mils(9)) / (basevals[9] * peggy_mils(0)); + btcrub = 1000 * btcusd * usdrub; + } + btcdusd = (btcusd * btcdbtc); + printf("xauusd %f usdval %f %f %f usdcny %f usdrub %f btcusd %f btcdbtc %f btcdusd %f btccny %f btcrub %f\n",xauusd,usdval,basevals[8],basevals[9],usdcny,usdrub,btcusd,btcdbtc,btcdusd,btccny,btcrub); + prices[0].Pval = (PRICE_RESOLUTION * 100. * btcdbtc); + for (base=0,contractnum=1; base<32; base++,contractnum++) + { + if ( strcmp(contracts[contractnum],CURRENCIES[base]) == 0 ) + { + if ( (dprice= basevals[base]) > SMALLVAL ) + { + nonz++; + if ( base == 0 ) + usdprice = price_in_btcd = (1. / btcdusd); + else price_in_btcd = (dprice / (btcdusd * usdval)); + prices[contractnum].Pval = (PRICE_RESOLUTION * price_in_btcd); + } + } else printf("unexpected list entry %s vs %s at %d\n",contracts[contractnum],CURRENCIES[base],contractnum); + } + if ( strcmp(contracts[contractnum],"BTCUSD") != 0 ) + printf("unexpected contract (%s) at %d\n",contracts[contractnum],contractnum); + btcprice = (1. / btcdbtc); + prices[contractnum++].Pval = (PRICE_RESOLUTION / btcdbtc) / 1000.; + printf("btcprice %f = 1/%f %llu\n",btcprice,1./btcdbtc,(long long)prices[contractnum-1].Pval); + for (; contractnum<64; contractnum++) + { + //dprice = 0; + if ( contractnum == 63 && strcmp(contracts[contractnum],"BTCUSD") == 0 ) + dprice = btcusd; + else if ( contractnum == 62 && strcmp(contracts[contractnum],"BTCCNY") == 0 ) + dprice = btccny; + else if ( contractnum == 61 && strcmp(contracts[contractnum],"BTCRUB") == 0 ) + dprice = btcrub; + else if ( contractnum == 60 && strcmp(contracts[contractnum],"XAUUSD") == 0 ) + dprice = xauusd; + else + { + dprice = cprices[contractnum]; + if ( dprice > SMALLVAL && strlen(contracts[contractnum]) > 3 ) + { + if ( strcmp(contracts[contractnum]+strlen(contracts[contractnum])-3,"USD") == 0 || strcmp(contracts[contractnum],"Copper") == 0 || strcmp(contracts[contractnum],"NGAS") == 0 || strcmp(contracts[contractnum],"UKOil") == 0 || strcmp(contracts[contractnum],"USOil") == 0 ) + dprice *= usdprice; + else if ( strcmp(contracts[contractnum],"SuperNET") == 0 ) + { + printf("SuperNET %f -> %f\n",dprice,dprice*btcprice); + dprice *= btcprice; + } + else if ( strcmp(contracts[contractnum]+strlen(contracts[contractnum])-3,"BTC") == 0 ) + dprice *= btcprice; + } + } + prices[contractnum].Pval = (uint64_t)((PRICE_RESOLUTION * dprice) * ((double)peggy_mils(contractnum) / 10000.)); + //if ( Debuglevel > 2 ) + { + struct price_resolution tmp; + tmp = peggy_scaleprice(prices[contractnum],peggy_mils(contractnum)); + printf("%.8f btcprice %.6f %f -->>> %s %.6f -> %llu %.6f mils.%d\n",cprices[contractnum],btcprice,cprices[contractnum]*btcprice,contracts[contractnum],Pval(&tmp),(long long)prices[contractnum].Pval,Pval(&prices[contractnum]),peggy_mils(contractnum)); + } + } + } + return(nonz); +} + +char *peggy_emitprices(int32_t *nonzp,struct peggy_info *PEGS,uint32_t blocktimestamp,int32_t maxlockdays) +{ + double matrix[32][32],RTmatrix[32][32],cprices[64],basevals[64]; struct price_resolution prices[256]; + cJSON *json,*array; char *jsonstr,*opreturnstr = 0; int32_t i,nonz = 0; + memset(cprices,0,sizeof(cprices)); + //printf("peggy_emitprices\n"); + if ( prices777_getmatrix(basevals,&PEGS->btcusd,&PEGS->btcdbtc,matrix,cprices+1,peggy_contracts+1,sizeof(peggy_contracts)/sizeof(*peggy_contracts)-1,blocktimestamp) > 0 ) + { + cprices[0] = PEGS->btcdbtc; + /*for (i=0; i<32; i++) + printf("%f ",basevals[i]); + printf("basevals\n"); + for (i=0; i<64; i++) + printf("%f ",cprices[i]); + printf("cprices\n");*/ + json = cJSON_CreateObject(), array = cJSON_CreateArray(); + memset(prices,0,sizeof(prices)); + memset(matrix,0,sizeof(matrix)); + memset(RTmatrix,0,sizeof(RTmatrix)); + peggy_prices(prices,PEGS->btcusd,PEGS->btcdbtc,peggy_contracts,sizeof(peggy_contracts)/sizeof(*peggy_contracts),cprices,basevals); + for (i=0; i 2 ) + printf("{%s %.6f %u}.%d ",peggy_contracts[i],Pval(&prices[i]),(uint32_t)prices[i].Pval,peggy_mils(i)); + } + jaddnum(json,"txtype",PEGGY_TXPRICES); + //jaddnum(json,"btcusd",btc.Pval); + if ( maxlockdays != 0 ) + { + jaddnum(json,"timestamp",blocktimestamp); + jaddnum(json,"maxlockdays",maxlockdays); + } + //jaddstr(json,"privkey","1259ec21d31a30898d7cd1609f80d9668b4778e3d97e941044b39f0c44d2e51b"); + jadd(json,"details",array); + jsonstr = jprint(json,1); + //printf("%s\n",jsonstr); + opreturnstr = peggy_tx(jsonstr); + free(jsonstr); + } else printf("pricematrix returned null\n"); + *nonzp = nonz; + //printf("nonz.%d\n",nonz); + return(opreturnstr); +} + +uint64_t peggy_basebits(char *name) +{ + int32_t i; char basebuf[64],relbuf[64]; + for (i=0; i<64; i++) + { + if ( strcmp(name,peggy_contracts[i]) == 0 ) + { + peggy_mapname(basebuf,relbuf,i); + return(stringbits(basebuf)); + } + } + return(0); +} + +uint64_t peggy_relbits(char *name) +{ + int32_t i; char basebuf[64],relbuf[64]; + for (i=0; i<64; i++) + { + if ( strcmp(name,peggy_contracts[i]) == 0 ) + { + peggy_mapname(basebuf,relbuf,i); + return(stringbits(relbuf)); + } + } + return(0); +} + +struct peggy_info *peggy_genesis(int32_t lookbacks[OPRETURNS_CONTEXTS],struct peggy_info *PEGS,char *path,uint32_t firsttimestamp,char *opreturnstr) +{ + //struct peggy_limits limits = { { PERCENTAGE(10), PERCENTAGE(25), PERCENTAGE(33), PERCENTAGE(50) }, SATOSHIDEN * 10000, SATOSHIDEN * 1000, { 0, 30, 90, 180 }, 4 }; + char name[64],base[64],rel[64]; uint8_t opret[1024]; struct peggy_tx Ptx; struct peggy *PEG; + struct price_resolution mindenom,spread,price; uint64_t len; long offset; uint64_t maxsupply=0,maxnetbalance=0; + int32_t i,c,baseid,relid,peggymils=0,signedcount,datalen,n=0,maxmargin=0,numprices,err=-1; uint32_t pval = 0; + numprices = 1; + datalen = (int32_t)strlen(opreturnstr) / 2; + decode_hex(opret,datalen,opreturnstr); + printf("peggy_genesis(%s)\n",opreturnstr); + if ( opret[0] == OP_RETURN_OPCODE ) + { + offset = hdecode_varint(&len,opret,1,sizeof(opret)); + if ( opret[offset] == 'P' && opret[offset+1] == 'A' && opret[offset+2] == 'X' ) + { + printf("deser\n"); + if ( (n= serdes777_deserialize(&signedcount,&Ptx,firsttimestamp,opret+offset+3,(int32_t)len-3)) > 0 ) + { + err = 0; + for (i=0; iaccts = accts777_init(path,0); + PEGS->genesis = opreturnstr, opreturnstr = 0; + } + } else printf("i.%d vs %d\n",i,Ptx.details.price.num); + } else printf("deser got n.%d\n",n); + } else printf("illegal opret.(%c%c%c)\n",opret[offset],opret[offset+1],opret[offset+2]); + } else printf("opret[0] %d\n",opret[0]); + if ( err < 0 || PEGS == 0 ) + return(0); + mindenom.Pval = PRICE_RESOLUTION; + spread.Pval = PERCENTAGE(1); + for (i=1; icontracts[baseid]->peggymils * 10000) / PEGS->contracts[relid]->peggymils; + if ( strcmp(PEGS->contracts[baseid]->name.base,base) == 0 && strcmp(PEGS->contracts[relid]->name.base,rel) == 0 ) + price.Pval = (PRICE_RESOLUTION * Ptx.details.price.feed[baseid]) / Ptx.details.price.feed[relid]; + else printf("mismatched %p base.(%s) baseid.%d (%s) or %p rel.(%s) relid.%d (%s)\n",PEGS->contracts[baseid],PEGS->contracts[baseid]->name.base,baseid,base,PEGS->contracts[relid],PEGS->contracts[relid]->name.base,relid,rel); + pval = (uint32_t)price.Pval; + } else printf("peggy_genesis RAN out of space\n"); + if ( (PEG= peggy_createpair(PEGS,0,0,name,base,rel,maxsupply,maxnetbalance,0,SATOSHIDEN*10,PEGGY_RATE_777,firsttimestamp,&price,numprices,spread,maxmargin,mindenom,i,iname.name,PEG->name.base,PEG->name.rel,Pval(&price),Pval(&x),pval,maxmargin,dstr(maxsupply),dstr(maxnetbalance),Pval(&spread),Pval(&mindenom),PEG->peggymils); + n++; + } + } + printf("genesis prices t%u vs %u\n",Ptx.timestamp,firsttimestamp); + return(PEGS); +} + +char *peggybase(uint32_t blocknum,uint32_t blocktimestamp) +{ + int32_t nonz; struct peggy_info *PEGS = opreturns_context("peggy",0); + if ( PEGS != 0 ) + return(peggy_emitprices(&nonz,PEGS,blocktimestamp,PEGS->genesis != 0 ? 0 : PEGGY_MAXLOCKDAYS)); + return(0); +} + +char *peggypayments(uint32_t blocknum,uint32_t blocktimestamp) +{ + int32_t peggy_payments(queue_t *PaymentsQ,struct opreturn_payment *payments,int32_t max,uint32_t currentblocknum,uint32_t blocknum,uint32_t blocktimestamp); + struct opreturn_payment payments[8192]; cJSON *json; + int32_t i,n; struct peggy_info *PEGS = opreturns_context("peggy",0); + memset(payments,0,sizeof(payments)); + if ( PEGS != 0 && PEGS->accts != 0 && (n= peggy_payments(&PEGS->accts->PaymentsQ,payments,sizeof(payments)/sizeof(*payments),blocknum,blocknum,blocktimestamp)) > 0 ) + { + json = cJSON_CreateObject(); + for (i=0; igenesis != 0 ? 0 : PEGGY_MAXLOCKDAYS); + if ( opreturnstr != 0 ) + { + printf("OPRETURN.(%s)\n",opreturnstr); + if ( Debuglevel > 2 ) + printf("update.%d opreturns.(%s) t%u\n",PEGS->numopreturns,opreturnstr,timestamp); + sprintf(fname,"opreturns/%d",PEGS->numopreturns); + if ( (fp= fopen(fname,"wb")) != 0 ) + { + fwrite(opreturnstr,1,strlen(opreturnstr)+1,fp); + fclose(fp); + } + if ( nonz == 64 && PEGS->genesis == 0 ) + peggy_genesis(lookbacks,PEGS,PEGS->path,timestamp,opreturnstr); + else + { + num = 1; + peggylen = (int32_t)strlen(opreturnstr) / 2; + decode_hex(opret,peggylen,opreturnstr); + opreturns_process(1,PEGS->numopreturns,PEGS->numopreturns,timestamp,0,0,opret,peggylen); + free(opreturnstr); + PEGS->numopreturns++; + } + } + } +} + +uint64_t map_apr(uint64_t *spreadp,int32_t maxdays,double apr) +{ + int64_t bestdiff,diff; int32_t i; uint64_t rate,bestsatoshis,satoshis,bestrate = 0,target; + target = PRICE_RESOLUTION * (1. + apr/100.); + bestrate = ((PRICE_RESOLUTION * log(apr)/10) / (365-1)); + satoshis = peggy_compound(0,PRICE_RESOLUTION,bestrate,365); + bestdiff = (satoshis - target); + if ( bestdiff < 0 ) + bestdiff = -bestdiff; + //err = ((double)bestdiff / target); + //n = (int32_t)(err * 4. * bestrate); + //if ( n < 1000 ) + // n = 1000; + //printf("err %f %d: new bestdiff %llu, bestrate %llu, satoshis %.8f target %.8f\n",err,n,(long long)bestdiff,(long long)bestrate,(double)satoshis/PRICE_RESOLUTION,(double)target/PRICE_RESOLUTION); + //for (i=0,rate=bestrate-n; rate<=bestrate+2*n; rate++,i++) + for (i=0,rate=1; rate %llu, rate %llu -> %llu, satoshis %.8f target %.8f\n",i,n,(long long)bestdiff,(long long)diff,(long long)bestrate,(long long)rate,(double)satoshis/PRICE_RESOLUTION,(double)target/PRICE_RESOLUTION); + bestdiff = diff, bestrate = rate, bestsatoshis = satoshis; + if ( diff == 0 ) + break; + } + } + //printf("\nnew bestdiff %llu rate %llu, satoshis %.8f target %.8f\n",(long long)bestdiff,(long long)bestrate,(double)bestsatoshis/PRICE_RESOLUTION,(double)target/PRICE_RESOLUTION); + *spreadp = PERCENTAGE((apr * maxdays)/365); + return(bestrate); +} + +uint64_t peggy_dailyrates() +{ + //struct peggy_limits limits = { { PERCENTAGE(10), PERCENTAGE(25), PERCENTAGE(33), PERCENTAGE(50) }, SATOSHIDEN * 10000, SATOSHIDEN * 1000, { 0, 30, 90, 180 }, 4 }; + extern int32_t dailyrates[]; + uint64_t satoshis,maxspread; int64_t err,errsum; int32_t i,milliperc; + dailyrates[0] = (int32_t)map_apr(&maxspread,PEGGY_MAXLOCKDAYS,(double)7770/1000); + satoshis = peggy_compound(0,SATOSHIDEN,dailyrates[0],365); + printf("%.2f%% %d %llu -> %llu %.2f%%\n",(double)7770/1000,dailyrates[0],(long long)SATOSHIDEN,(long long)satoshis,100. * ((double)(satoshis-SATOSHIDEN)/SATOSHIDEN)); + for (errsum=i=0; i<=100; i++) + { + satoshis = peggy_compound(0,SATOSHIDEN,dailyrates[i],365); + //printf("%.1f%%: %d %llu -> %llu %.3f%%\n",(double)i*.1,dailyrates[i],(long long)PRICE_RESOLUTION,(long long)satoshis,100. * (double)satoshis/PRICE_RESOLUTION - 100.); + printf("%.2f%% ",100. * (double)satoshis/SATOSHIDEN - 100.); + err = (satoshis - SATOSHIDEN) - (i == 0 ? 7770000 : i*100000); + errsum += err < 0 ? -err : err; + //printf("i.%d err %lld sum %lld\n",i,(long long)err,(long long)errsum); + } + errsum /= 101; + printf("dailyrate check errsum %lld %f%% ave err\n",(long long)errsum,100*dstr(errsum)); + if ( errsum > 10000 ) + { + //int32_t dailyrates[101]; + for (milliperc=100; milliperc<=10000; milliperc+=100) + { + dailyrates[milliperc/100] = (int32_t)map_apr(&maxspread,PEGGY_MAXLOCKDAYS,(double)milliperc/1000); + satoshis = peggy_compound(0,SATOSHIDEN,dailyrates[milliperc/100],365); + printf("%.2f%% %d %llu -> %llu %.3f%%\n",(double)milliperc/1000,dailyrates[milliperc/100],(long long)SATOSHIDEN,(long long)satoshis,100. * ((double)(satoshis-SATOSHIDEN)/SATOSHIDEN)); + } + for (i=0; i<=100; i++) + printf("%d, ",dailyrates[i]); + printf("dailyrates in 0.1%% incr\n"); + printf("root.%lld resolution.%lld squared.%llu maxPval.%llu maxunits.%d\n",(long long)PRICE_RESOLUTION_ROOT,(long long)PRICE_RESOLUTION,(long long)PRICE_RESOLUTION2,(long long)PRICE_RESOLUTION_MAXPVAL,PRICE_RESOLUTION_MAXUNITS); + } + return(errsum); +} + +void *peggy_replay(char *path,struct txinds777_info *opreturns,void *_PEGS,uint32_t blocknum,char *opreturnstr,uint8_t *data,int32_t datalen) +{ + int32_t lookbacks[OPRETURNS_CONTEXTS]; uint64_t allocsize,len; int32_t n,signedcount,valid=0; long offset; struct price_resolution tmp; + char fname[512]; uint8_t opret[8192]; struct peggy_tx Ptx; struct peggy_info *PEGS = _PEGS; + if ( blocknum == 0 ) + opreturnstr = PEGGY_GENESIS; + //printf("replay genesis.%p opreturnstr.%p data.%p\n",PEGGY_GENESIS,opreturnstr,data); + if ( data == 0 ) + { + data = opret; + if ( opreturnstr == 0 ) + { + sprintf(fname,"%s/%d",path,blocknum); + if ( (opreturnstr= loadfile(&allocsize,fname)) != 0 ) + { + //printf("loaded.(%s) %s\n",fname,opreturnstr); + if ( is_hexstr(opreturnstr) != 0 ) + valid = 1; + } //else printf("couldnt find.(%s)\n",fname); + } else valid = 1; + if ( valid != 0 ) + { + datalen = (int32_t)strlen(opreturnstr) / 2; + decode_hex(opret,datalen,opreturnstr); + } else return(0); + } + if ( data != 0 && data[0] == OP_RETURN_OPCODE ) + { + offset = hdecode_varint(&len,data,1,sizeof(opret)); + if ( data[offset] == 'P' && data[offset+1] == 'A' && data[offset+2] == 'X' ) + { + if ( (n= serdes777_deserialize(&signedcount,&Ptx,0,&data[offset+3],(int32_t)(len - 3))) < 0 ) + printf("peggy_process.%d peggy_deserialize error datalen.%d t%d\n",blocknum,datalen,Ptx.timestamp); + else + { + int32_t j,nonz = 0; + for (j=0; j PEGS->genesistime ) + { + Ptx.flags |= PEGGY_FLAGS_PEGGYBASE; + if ( peggy_process(PEGS,1,&Ptx.funding.src.coinaddr,Ptx.funding.amount,&data[offset+3],(int32_t)len-3,blocknum,Ptx.timestamp,blocknum) < 0 ) + { + printf("error processing blocknum.%u Ptx.blocknum %u\n",blocknum,blocknum); + } + } + if ( PEGS != 0 ) + PEGS->numopreturns++; + } + } else printf("illegal.(%c%c%c)\n",data[offset],data[offset+1],data[offset+2]); + } else printf("missing OP_RETURN_OPCODE [%02x]\n",data[0]); + return(PEGS); +} + +uint32_t peggy_currentblock(void *_PEGS) { struct peggy_info *PEGS; if ( (PEGS= _PEGS) != 0 ) return(PEGS->numopreturns); return(0); } + +struct peggy_info *peggy_lchain(struct txinds777_info *opreturns,char *path) +{ + double startmilli; int32_t i; struct peggy_info *tmp,*PEGS = 0; + startmilli = milliseconds(); + printf("about to replay\n"); + for (i=0; i<1000000; i++) + { + if ( PEGS == 0 && (PEGS= peggy_replay(path,opreturns,PEGS,0,0,0,0)) == 0 ) + break; + else if ( (tmp= peggy_replay(path,opreturns,PEGS,i,0,0,0)) != PEGS ) + break; + } + if ( PEGS != 0 ) + printf("loaded %d in %.3f millis per opreturn\n",PEGS->numopreturns,(milliseconds() - startmilli)/PEGS->numopreturns);// getchar(); + return(PEGS); +} + +void norm_smooth_wts(int32_t j,double *smoothwts,int32_t n) +{ + double wt; int32_t iter,i; + for (iter=0; iter<13; iter++) + { + wt = 0.; + for (i=0; i=3; numprimes--) + { + for (p=1; p SMALLVAL ) + printf("x.%d error %.20f != %.20f [%.20f]\n",x,smoothbuf[5000 - x],smoothbuf[5000 + x],smoothbuf[5000 - x] - smoothbuf[5000 + x]); + _coeffs[x-1] = (smoothbuf[5000 - x] + smoothbuf[5000 + x]) / 2.; + } + sum = 0.; + for (x=0; x 0 ) + { + i = ((rand() >> 8) % n); + //printf("(n.%d [%d] i.%d [%d]) ",n,inds[n],i,inds[i]); + n--; + tmp = inds[n]; + inds[n] = inds[i]; + inds[i] = tmp; + } + for (i=0; igenesistime,PEGS->BTCD_price0); + startmilli = milliseconds(); + peggy_clone(buf,PEGS2,PEGS); + printf("cloned %d in %.3f millis per opreturn\n",PEGS->numopreturns,(milliseconds() - startmilli)/PEGS->numopreturns); sleep(3); + return(2); +} + +#endif +#endif +#include +extern int32_t Debuglevel; + +#endif diff --git a/iguana/InstantDEX/subatomic.h b/iguana/InstantDEX/subatomic.h new file mode 100755 index 000000000..c98e30fd5 --- /dev/null +++ b/iguana/InstantDEX/subatomic.h @@ -0,0 +1,1496 @@ +/****************************************************************************** + * Copyright © 2014-2015 The SuperNET Developers. * + * * + * See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at * + * the top-level directory of this distribution for the individual copyright * + * holder information and the developer policies on copyright and licensing. * + * * + * Unless otherwise agreed in a custom licensing agreement, no part of the * + * SuperNET software, including this file may be copied, modified, propagated * + * or distributed except according to the terms contained in the LICENSE file * + * * + * Removal or modification of this copyright notice is prohibited. * + * * + ******************************************************************************/ + +#ifndef xcode_subatomic_h +#define xcode_subatomic_h + +//https://bitcointalk.org/index.php?topic=1172153.0 + +#include + +struct bp_key { void *k; }; +typedef struct cstring { + char *str; // string data, incl. NUL + size_t len; // length of string, not including NUL + size_t alloc; // total allocated buffer length +} cstring; + +extern bool bp_key_init(struct bp_key *key); +extern void bp_key_free(struct bp_key *key); +extern bool bp_key_generate(struct bp_key *key); +extern bool bp_privkey_set(struct bp_key *key, const void *privkey, size_t pk_len); +extern bool bp_pubkey_set(struct bp_key *key, const void *pubkey, size_t pk_len); +extern bool bp_key_secret_set(struct bp_key *key, const void *privkey_, size_t pk_len); +extern bool bp_privkey_get(const struct bp_key *key, void **privkey, size_t *pk_len); +extern bool bp_pubkey_get(const struct bp_key *key, void **pubkey, size_t *pk_len); +extern bool bp_key_secret_get(void *p, size_t len, const struct bp_key *key); +extern bool bp_sign(const struct bp_key *key, const void *data, size_t data_len,void **sig_, size_t *sig_len_); +extern bool bp_verify(const struct bp_key *key, const void *data, size_t data_len,const void *sig, size_t sig_len); + +void cstr_free(cstring *s, bool free_buf); +cstring *base58_encode_check(unsigned char addrtype,bool have_addrtype,const void *data,size_t data_len); +cstring *base58_decode_check(unsigned char *addrtype, const char *s_in); +int32_t btc_setprivkey(struct bp_key *key,char *privkeystr); +int32_t btc_getpubkey(char pubkeystr[67],uint8_t pubkeybuf[33],struct bp_key *key); +void btc_freekey(void *key); + +struct btcaddr +{ + struct bp_key key; + uint8_t *pubkey; uint16_t p2sh; + char addr[36],coin[8]; + uint8_t privkey[280]; +}; + +#define SCRIPT_OP_IF 0x63 +#define SCRIPT_OP_ELSE 0x67 +#define SCRIPT_OP_DUP 0x76 +#define SCRIPT_OP_ENDIF 0x68 +#define SCRIPT_OP_TRUE 0x51 +#define SCRIPT_OP_2 0x52 +#define SCRIPT_OP_3 0x53 +#define SCRIPT_OP_EQUALVERIFY 0x88 +#define SCRIPT_OP_HASH160 0xa9 +#define SCRIPT_OP_EQUAL 0x87 +#define SCRIPT_OP_CHECKSIG 0xac +#define SCRIPT_OP_CHECKMULTISIG 0xae +#define SCRIPT_OP_CHECKMULTISIGVERIFY 0xaf + +char *create_atomictx_scripts(uint8_t addrtype,char *scriptPubKey,char *p2shaddr,char *pubkeyA,char *pubkeyB,char *hash160str) +{ + // if ( refund ) OP_HASH160 <2of2 multisig hash> OP_EQUAL // standard multisig + // else OP_DUP OP_HASH160 OP_EQUALVERIFY OP_CHECKSIG // standard spend + cstring *btc_addr; char *retstr; uint8_t pubkeyAbytes[33],pubkeyBbytes[33],hash160[20],tmpbuf[24],hex[4096]; int32_t i,n = 0; + decode_hex(pubkeyAbytes,33,pubkeyA); + decode_hex(pubkeyBbytes,33,pubkeyB); + decode_hex(hash160,20,hash160str); + hex[n++] = SCRIPT_OP_IF; + hex[n++] = SCRIPT_OP_2; + hex[n++] = 33, memcpy(&hex[n],pubkeyAbytes,33), n += 33; + hex[n++] = 33, memcpy(&hex[n],pubkeyBbytes,33), n += 33; + hex[n++] = SCRIPT_OP_2; + hex[n++] = SCRIPT_OP_CHECKMULTISIG; + hex[n++] = SCRIPT_OP_ELSE; + hex[n++] = SCRIPT_OP_DUP; + hex[n++] = SCRIPT_OP_HASH160; + hex[n++] = 20; memcpy(&hex[n],hash160,20); n += 20; + hex[n++] = SCRIPT_OP_EQUALVERIFY; + hex[n++] = SCRIPT_OP_CHECKSIG; + hex[n++] = SCRIPT_OP_ENDIF; + if ( (retstr= calloc(1,n*2+16)) == 0 ) + return(0); + //printf("pubkeyA.(%s) pubkeyB.(%s) hash160.(%s) ->\n",pubkeyA,pubkeyB,hash160str); + //strcpy(retstr,"01"); + //sprintf(retstr+2,"%02x",n); + for (i=0; i>4) & 0xf); + retstr[i*2 + 1] = hexbyte(hex[i] & 0xf); + //printf("%02x",hex[i]); + } + retstr[n*2] = 0; + calc_OP_HASH160(scriptPubKey,tmpbuf+2,retstr); + tmpbuf[0] = SCRIPT_OP_HASH160; + tmpbuf[1] = 20; + tmpbuf[22] = SCRIPT_OP_EQUAL; + init_hexbytes_noT(scriptPubKey,tmpbuf,23); + if ( p2shaddr != 0 ) + { + p2shaddr[0] = 0; + if ( (btc_addr= base58_encode_check(addrtype,true,tmpbuf+2,20)) != 0 ) + { + if ( strlen(btc_addr->str) < 36 ) + strcpy(p2shaddr,btc_addr->str); + cstr_free(btc_addr,true); + } + } + return(retstr); +} + +#ifdef noiguana +int32_t create_MofN(uint8_t addrtype,char *redeemScript,char *scriptPubKey,char *p2shaddr,char *pubkeys[],int32_t M,int32_t N) +{ + cstring *btc_addr; uint8_t pubkey[33],tmpbuf[24],hex[4096]; int32_t i,n = 0; + hex[n++] = 0x50 + M; + for (i=0; i>4) & 0xf); + redeemScript[i*2 + 1] = hexbyte(hex[i] & 0xf); + //fprintf(stderr,"%02x",hex[i]); + } + //fprintf(stderr," n.%d\n",n); + redeemScript[n*2] = 0; + calc_OP_HASH160(0,tmpbuf+2,redeemScript); + //printf("op160.(%s)\n",redeemScript); + tmpbuf[0] = SCRIPT_OP_HASH160; + tmpbuf[1] = 20; + tmpbuf[22] = SCRIPT_OP_EQUAL; + init_hexbytes_noT(scriptPubKey,tmpbuf,23); + p2shaddr[0] = 0; + if ( (btc_addr= base58_encode_check(addrtype,true,tmpbuf+2,20)) != 0 ) + { + if ( strlen(btc_addr->str) < 36 ) + strcpy(p2shaddr,btc_addr->str); + cstr_free(btc_addr,true); + } + return(n); +} + +struct btcaddr *btcaddr_new(char *coinstr,char *p2sh_script) +{ + uint8_t script[8192],md160[20]; char pubkeystr[512],privkeystr[512],hashstr[41]; struct coin777 *coin; + void *privkey=0,*pubkey=0; int32_t n; size_t len,slen; cstring *btc_addr; struct btcaddr *btc; + if ( (btc= calloc(1,sizeof(*btc))) == 0 || (coin = coin777_find(coinstr,1)) == 0 ) + { + if ( btc != 0 ) + free(btc); + return(0); + } + strncpy(btc->coin,coin->name,sizeof(btc->coin)-1); + if ( p2sh_script != 0 ) + { + calc_OP_HASH160(0,md160,p2sh_script); + btc->p2sh = n = (int32_t)strlen(p2sh_script) >> 1; + decode_hex(script,n,p2sh_script); + if ( (btc_addr= base58_encode_check(coin->p2shtype,true,md160,sizeof(md160))) != 0 ) + { + if ( n > sizeof(btc->privkey)-23 ) + { + printf("script.(%s) len.%d is too big\n",p2sh_script,n); + free(btc); + return(0); + } + strcpy(btc->addr,btc_addr->str); + memcpy(btc->privkey,script,n); + btc->pubkey = &btc->privkey[sizeof(btc->privkey) - 23]; + btc->pubkey[0] = SCRIPT_OP_HASH160; + btc->pubkey[2] = 20; + memcpy(&btc->pubkey[2],md160,20); + btc->pubkey[22] = SCRIPT_OP_EQUAL; + init_hexbytes_noT(privkeystr,script,n); + printf("type.%u btcaddr.%ld addr.(%s) %ld p2sh.(%s) %d\n",coin->p2shtype,(long)sizeof(struct btcaddr),btc->addr,(long)strlen(btc->addr),privkeystr,n); + cstr_free(btc_addr,true); + } else free(btc), btc = 0; + return(btc); + } + else if ( bp_key_init(&btc->key) != 0 && bp_key_generate(&btc->key) != 0 && bp_pubkey_get(&btc->key,&pubkey,&len) != 0 && bp_privkey_get(&btc->key,&privkey,&slen) != 0 ) + { + if ( len == 33 && slen == 214 && memcmp((void *)((long)privkey + slen - 33),pubkey,33) == 0 ) + { + init_hexbytes_noT(pubkeystr,pubkey,len); + init_hexbytes_noT(privkeystr,privkey,slen); + calc_OP_HASH160(hashstr,md160,pubkeystr); + if ( (btc_addr= base58_encode_check(coin->addrtype,true,md160,sizeof(md160))) != 0 ) + { + strcpy(btc->addr,btc_addr->str); + memcpy(btc->privkey,privkey,slen); + btc->pubkey = &btc->privkey[slen - len]; + printf("type.%u btcaddr.%ld rmd160.(%s) addr.(%s) %ld pubkey.(%s) %d privkey.(%s) %d\n",coin->addrtype,(long)sizeof(struct btcaddr),hashstr,btc->addr,(long)strlen(btc->addr),pubkeystr,(int32_t)len,privkeystr,(int32_t)slen); + cstr_free(btc_addr,true); + } + else free(btc), btc = 0; + } else free(btc), btc = 0; + } + return(btc); +} + +int32_t btc_getpubkey(char pubkeystr[67],uint8_t pubkeybuf[33],struct bp_key *key) +{ + void *pubkey = 0; size_t len = 0; + bp_pubkey_get(key,&pubkey,&len); + if ( pubkey != 0 ) + { + if ( pubkeystr != 0 ) + { + if ( len < 34 ) + { + init_hexbytes_noT(pubkeystr,pubkey,(int32_t)len); + memcpy(pubkeybuf,pubkey,len); + } + else printf("btc_getpubkey error len.%d\n",(int32_t)len), len = -1; + } + //printf("btc_getpubkey len.%ld (%s).%p\n",len,pubkeystr,pubkeystr); + } else len = -1; + return((int32_t)len); +} + +int32_t btc_convrmd160(char *coinaddr,uint8_t addrtype,uint8_t md160[20]) +{ + cstring *btc_addr; + if ( (btc_addr= base58_encode_check(addrtype,true,md160,20)) != 0 ) + { + strcpy(coinaddr,btc_addr->str); + cstr_free(btc_addr,true); + return(0); + } + return(-1); +} + +int32_t btc_coinaddr(char *coinaddr,uint8_t addrtype,char *pubkeystr) +{ + uint8_t rmd160[20]; char hashstr[41]; + calc_OP_HASH160(hashstr,rmd160,pubkeystr); + return(btc_convrmd160(coinaddr,addrtype,rmd160)); +} + +int32_t btc_convaddr(char *hexaddr,char *addr58) +{ + uint8_t addrtype; cstring *cstr; + if ( (cstr= base58_decode_check(&addrtype,(const char *)addr58)) != 0 ) + { + sprintf(hexaddr,"%02x",addrtype); + init_hexbytes_noT(hexaddr+2,(void *)cstr->str,cstr->len); + cstr_free(cstr,true); + return(0); + } + return(-1); +} + +int32_t btc_priv2wip(char *wipstr,uint8_t privkey[32],uint8_t addrtype) +{ + uint8_t tmp[128]; char hexstr[67]; cstring *btc_addr; + memcpy(tmp,privkey,32); + tmp[32] = 1; + init_hexbytes_noT(hexstr,tmp,32); + if ( (btc_addr= base58_encode_check(addrtype,true,tmp,33)) != 0 ) + { + strcpy(wipstr,btc_addr->str); + cstr_free(btc_addr,true); + } + printf("-> (%s) -> wip.(%s) addrtype.%02x\n",hexstr,wipstr,addrtype); + return(0); +} + +int32_t btc_wip2priv(uint8_t privkey[32],char *wipstr) +{ + uint8_t addrtype; cstring *cstr; int32_t len = -1; + if ( (cstr= base58_decode_check(&addrtype,(const char *)wipstr)) != 0 ) + { + init_hexbytes_noT((void *)privkey,(void *)cstr->str,cstr->len); + if ( cstr->str[cstr->len-1] == 0x01 ) + cstr->len--; + memcpy(privkey,cstr->str,cstr->len); + len = (int32_t)cstr->len; + char tmp[138]; + btc_priv2wip(tmp,privkey,addrtype); + printf("addrtype.%02x wipstr.(%llx) len.%d\n",addrtype,*(long long *)privkey,len); + cstr_free(cstr,true); + } + return(len); +} + +int32_t btc_setprivkey(struct bp_key *key,char *privkeystr) +{ + uint8_t privkey[512]; int32_t len = btc_wip2priv(privkey,privkeystr); + if ( len < 0 || bp_key_init(key) == 0 || bp_key_secret_set(key,privkey,len) == 0 ) + { + printf("error setting privkey\n"); + return(-1); + } + return(0); +} + +void jumblr_freekey(void *key) +{ + bp_key_free(key); + free(key); +} + +int32_t btc_priv2pub(uint8_t pubkey[33],uint8_t privkey[32]) +{ + size_t len; void *pub = 0; int32_t retval = -1; + struct bp_key *key = calloc(1,sizeof(*key)); + if ( key != 0 && bp_key_init(key) != 0 && bp_key_secret_set(key,privkey,32) != 0 ) + { + bp_pubkey_get(key,&pub,&len); + bp_key_free(key); + if ( len == 33 ) + memcpy(pubkey,pub,33); + if ( pub != 0 ) + free(pub); + return(retval); + } + if ( key != 0 ) + bp_key_free(key); + return(retval); +} + +int32_t btc_pub2rmd(uint8_t rmd160[20],uint8_t pubkey[33]) +{ + char pubkeystr[67],hashstr[41]; + init_hexbytes_noT(pubkeystr,pubkey,33); + calc_OP_HASH160(hashstr,rmd160,pubkeystr); + return(0); +} + +void *jumblr_bpkey(char *pubP,struct coin777 *coin,char *coinaddr) +{ + uint8_t buf[2048]; char *privkey; struct bp_key *key = 0; + //printf("coin.%s (%s)\n",coin->name,coinaddr); + if ( (privkey = dumpprivkey(coin->name,coin->serverport,coin->userpass,coinaddr)) != 0 ) + { + //printf("privkey.(%s)\n",privkey); + key = calloc(1,sizeof(*key)); + if ( key != 0 && btc_setprivkey(key,privkey) == 0 && btc_getpubkey(pubP,buf,key) > 0 ) + return(key); + btc_freekey(key); + } + return(0); +} + +void set_spendscript(char *spendscript,char *coinaddr) +{ + char hexaddr[128]; + btc_convaddr(hexaddr,coinaddr); + sprintf(spendscript,"76a914%s88ac",hexaddr+2); +} + +int32_t script_coinaddr(char *coinaddr,cJSON *scriptobj) +{ + struct destbuf buf; cJSON *addresses; + coinaddr[0] = 0; + if ( scriptobj == 0 ) + return(-1); + if ( (addresses= cJSON_GetObjectItem(scriptobj,"addresses")) != 0 ) + { + copy_cJSON(&buf,jitem(addresses,0)); + strcpy(coinaddr,buf.buf); + return(0); + } + return(-1); +} + +char *pangea_signp2sh(int32_t oldtx_format,struct cointx_info *refT,int32_t redeemi,char *redeemscript,char sigs[][256],int32_t n,uint8_t privkey[32],int32_t privkeyind) +{ + char hexstr[16384]; bits256 hash2; uint8_t data[4096],sigbuf[512]; struct bp_key key; + struct cointx_info *T; int32_t i,len; void *sig = NULL; size_t siglen = 0; struct cointx_input *vin; + if ( bp_key_init(&key) != 0 && bp_key_secret_set(&key,privkey,32) != 0 ) + { + if ( (T= calloc(1,sizeof(*T))) == 0 ) + return(0); + *T = *refT; vin = &T->inputs[redeemi]; + for (i=0; inuminputs; i++) + strcpy(T->inputs[i].sigs,"00"); + strcpy(vin->sigs,redeemscript); + vin->sequence = (uint32_t)-1; + T->nlocktime = 0; + //disp_cointx(&T); + emit_cointx(&hash2,data,sizeof(data),T,oldtx_format,SIGHASH_ALL); + //printf("HASH2.(%llx)\n",(long long)hash2.txid); + if ( bp_sign(&key,hash2.bytes,sizeof(hash2),&sig,&siglen) != 0 ) + { + memcpy(sigbuf,sig,siglen); + sigbuf[siglen++] = SIGHASH_ALL; + init_hexbytes_noT(sigs[privkeyind],sigbuf,(int32_t)siglen); + strcpy(vin->sigs,"00"); + for (i=0; isigs + strlen(vin->sigs),"%02x%s",(int32_t)strlen(sigs[i])>>1,sigs[i]); + //printf("(%s).%ld ",sigs[i],strlen(sigs[i])); + } + } + len = (int32_t)(strlen(redeemscript)/2); + if ( len >= 0xfd ) + sprintf(&vin->sigs[strlen(vin->sigs)],"4d%02x%02x",len & 0xff,(len >> 8) & 0xff); + else sprintf(&vin->sigs[strlen(vin->sigs)],"4c%02x",len); + sprintf(&vin->sigs[strlen(vin->sigs)],"%s",redeemscript); + //printf("after A.(%s) othersig.(%s) siglen.%02lx -> (%s)\n",hexstr,othersig != 0 ? othersig : "",siglen,vin->sigs); + //printf("vinsigs.(%s) %ld\n",vin->sigs,strlen(vin->sigs)); + _emit_cointx(hexstr,sizeof(hexstr),T,oldtx_format); + //disp_cointx(&T); + free(T); + return(clonestr(hexstr)); + } + else printf("error signing\n"); + free(T); + } + return(0); +} + +uint64_t jumblr_getcoinaddr(char *coinaddr,struct destbuf *scriptPubKey,struct coin777 *coin,char *txid,int32_t vout) +{ + char *rawtransaction,*txidstr,*asmstr; uint64_t value = 0; int32_t n,m,len,reqSigs; cJSON *json,*scriptobj,*array,*item,*hexobj; + scriptPubKey->buf[0] = 0; + if ( (rawtransaction= _get_transaction(coin->name,coin->serverport,coin->userpass,txid)) == 0 ) + { + printf("jumblr_getprivkey: error getting (%s)\n",txid); + return(0); + } + if ( (json= cJSON_Parse(rawtransaction)) != 0 ) + { + if ( (txidstr= jstr(json,"txid")) == 0 || strcmp(txidstr,txid) != 0 ) + { + printf("jumblr_getcoinaddr no txid or mismatch\n"); + free_json(json); + free(rawtransaction); + return(0); + } + if ( (array= jarray(&n,json,"vout")) != 0 && vout < n && (item= jitem(array,vout)) != 0 ) + { + reqSigs = (int32_t)get_cJSON_int(item,"reqSigs"); + value = conv_cJSON_float(item,"value"); + scriptobj = cJSON_GetObjectItem(item,"scriptPubKey"); + printf("ITEM.(%s)\n",jprint(item,0)); + if ( scriptobj != 0 ) + { + printf("script.(%s)\n",jprint(scriptobj,0)); + script_coinaddr(coinaddr,scriptobj); + hexobj = cJSON_GetObjectItem(scriptobj,"hex"); + if ( scriptPubKey != 0 && hexobj != 0 ) + copy_cJSON(scriptPubKey,hexobj); + else + { + // OP_DUP OP_HASH160 f563e867027dedd109c9bb5f3354c3cc41dc7c7f OP_EQUALVERIFY OP_CHECKSIG + // 0318d4f6cdcbe6c822b979fc318dbe4ad58287223c8fb57b7bec0c88cd58a4b16a OP_CHECKSIG + if ( (asmstr= jstr(scriptobj,"asm")) != 0 ) + { + len = (int32_t)strlen(asmstr); + m = (int32_t)strlen(" OP_EQUALVERIFY OP_CHECKSIG"); + if ( strncmp(asmstr,"OP_DUP OP_HASH160 ",strlen("OP_DUP OP_HASH160 ")) == 0 && strcmp(&asmstr[len - m]," OP_EQUALVERIFY OP_CHECKSIG") == 0 ) + set_spendscript(scriptPubKey->buf,coinaddr); + else + { + printf("nonstandard.(%s)\n",&asmstr[len - m]); + m = (int32_t)strlen(" OP_CHECKSIG"); + if ( strcmp(&asmstr[len - m]," OP_CHECKSIG") == 0 ) + { + printf("key sig (%s)\n",asmstr); + sprintf(scriptPubKey->buf,"%02x",(len-m)/2); + memcpy(&scriptPubKey->buf[2],asmstr,(len - m)); + scriptPubKey->buf[2 + (len - m)] = 0; + strcat(scriptPubKey->buf,"ac"); + } + } + } + } + } else printf("null scriptobj.%p (%s)\n",scriptobj,coinaddr); + } + free_json(json); + } + free(rawtransaction); + return(value); +} + +char *jumblr_getprivkey(uint64_t *valuep,struct destbuf *scriptPubKey,uint32_t *locktimep,struct coin777 *coin,char *txid,int32_t vout) +{ + char *rawtransaction,*txidstr,*privkey=0,coinaddr[64]; uint64_t value = 0; int32_t n,reqSigs; cJSON *json,*scriptobj,*array,*item,*hexobj; + *locktimep = -1; + scriptPubKey->buf[0] = 0; + if ( (rawtransaction= _get_transaction(coin->name,coin->serverport,coin->userpass,txid)) == 0 ) + { + printf("jumblr_getprivkey: error getting (%s)\n",txid); + return(0); + } + if ( (json= cJSON_Parse(rawtransaction)) != 0 )//get_decoderaw_json(coin,rawtransaction)) != 0 ) + { + *locktimep = (int32_t)get_cJSON_int(json,"locktime"); + if ( (txidstr= jstr(json,"txid")) == 0 || strcmp(txidstr,txid) != 0 ) + { + printf("jumblr_getprivkey no txid or mismatch\n"); + free_json(json); + free(rawtransaction); + return(0); + } + //printf("txidstr.(%s) vout.%d\n",txidstr,vout); + if ( (array= jarray(&n,json,"vout")) != 0 && (item= jitem(array,vout)) != 0 ) + { + scriptobj = cJSON_GetObjectItem(item,"scriptPubKey"); + if ( scriptobj != 0 && script_coinaddr(coinaddr,scriptobj) == 0 ) + { + reqSigs = (int32_t)get_cJSON_int(item,"reqSigs"); + value = conv_cJSON_float(item,"value"); + hexobj = cJSON_GetObjectItem(scriptobj,"hex"); + if ( scriptPubKey != 0 && hexobj != 0 ) + copy_cJSON(scriptPubKey,hexobj); + privkey = dumpprivkey(coin->name,coin->serverport,coin->userpass,coinaddr); + } else printf("null scriptobj.%p (%s)\n",scriptobj,coinaddr); + } + free_json(json); + } + free(rawtransaction); + if ( valuep != 0 ) + *valuep = value; + return(privkey); +} + +cJSON *cointx_vins_json_params(struct coin777 *coin,char *rawbytes) +{ + int32_t i; cJSON *json,*array; char coinaddr[128]; struct destbuf scriptPubKey; struct cointx_info *cointx; + array = cJSON_CreateArray(); + printf("convert.(%s)\n",rawbytes); + if ( (cointx= _decode_rawtransaction(rawbytes,coin->mgw.oldtx_format)) != 0 ) + { + disp_cointx(cointx); + for (i=0; inuminputs; i++) + { + json = cJSON_CreateObject(); + jaddstr(json,"txid",cointx->inputs[i].tx.txidstr); + jaddnum(json,"vout",cointx->inputs[i].tx.vout); + if ( cointx->inputs[i].sigs[0] != 0 ) + jaddstr(json,"scriptPubKey",cointx->inputs[i].sigs); + else + { + jumblr_getcoinaddr(coinaddr,&scriptPubKey,coin,cointx->inputs[i].tx.txidstr,cointx->inputs[i].tx.vout); + jaddstr(json,"scriptPubKey",scriptPubKey.buf); + } + cJSON_AddItemToArray(array,json); + } + free(cointx); + } + return(array); +} + +char *jumblr_signraw_json_params(struct coin777 *coin,char *rawbytes) +{ + char *paramstr = 0; cJSON *array,*rawobj,*vinsobj;//,*keysobj;char *coinaddrs[MAX_SUBATOMIC_INPUTS+1], + if ( (rawobj= cJSON_CreateString(rawbytes)) != 0 ) + { + if ( (vinsobj= cointx_vins_json_params(coin,rawbytes)) != 0 ) + { + array = cJSON_CreateArray(); + jaddi(array,rawobj); + jaddi(array,vinsobj); + //cJSON_AddItemToArray(array,keysobj); + paramstr = jprint(array,1); + } + else free_json(rawobj); + } + return(paramstr); +} + +int32_t jumblr_signtx(char *signedtx,unsigned long destsize,struct coin777 *coin,char *signparams) +{ + cJSON *json,*compobj; char *retstr,*deststr; uint32_t completed = 0; + signedtx[0] = 0; + //printf("cp.%d vs %d: subatomic_signtx rawbytes.(%s)\n",cp->coinid,coinid,rawbytes); + if ( coin != 0 && signparams != 0 ) + { + _stripwhite(signparams,' '); + printf("got signparams.(%s)\n",signparams); + if ( (retstr= bitcoind_RPC(0,coin->name,coin->serverport,coin->userpass,"signrawtransaction",signparams)) != 0 ) + { + //printf("got retstr.(%s)\n",retstr); + if ( (json= cJSON_Parse(retstr)) != 0 ) + { + if ( (deststr= jstr(json,"hex")) != 0 ) + { + compobj = cJSON_GetObjectItem(json,"complete"); + if ( compobj != 0 ) + completed = ((compobj->type&0xff) == cJSON_True); + if ( strlen(deststr) > destsize ) + printf("sign_rawtransaction: strlen(deststr) %ld > %ld destize\n",(long)strlen(deststr),destsize); + else strcpy(signedtx,deststr); + } else printf("cant get hex from.(%s)\n",retstr); + free_json(json); + } else printf("json parse error.(%s)\n",retstr); + free(retstr); + } else printf("error signing rawtx\n"); + } else printf("error generating signparams\n"); + return(completed); +} + +char *jumblr_signvin(char *sigstr,struct coin777 *coin,char *signedtx,int32_t bufsize,void *bpkey,char *pubP,struct cointx_info *refT,int32_t redeemi,char *rawtx) +{ + // signrawtransaction [{"txid":txid,"vout":n,"scriptPubKey":hex},...] [,...] + char hexstr[4096],redeem[2048]; bits256 hash2; uint8_t *data,sigbuf[1024]; + struct cointx_info *T; int32_t i; void *sig = NULL; size_t siglen = 0; struct cointx_input *vin; + sigstr[0] = 0; + if ( 1 ) + { + char *paramstr; cJSON *vinarray,*item,*array = cJSON_CreateArray(); + vinarray = cJSON_CreateArray(); + jaddistr(array,rawtx); + for (i=0; inuminputs; i++) + { + vin = &refT->inputs[i]; + item = cJSON_CreateObject(); + jaddstr(item,"txid",vin->tx.txidstr); + jaddnum(item,"vout",vin->tx.vout); + jaddstr(item,"scriptPubKey",vin->sigs); + jaddi(vinarray,item); + } + jaddi(array,vinarray); + paramstr = jprint(array,1); + if ( jumblr_signtx(signedtx,bufsize,coin,paramstr) > 0 ) + printf("SIGS completed\n"); + if ( signedtx[0] != 0 ) + { + if ( (T= _decode_rawtransaction(signedtx,coin->mgw.oldtx_format)) != 0 ) + { + strcpy(sigstr,T->inputs[redeemi].sigs); + free(T); + return(sigstr); + } + } + return(0); + } + if ( (T = calloc(1,sizeof(*T))) == 0 ) + { + printf("unexpected out of mem in jumblr_signvin\n"); + return(0); + } + + *T = *refT; + vin = &T->inputs[redeemi]; + safecopy(redeem,vin->sigs,sizeof(redeem)); + fprintf(stderr,"redeemi.%d numinputs.%d\n",redeemi,T->numinputs); + for (i=0; inuminputs; i++) + if ( i != redeemi ) + strcpy(T->inputs[i].sigs,"00"); + vin->sequence = (uint32_t)-1; + T->nlocktime = 0; + data = malloc(65536); + disp_cointx(T); + emit_cointx(&hash2,data,sizeof(data),T,coin->mgw.oldtx_format,SIGHASH_ALL); + free(data); + if ( bp_sign(bpkey,hash2.bytes,sizeof(hash2),&sig,&siglen) != 0 && sig != 0 ) + { + memcpy(sigbuf,sig,siglen); + free(sig); + sigbuf[siglen++] = SIGHASH_ALL; + init_hexbytes_noT(hexstr,sigbuf,(int32_t)siglen); + sprintf(vin->sigs,"%02x%s%02x%s",(uint32_t)siglen,hexstr,(uint32_t)strlen(pubP)/2,pubP); + strcpy(sigstr,vin->sigs); + printf("after P.(%s) siglen.%02x -> %s pubP.(%s)\n",sigstr,(uint32_t)siglen,vin->sigs,pubP); + } + free(T); + if ( sigstr[0] != 0 ) + return(sigstr); + else return(0); +} + +int32_t script_has_coinaddr(cJSON *scriptobj,char *coinaddr) +{ + int32_t i,n; struct destbuf buf; cJSON *addresses,*addrobj; + if ( scriptobj == 0 ) + return(0); + addresses = cJSON_GetObjectItem(scriptobj,"addresses"); + if ( addresses != 0 ) + { + n = cJSON_GetArraySize(addresses); + for (i=0; iname,coin->serverport,coin->userpass,"decoderawtransaction",str)) != 0 && retstr[0] != 0 ) + { + //printf("got decodetransaction.(%s)\n",retstr); + json = cJSON_Parse(retstr); + } else printf("error decoding.(%s)\n",str); + if ( retstr != 0 ) + free(retstr); + free(str); + return(json); +} + +char *subatomic_decodetxid(int64_t *valuep,struct destbuf *scriptPubKey,uint32_t *locktimep,struct coin777 *coin,char *rawtransaction,char *mycoinaddr) +{ + char *txidstr,checkasmstr[1024],*asmstr,*txid = 0; uint64_t value = 0; int32_t i,n,nval,reqSigs; cJSON *json,*scriptobj,*array,*item,*hexobj; + *locktimep = -1; + if ( (json= get_decoderaw_json(coin,rawtransaction)) != 0 ) + { + *locktimep = (int32_t)get_cJSON_int(json,"locktime"); + if ( (txidstr= jstr(json,"txid")) == 0 ) + { + printf("subatomic_decodetxid no txid\n"); + return(0); + } + txid = clonestr(txidstr); + array = cJSON_GetObjectItem(json,"vout"); + if ( mycoinaddr != 0 && is_cJSON_Array(array) != 0 ) + { + n = cJSON_GetArraySize(array); + for (i=0; inuminputs; i++) + { + up = &rp->inputs[i]; + json = cJSON_CreateObject(); + jaddstr(json,"txid",up->txid.buf); + jaddnum(json,"vout",up->vout); + if ( up->scriptPubKey.buf[0] != 0 ) + jaddstr(json,"scriptPubKey",up->scriptPubKey.buf); + if ( up->redeemScript.buf[0] != 0 ) + jaddstr(json,"redeemScript",up->redeemScript.buf); + cJSON_AddItemToArray(array,json); + } + return(array); +} + +cJSON *subatomic_privkeys_json_params(struct coin777 *coin,char **coinaddrs,int32_t n) +{ + int32_t i; char *privkey; cJSON *array = cJSON_CreateArray(); + //sprintf(walletkey,"[\"%s\",%d]",Global_subatomic->NXTADDR,BITCOIN_WALLET_UNLOCKSECONDS); + // locking first avoids error, hacky but no time for wallet fiddling now + //bitcoind_RPC(0,coin->name,coin->serverport,coin->userpass,"walletlock",0); + //bitcoind_RPC(0,coin->name,coin->serverport,coin->userpass,"walletpassphrase",walletkey); + for (i=0; iname,coin->serverport,coin->userpass,coinaddrs[i])) != 0 ) + { + jaddistr(array,privkey); + free(privkey); + } + } + } + return(array); +} + +char *subatomic_signraw_json_params(char *skipaddr,char *coinaddr,struct coin777 *coin,struct subatomic_rawtransaction *rp,char *rawbytes) +{ + int32_t i,j,flag; char *coinaddrs[MAX_SUBATOMIC_INPUTS+1],*paramstr = 0; cJSON *array,*rawobj,*vinsobj,*keysobj; + if ( (rawobj= cJSON_CreateString(rawbytes)) != 0 ) + { + if ( (vinsobj= subatomic_vins_json_params(coin,rp)) != 0 ) + { + // printf("add %d inputs skipaddr.%s coinaddr.%s\n",rp->numinputs,skipaddr,coinaddr); + for (i=flag=j=0; inuminputs; i++) + { + if ( skipaddr == 0 || strcmp(rp->inputs[i].address.buf,skipaddr) != 0 ) + { + printf("i.%d j.%d flag.%d %s\n",i,j,flag,rp->inputs[i].address.buf); + coinaddrs[j] = rp->inputs[i].address.buf; + if ( coinaddr != 0 && strcmp(coinaddrs[j],coinaddr) == 0 ) + flag++; + j++; + } + } + //printf("i.%d j.%d flag.%d\n",i,j,flag); + //if ( coinaddr != 0 && flag == 0 ) + //coinaddrs[j++] = coinaddr; + coinaddrs[j] = 0; + keysobj = subatomic_privkeys_json_params(coin,coinaddrs,j); + if ( keysobj != 0 ) + { + array = cJSON_CreateArray(); + cJSON_AddItemToArray(array,rawobj); + cJSON_AddItemToArray(array,vinsobj); + cJSON_AddItemToArray(array,keysobj); + paramstr = cJSON_Print(array); + free_json(array); + } + else free_json(vinsobj); + } + else free_json(rawobj); + } + return(paramstr); +} + +char *subatomic_signtx(char *skipaddr,uint32_t *lockedblockp,int64_t *valuep,char *coinaddr,char *signedtx,unsigned long destsize,struct coin777 *coin,struct subatomic_rawtransaction *rp,char *rawbytes) +{ + cJSON *json,*compobj; char *retstr,*deststr,*signparams,*txid = 0; uint32_t locktime = 0; + rp->txid[0] = signedtx[0] = 0; + rp->completed = -1; + //printf("cp.%d vs %d: subatomic_signtx rawbytes.(%s)\n",cp->coinid,coinid,rawbytes); + if ( coin != 0 && (signparams= subatomic_signraw_json_params(skipaddr,coinaddr,coin,rp,rawbytes)) != 0 ) + { + _stripwhite(signparams,' '); + //printf("got signparams.(%s)\n",signparams); + if ( (retstr= bitcoind_RPC(0,coin->name,coin->serverport,coin->userpass,"signrawtransaction",signparams)) != 0 ) + { + //printf("got retstr.(%s)\n",retstr); + if ( (json= cJSON_Parse(retstr)) != 0 ) + { + if ( (deststr= jstr(json,"hex")) != 0 ) + { + compobj = cJSON_GetObjectItem(json,"complete"); + if ( compobj != 0 ) + rp->completed = ((compobj->type&0xff) == cJSON_True); + if ( strlen(deststr) > destsize ) + printf("sign_rawtransaction: strlen(deststr) %ld > %ld destize\n",(long)strlen(deststr),destsize); + else + { + strcpy(signedtx,deststr); + txid = subatomic_decodetxid(valuep,0,&locktime,coin,deststr,coinaddr); + if ( txid != 0 ) + { + safecopy(rp->txid,txid,sizeof(rp->txid)); + free(txid); + txid = rp->txid; + } + // printf("got signedtransaction -> txid.(%s) %.8f\n",rp->txid,dstr(valuep!=0?*valuep:0)); + } + } else printf("cant get hex from.(%s)\n",retstr); + free_json(json); + } else printf("json parse error.(%s)\n",retstr); + free(retstr); + } else printf("error signing rawtx\n"); + free(signparams); + } else printf("error generating signparams\n"); + if ( lockedblockp != 0 ) + *lockedblockp = locktime; + return(txid); +} + +cJSON *subatomic_vouts_json_params(struct subatomic_rawtransaction *rp) +{ + int32_t i; cJSON *json,*obj; + json = cJSON_CreateObject(); + for (i=0; inumoutputs; i++) + { + obj = cJSON_CreateNumber((double)rp->destamounts[i]/SATOSHIDEN); + cJSON_AddItemToObject(json,rp->destaddrs[i],obj); + } + // printf("numdests.%d (%s)\n",rp->numoutputs,cJSON_Print(json)); + return(json); +} + +char *subatomic_rawtxid_json(struct coin777 *coin,struct subatomic_rawtransaction *rp) +{ + char *paramstr = 0; cJSON *array,*vinsobj,*voutsobj; + if ( (vinsobj= subatomic_vins_json_params(coin,rp)) != 0 ) + { + if ( (voutsobj= subatomic_vouts_json_params(rp)) != 0 ) + { + array = cJSON_CreateArray(); + cJSON_AddItemToArray(array,vinsobj); + cJSON_AddItemToArray(array,voutsobj); + paramstr = cJSON_Print(array); + free_json(array); // this frees both vinsobj and voutsobj + } + else free_json(vinsobj); + } + // printf("subatomic_rawtxid_json.%s\n",paramstr); + return(paramstr); +} + +uint64_t subatomic_donation(struct coin777 *coin,uint64_t amount) +{ + uint64_t donation = 0; + if ( coin->donationaddress[0] != 0 ) + { + donation = amount >> 11; + if ( donation < coin->mgw.txfee ) + donation = coin->mgw.txfee; + } + return(donation); +} + +char *gather_account_addresses(struct coin777 *coin,char *account) +{ + cJSON *array,*retarray,*subarray,*item; int32_t i,j,m,n; char *acct; + //printf("call listaddressgroupings\n"); + if ( (array= _get_localaddresses(coin->name,coin->serverport,coin->userpass)) != 0 ) + { + retarray = cJSON_CreateArray(); + n = cJSON_GetArraySize(array); + for (i=0; i 0 ) + { + for (j=0; j 2 ) + { + if ( (acct= jstr(jitem(item,2),0)) != 0 && strcmp(acct,account) == 0 ) + { + //printf("gather.(%s) %s\n",jstr(jitem(item,0),0),account); + jaddistr(retarray,jstr(jitem(item,0),0)); + } + } //else printf("skip item.%p, %d %d\n",item,is_cJSON_Array(item),cJSON_GetArraySize(item)); + } + } + } + } + free_json(array); + if ( cJSON_GetArraySize(retarray) == 0 ) + { + free_json(retarray); + return(0); + } + else return(jprint(retarray,1)); + } + else return(0); +} + +struct subatomic_unspent_tx *gather_unspents(uint64_t *totalp,int32_t *nump,struct coin777 *coin,char *account) +{ + int32_t i,j,num; struct subatomic_unspent_tx *ups = 0; char *params,*addrs,*retstr; cJSON *json,*item; + /*{ + "txid" : "1ccd2a9d0f8d690ed13b6768fc6c041972362f5531922b6b152ed2c98d3fe113", + "vout" : 1, + "address" : "DK3nxu6GshBcQNDMqc66ARcwqDZ1B5TJe5", + "scriptPubKey" : "76a9149891029995222077889b36c77e2b85690878df9088ac", + "amount" : 2.00000000, + "confirmations" : 72505 + },*/ + *totalp = *nump = 0; + if ( account != 0 && account[0] != 0 ) + { + if ( (addrs= gather_account_addresses(coin,account)) != 0 ) + { + if ( (params = calloc(1,strlen(addrs) + 128)) == 0 ) + { + free(addrs); + return(0); + } + addrs[strlen(addrs)-1] = 0; + sprintf(params,"[%d, 99999999, [%s]]",coin->minconfirms,addrs+1); + free(addrs); + } else return(0); + } + else + { + if ( (params = calloc(1,128)) == 0 ) + return(0); + sprintf(params,"%d, 99999999",coin->minconfirms); + } + //printf("issue listunspent.(%s)\n",params); + if ( (retstr= bitcoind_passthru(coin->name,coin->serverport,coin->userpass,"listunspent",params)) != 0 ) + { + //printf("unspents (%s)\n",retstr); + if ( (json= cJSON_Parse(retstr)) != 0 ) + { + if ( is_cJSON_Array(json) != 0 && (num= cJSON_GetArraySize(json)) > 0 ) + { + ups = calloc(num,sizeof(struct subatomic_unspent_tx)); + for (i=j=0; i 0 ) + { + int _decreasing_signedint64(const void *a,const void *b); + if ( j > 1 ) + qsort(ups,j,sizeof(*ups),_decreasing_signedint64); + if ( coin->changeaddr[0] == 0 ) + strcpy(coin->changeaddr,ups[0].address.buf); + //for (i=0; iname,account != 0 ? account : ""); + return(ups); +} + +struct subatomic_unspent_tx *subatomic_bestfit(struct coin777 *coin,struct subatomic_unspent_tx *unspents,int32_t numunspents,uint64_t value,int32_t mode) +{ + int32_t i; uint64_t above,below,gap,atx_value; struct subatomic_unspent_tx *vin,*abovevin,*belowvin; + abovevin = belowvin = 0; + for (above=below=i=0; iamount; + //printf("(%.8f vs %.8f)\n",dstr(atx_value),dstr(value)); + if ( atx_value == value ) + return(vin); + else if ( atx_value > value ) + { + gap = (atx_value - value); + if ( above == 0 || gap < above ) + { + above = gap; + abovevin = vin; + } + } + else if ( mode == 0 ) + { + gap = (value - atx_value); + if ( below == 0 || gap < below ) + { + below = gap; + belowvin = vin; + } + } + } + if ( (vin= (abovevin != 0) ? abovevin : belowvin) == 0 && mode == 1 ) + vin = unspents; + return(vin); +} + +int64_t subatomic_calc_rawinputs(struct coin777 *coin,struct subatomic_rawtransaction *rp,uint64_t amount,struct subatomic_unspent_tx *ups,int32_t num,uint64_t donation) +{ + uint64_t sum = 0; struct subatomic_unspent_tx *up; int32_t i; + rp->inputsum = rp->numinputs = 0; + printf("unspent num %d, amount %.8f vs donation %.8f txfee %.8f\n",num,dstr(amount),dstr(donation),dstr(coin->mgw.txfee)); + if ( coin == 0 || num == 0 ) // (donation + coin->mgw.txfee) > amount || + return(0); + amount += coin->mgw.txfee + donation; + for (i=0; iinputs)/sizeof(*rp->inputs))); i++) + { + if ( (up= subatomic_bestfit(coin,ups,num,amount,0)) != 0 ) + { + sum += up->amount; + rp->inputs[rp->numinputs++] = *up; + if ( sum >= amount ) + { + rp->amount = (amount - coin->mgw.txfee - donation); + rp->change = (sum - amount); + rp->inputsum = sum; + printf("numinputs %d sum %.8f vs amount %.8f change %.8f -> txfee %.8f\n",rp->numinputs,dstr(rp->inputsum),dstr(amount),dstr(rp->change),dstr(sum - rp->change - rp->amount)); + return(rp->inputsum); + } + } + printf("error getting bestfit unspent\n"); + break; + } + printf("i.%d error numinputs %d sum %.8f\n",i,rp->numinputs,dstr(rp->inputsum)); + return(0); +} + +char *subatomic_gen_rawtransaction(char *skipaddr,struct coin777 *coin,struct subatomic_rawtransaction *rp,char *signcoinaddr,uint32_t locktime,uint32_t vin0sequenceid,char *redeem0script) +{ + char *rawparams,*retstr,*txid=0; int64_t value; long len; struct cointx_info *cointx; + if ( (rawparams= subatomic_rawtxid_json(coin,rp)) != 0 ) + { + _stripwhite(rawparams,' '); + //printf("create.(%s)\n",rawparams); + if ( (retstr= bitcoind_RPC(0,coin->name,coin->serverport,coin->userpass,"createrawtransaction",rawparams)) != 0 ) + { + if ( retstr[0] != 0 ) + { + // printf("calc_rawtransaction retstr.(%s)\n",retstr); + safecopy(rp->rawtransaction,retstr,sizeof(rp->rawtransaction)); + len = strlen(rp->rawtransaction); + if ( len < 8 ) + { + printf("funny rawtransactionlen %ld??\n",len); + free(rawparams); + return(0); + } + if ( locktime != 0 || redeem0script != 0 ) + { + if ( (cointx= _decode_rawtransaction(rp->rawtransaction,coin->mgw.oldtx_format)) != 0 ) + { + //printf("%s\n->\n",rp->rawtransaction); + cointx->nlocktime = locktime; + cointx->inputs[0].sequence = vin0sequenceid; + if ( redeem0script != 0 ) + safecopy(cointx->outputs[0].script,redeem0script,sizeof(cointx->outputs[0].script)); + _emit_cointx(rp->rawtransaction,sizeof(rp->rawtransaction),cointx,coin->mgw.oldtx_format); + _validate_decoderawtransaction(rp->rawtransaction,cointx,coin->mgw.oldtx_format); + //printf("spliced tx.(%s)\n",rp->rawtransaction); + free(cointx); + } + printf("locktime.%d sequenceid.%d signcoinaddr.(%s)\n",locktime,vin0sequenceid,signcoinaddr!=0?signcoinaddr:""); + } + if ( signcoinaddr != 0 ) + { + txid = subatomic_signtx(skipaddr,0,&value,signcoinaddr,rp->signedtransaction,sizeof(rp->signedtransaction),coin,rp,rp->rawtransaction); + printf("signedtxid.%s\n",txid); + } + } + free(retstr); + } else printf("error creating rawtransaction from.(%s)\n",rawparams); + free(rawparams); + } else printf("error creating rawparams\n"); + return(txid); +} + +char *subatomic_signp2sh(char *sigstr,struct coin777 *coin,struct cointx_info *refT,int32_t msigflag,int32_t lockblocks,int32_t redeemi,char *redeemscript,int32_t p2shflag,char *privkeystr,int32_t privkeyind,char *othersig,char *otherpubkey,char *checkprivkey) +{ + char hexstr[1024],pubP[128],*sig0,*sig1; bits256 hash2; uint8_t data[4096],sigbuf[512]; struct bp_key key,keyV; + struct cointx_info *T; int32_t i,n; void *sig = NULL; size_t siglen = 0; struct cointx_input *vin; + if ( (T= calloc(1,sizeof(*T))) == 0 ) + return(0); + if ( privkeystr != 0 ) + btc_setprivkey(&key,privkeystr); + *T = *refT; vin = &T->inputs[redeemi]; + for (i=0; inuminputs; i++) + strcpy(T->inputs[i].sigs,"00"); + strcpy(vin->sigs,redeemscript); + if ( msigflag == 0 ) + { + vin->sequence = (uint32_t)-1; + T->nlocktime = 0; + } + else + { + if ( vin->sequence == 0 ) + vin->sequence = (uint32_t)time(NULL); + if ( T->nlocktime == 0 && lockblocks != 0 ) + { + if ( lockblocks != 0 ) + { + coin->ramchain.RTblocknum = _get_RTheight(&coin->ramchain.lastgetinfo,coin->name,coin->serverport,coin->userpass,coin->ramchain.RTblocknum); + if ( coin->ramchain.RTblocknum == 0 ) + { + printf("cant get RTblocknum for %s\n",coin->name); + free(T); + return(0); + } + lockblocks += coin->ramchain.RTblocknum; + } + T->nlocktime = lockblocks; + } + } + //disp_cointx(&T); + emit_cointx(&hash2,data,sizeof(data),T,coin->mgw.oldtx_format,SIGHASH_ALL); + //printf("HASH2.(%llx)\n",(long long)hash2.txid); + if ( msigflag != 0 ) + { + if ( othersig != 0 ) + { + n = (int32_t)strlen(otherpubkey) >> 1; + decode_hex(data,n,otherpubkey); + if ( bp_key_init(&keyV) == 0 || bp_pubkey_set(&keyV,data,n) == 0 ) + { + printf("cant set pubkey\n"); + free(T); + return(0); + } + n = (int32_t)strlen(othersig) >> 1; + decode_hex(data,n,othersig); + if ( data[n-1] != SIGHASH_ALL ) + { + printf("othersig.(%s) hash type mismatch %d != %d\n",othersig,data[n-1],SIGHASH_ALL); + free(T); + return(0); + } + if ( bp_verify(&keyV,hash2.bytes,sizeof(hash2),data,n-1) == 0 ) + { + hexstr[0] = 0; + if ( checkprivkey != 0 ) + { + //printf("checkprivkey.(%s)\n",checkprivkey); + btc_setprivkey(&keyV,checkprivkey); + void *dispkey; size_t slen; + bp_privkey_get(&keyV,&dispkey,&slen); + //for (i=0; isigs,"00%02x%s%02x%s51",(int32_t)strlen(sig0)>>1,sig0,(int32_t)strlen(sig1)>>1,sig1); + //printf("after A.(%s) othersig.(%s) siglen.%02lx -> (%s)\n",hexstr,othersig != 0 ? othersig : "",siglen,vin->sigs); + } + else + { + printf("error signing\n"); + free(T); + return(0); + } + } + else vin->sigs[0] = 0; + } + else + { + if ( bp_sign(&key,hash2.bytes,sizeof(hash2),&sig,&siglen) != 0 && btc_getpubkey(pubP,data,&key) > 0 ) + { + memcpy(sigbuf,sig,siglen); + sigbuf[siglen++] = SIGHASH_ALL; + init_hexbytes_noT(hexstr,sigbuf,(int32_t)siglen); + sprintf(vin->sigs,"%02x%s%02x%s00",(int32_t)siglen,hexstr,(int32_t)strlen(pubP)/2,pubP); + //printf("after P.(%s) siglen.%02lx\n",vin->sigs,siglen); + } + } + if ( vin->sigs[0] != 0 ) + { + if ( p2shflag != 0 ) + sprintf(&vin->sigs[strlen(vin->sigs)],"4c%02x",(int32_t)strlen(redeemscript)/2); + sprintf(&vin->sigs[strlen(vin->sigs)],"%s",redeemscript); + } + //printf("scriptSig.(%s)\n",vin->sigs); + _emit_cointx(hexstr,sizeof(hexstr),T,coin->mgw.oldtx_format); + //disp_cointx(&T); + free(T); + return(clonestr(hexstr)); + //printf("T.msigredeem %d -> (%s)\n",msigflag,hexstr); +} + +char *subatomic_fundingtx(char *refredeemscript,struct subatomic_rawtransaction *funding,struct coin777 *coin,char *mypubkey,char *otherpubkey,char *pkhash,uint64_t amount,int32_t lockblocks) +{ + char scriptPubKey[128],mycoinaddr[64],p2shaddr[64],sigstr[512],*refundtx=0,*redeemscript,*txid=0; struct subatomic_unspent_tx *utx; + uint64_t total,donation; int32_t num,n=0,lockblock = 0; struct cointx_info *refT; uint8_t rmd160[20]; + memset(funding,0,sizeof(*funding)); + refredeemscript[0] = 0; + if ( (redeemscript= create_atomictx_scripts(coin->p2shtype,scriptPubKey,p2shaddr,mypubkey,otherpubkey,pkhash)) != 0 ) + { + strcpy(refredeemscript,redeemscript); + if ( btc_coinaddr(mycoinaddr,coin->addrtype,mypubkey) != 0 && (utx= gather_unspents(&total,&num,coin,0)) != 0 ) + { + donation = subatomic_donation(coin,amount); + //printf("CREATE FUNDING TX.(%s) [%s %s %s] for %.8f -> %s locktime.%u donation %.8f\n",coin->name,mypubkey,otherpubkey,pkhash,dstr(amount),p2shaddr,lockblock,dstr(donation)); + if ( subatomic_calc_rawinputs(coin,funding,amount,utx,num,donation) >= amount ) + { + if ( funding->amount == amount && funding->change == (funding->inputsum - amount - coin->mgw.txfee - donation) ) + { + safecopy(funding->destaddrs[n],p2shaddr,sizeof(funding->destaddrs[n])); + funding->destamounts[n] = amount; + n++; + } + if ( donation != 0 ) + { + if ( coin->donationaddress[0] != 0 ) + { + safecopy(funding->destaddrs[n],coin->donationaddress,sizeof(funding->destaddrs[n])); + funding->destamounts[n] = donation; + n++; + } else funding->change += donation; + } + if ( funding->change != 0 ) + { + if ( coin->changeaddr[0] == 0 ) + { + printf("no changeaddress for (%s)\n",coin->name); + return(0); + } + safecopy(funding->destaddrs[n],coin->changeaddr,sizeof(funding->destaddrs[n])); + funding->destamounts[n] = funding->change; + n++; + } + funding->numoutputs = n; + if ( (txid= subatomic_gen_rawtransaction(0,coin,funding,p2shaddr,lockblock,lockblock==0?0xffffffff:(uint32_t)time(NULL),coin->usep2sh!=0?0:redeemscript)) == 0 ) + printf("error creating tx\n"); + else + { + if ( (refT= calloc(1,sizeof(*refT))) == 0 ) + return(0); + refT->version = 1; + refT->timestamp = (uint32_t)time(NULL); + strcpy(refT->inputs[0].tx.txidstr,txid); + refT->inputs[0].tx.vout = 0; + refT->numinputs = 1; + strcpy(scriptPubKey,"76a914"); + calc_OP_HASH160(scriptPubKey+6,rmd160,mypubkey); + strcat(scriptPubKey,"88ac"); + if ( mycoinaddr[0] != 0 ) + { + strcpy(refT->outputs[0].coinaddr,mycoinaddr); + strcpy(refT->outputs[0].script,scriptPubKey); + refT->outputs[0].value = funding->destamounts[0] - coin->mgw.txfee; + refT->numoutputs = 1; + if ( lockblocks == 0 ) + lockblocks = 10; + refundtx = subatomic_signp2sh(sigstr,coin,refT,1,lockblocks,0,redeemscript,coin->usep2sh,0,0,0,0,0); + free(refT); + } else printf("cant get %s addr from (%s)\n",coin->name,mypubkey); + } + } else printf("error: probably not enough funds\n"); + } else printf("error: btc_coinaddr.(%s)\n",mycoinaddr); + free(redeemscript); + } else printf("subatomic_fundingtx: cant create redeemscript\n"); + return(refundtx); +} + +char *subatomic_spendtx(struct destbuf *spendtxid,char *vintxid,char *refundsig,struct coin777 *coin,char *otherpubkey,char *mypubkey,char *onetimepubkey,uint64_t amount,char *refundtx,char *refredeemscript) +{ + char scriptPubKey[128],p2shaddr[64],rmdstr[41],onetimecoinaddr[64],msigcoinaddr[64],sigstr[512]; cJSON *json; + char *redeemscript,*signedtx,*spendtx=0,*mprivkey,*oprivkey; uint8_t rmd160[20]; long diff=0; struct cointx_info *refundT=0; + refundsig[0] = onetimecoinaddr[0] = msigcoinaddr[0] = spendtxid->buf[0] = vintxid[0] = 0; + if ( btc_coinaddr(onetimecoinaddr,coin->addrtype,onetimepubkey) != 0 && btc_coinaddr(msigcoinaddr,coin->addrtype,mypubkey) != 0 ) + { + //printf("mypubkey.(%s) -> (%s)\n",mypubkey,msigcoinaddr); + calc_OP_HASH160(rmdstr,rmd160,onetimepubkey); + amount -= coin->mgw.txfee; + coin->ramchain.RTblocknum = _get_RTheight(&coin->ramchain.lastgetinfo,coin->name,coin->serverport,coin->userpass,coin->ramchain.RTblocknum); + if ( (refundT= _decode_rawtransaction(refundtx,coin->mgw.oldtx_format)) != 0 && refundT->inputs[0].sequence != 0xffffffff && refundT->nlocktime != 0 && (diff= ((long)refundT->nlocktime - coin->ramchain.RTblocknum)) > 1 && diff < 1000 ) + { + strcpy(vintxid,refundT->inputs[0].tx.txidstr); + if ( (redeemscript= create_atomictx_scripts(coin->p2shtype,scriptPubKey,p2shaddr,otherpubkey,mypubkey,rmdstr)) != 0 ) + { + if ( refundT->outputs[0].value == amount && strcmp(refredeemscript,redeemscript) == 0 && refundT->numinputs == 1 && refundT->numoutputs == 1 ) + { + if ( (mprivkey= dumpprivkey(coin->name,coin->serverport,coin->userpass,msigcoinaddr)) != 0 && (oprivkey= dumpprivkey(coin->name,coin->serverport,coin->userpass,onetimecoinaddr)) != 0 ) + { + //printf("mprivkey.(%s)\n",mprivkey); + if ( (signedtx= subatomic_signp2sh(refundsig,coin,refundT,1,0,0,redeemscript,coin->usep2sh,mprivkey,1,0,0,0)) != 0 ) + { + //printf("one sig.(%s)\n",signedtx); + free(signedtx); + strcpy(refundT->outputs[0].coinaddr,onetimecoinaddr); + sprintf(scriptPubKey,"76a914%s88ac",rmdstr); + strcpy(refundT->outputs[0].script,scriptPubKey); + spendtx = subatomic_signp2sh(sigstr,coin,refundT,0,0,0,redeemscript,coin->usep2sh,oprivkey,0,0,0,0); + if ( (json= get_decoderaw_json(coin,spendtx)) != 0 ) + { + copy_cJSON(spendtxid,jobj(json,"txid")); + free_json(json); + } + } else printf("Error signing\n"); + free(mprivkey); + free(oprivkey); + } + else + { + if ( mprivkey != 0 ) + free(mprivkey); + printf("error getting privkeys M.(%s) onetime.(%s)\n",msigcoinaddr,onetimecoinaddr); + } + } else printf("error (%.8f vs %.8f) comparing redeemscript.(%s) vs (%s) io.(%d %d)\n",dstr(refundT->outputs[0].value),dstr(amount),refredeemscript,redeemscript,refundT->numinputs,refundT->numoutputs); + free(redeemscript); + } else printf("error creating redeemscript\n"); + free(refundT); + } else printf("error decoding refundT.%p or diff %ld too big (%u %u)\n",refundT,diff,refundT->nlocktime,coin->ramchain.RTblocknum); + } else printf("error getting addresses (%s) (%s)\n",msigcoinaddr,onetimecoinaddr); + return(spendtx); +} + +char *subatomic_validate(struct coin777 *coin,char *pubA,char *pubB,char *pkhash,char *refundtx,char *refundsig) +{ + char scriptPubKey[512],mycoinaddr[64],p2shaddr[128],mysig[512],*redeemscript,*privkeystr,*signedrefund=0; + struct cointx_info *refundT; + if ( (refundT= _decode_rawtransaction(refundtx,coin->mgw.oldtx_format)) != 0 && btc_coinaddr(mycoinaddr,coin->addrtype,pubA) != 0 ) + { + if ( (privkeystr= dumpprivkey(coin->name,coin->serverport,coin->userpass,mycoinaddr)) != 0 ) + { + if ( (redeemscript= create_atomictx_scripts(coin->p2shtype,scriptPubKey,p2shaddr,pubA,pubB,pkhash)) != 0 ) + { + if ( (signedrefund= subatomic_signp2sh(mysig,coin,refundT,1,0,0,redeemscript,1,privkeystr,0,refundsig,pubB,0)) != 0 ) + { + //printf("SIGNEDREFUND.(%s)\n",signedrefund); + } + free(redeemscript); + } + free(privkeystr); + } + free(refundT); + } + return(signedrefund); +} + +void test_subatomic() +{ + char pkhash[8192],pubA[67],pubB[67],pubP[67]; uint8_t tmpbuf[512]; struct coin777 *coin; + struct subatomic_rawtransaction funding; char refredeemscript[4096],vintxid[128],swapacct[64],othercoinaddr[64],mycoinaddr[64],onetimeaddr[64],refundsig[512],*signedrefund,*refundtx=0,*spendtx=0; + uint64_t amount; struct destbuf pubkey; struct destbuf spendtxid; + coin = coin777_find("BTCD",1); + if ( strcmp(coin->name,"BTC") == 0 ) + coin->mgw.oldtx_format = 1; + //coin->usep2sh = 0; + strcpy(mycoinaddr,coin->atomicsend),get_pubkey(&pubkey,coin->name,coin->serverport,coin->userpass,mycoinaddr), strcpy(pubA,pubkey.buf); + strcpy(othercoinaddr,coin->atomicrecv),get_pubkey(&pubkey,coin->name,coin->serverport,coin->userpass,othercoinaddr), strcpy(pubB,pubkey.buf); + sprintf(swapacct,"%u",777); + if ( get_acct_coinaddr(onetimeaddr,coin->name,coin->serverport,coin->userpass,swapacct) != 0 ) + { + get_pubkey(&pubkey,coin->name,coin->serverport,coin->userpass,onetimeaddr); + strcpy(pubP,pubkey.buf); + printf("onetimeadddr.(%s) pubkey.(%s)\n",onetimeaddr,pubP); + } + calc_OP_HASH160(pkhash,tmpbuf,pubP); + amount = 20000; + printf("pkhash.(%s)\n",pkhash); + if ( (refundtx= subatomic_fundingtx(refredeemscript,&funding,coin,pubA,pubB,pkhash,20000,10)) != 0 ) + { + printf("FUNDING.(%s) unsignedrefund.(%s)\n",funding.signedtransaction,refundtx); + if ( (spendtx= subatomic_spendtx(&spendtxid,vintxid,refundsig,coin,pubA,pubB,pubP,amount,refundtx,refredeemscript)) != 0 ) + { + printf("vin.%s SPENDTX.(%s) %s refundsig.(%s)\n",vintxid,spendtx,spendtxid.buf,refundsig); + if ( (signedrefund= subatomic_validate(coin,pubA,pubB,pkhash,refundtx,refundsig)) != 0 ) + { + printf("SIGNEDREFUND.(%s)\n",signedrefund); + free(signedrefund); + } else printf("null signedrefund\n"); + } else printf("null spendtx\n"); + free(refundtx); + } + getchar(); +} +#endif + +#endif diff --git a/iguana/InstantDEX/tradebots.h b/iguana/InstantDEX/tradebots.h new file mode 100755 index 000000000..60d570dfb --- /dev/null +++ b/iguana/InstantDEX/tradebots.h @@ -0,0 +1,323 @@ +/****************************************************************************** + * Copyright © 2014-2015 The SuperNET Developers. * + * * + * See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at * + * the top-level directory of this distribution for the individual copyright * + * holder information and the developer policies on copyright and licensing. * + * * + * Unless otherwise agreed in a custom licensing agreement, no part of the * + * SuperNET software, including this file may be copied, modified, propagated * + * or distributed except according to the terms contained in the LICENSE file * + * * + * Removal or modification of this copyright notice is prohibited. * + * * + ******************************************************************************/ + + +#ifndef xcode_tradebots_h +#define xcode_tradebots_h + +#define TRADEBOT_DEFAULT_DURATION (600) +struct tradebot_info +{ + char buf[512],name[64],*prevobookstr,NXTADDR[64],NXTACCTSECRET[64]; + uint32_t starttime,expiration,finishtime,startedtrades,apitag; + int32_t numtrades,havetrade,numlinks; + double price,volume; + struct prices777_order trades[256]; void *cHandles[256]; int32_t curlings[256]; + struct tradebot_info *linkedbots[8]; + struct apitag_info *api; + struct tradebot_info *oppo; + struct InstantDEX_quote iQ; +}; + +// ./SNapi "{\"allfields\":1,\"agent\":\"InstantDEX\",\"method\":\"orderbook\",\"exchange\":\"active\",\"base\":\"NXT\",\"rel\":\"BTC\"}" + +// test balance verifier +// test tradeleg verifier +// test pass through quotes +// user lockin addrs +// atomic swaps using 2of3 msig +// broadcast request to all marketmakers +// pick best response and do BTC <-> NXT and NXT <-> ABC + +int32_t tradebot_havealltrades(struct tradebot_info *bot) +{ + int32_t i; + if ( bot->havetrade != 0 ) + { + if ( bot->numlinks > 0 ) + { + for (i=0; inumlinks; i++) + if ( bot->linkedbots[i] == 0 || bot->linkedbots[i]->havetrade == 0 ) + return(0); + } + return(1); + } + return(0); +} + +struct tradebot_info *tradebot_compile(cJSON *argjson,struct InstantDEX_quote *iQ,struct apitag_info *api) +{ + static uint64_t lastmonce; + uint64_t monce; char *name,*tmp,*tmp2; int32_t duration; struct tradebot_info *bot = calloc(1,sizeof(*bot)); + monce = (long long)(1000*time(NULL) + milliseconds()); + if ( monce == lastmonce ) + monce++; + lastmonce = monce; + bot->iQ = *iQ; + bot->api = api; + if ( (duration= juint(argjson,"duration")) == 0 ) + duration = TRADEBOT_DEFAULT_DURATION; + bot->expiration = (uint32_t)time(NULL) + duration; + if ( (name= jstr(argjson,"name")) != 0 ) + safecopy(bot->name,name,sizeof(bot->name)); + else sprintf(bot->name,"bot.%llu",monce); + if ( (tmp= jstr(argjson,"botnxt")) == 0 || (tmp2= jstr(argjson,"secret")) == 0 ) + { + safecopy(bot->NXTADDR,SUPERNET.NXTADDR,sizeof(bot->NXTADDR)); + safecopy(bot->NXTACCTSECRET,SUPERNET.NXTACCTSECRET,sizeof(bot->NXTACCTSECRET)); + } + else + { + safecopy(bot->NXTADDR,tmp,sizeof(bot->NXTADDR)); + safecopy(bot->NXTACCTSECRET,tmp2,sizeof(bot->NXTACCTSECRET)); + } + //bot->arbmargin = jdouble(argjson,"arbmargin"); + return(bot); +} + +int32_t tradebot_acceptable(struct tradebot_info *bot,cJSON *item) +{ + double price,volume; int32_t dir,i,n; cJSON *trades,*trade; + if ( bot->iQ.s.isask != 0 ) + dir = -1; + else dir = 1; + bot->price = price = jdouble(item,"price"); + bot->volume = volume = jdouble(item,"volume"); + if ( (trades= jarray(&n,item,"trades")) != 0 ) + { + /*{ + "plugin": "InstantDEX", + "method": "tradesequence", + "dotrade": 1, + "price": 0.00001858, + "volume": 484.39181916, + "trades": [ + { + "basket": "bid", + "price": 0.00001858, + "volume": 484.39181916, + "group": 0, + "exchange": "bittrex", + "base": "NXT", + "rel": "BTC", + "trade": "sell", + "name": "NXT/BTC", + "orderprice": 0.00001858, + "ordervolume": 484.39181916 + } + ] + }*/ + if ( n == 1 && is_cJSON_Array(jitem(trades,0)) != 0 ) + { + //printf("NESTED ARRAY DETECTED\n"); + trades = jitem(trades,0); + n = cJSON_GetArraySize(trades); + } + sprintf(bot->buf,"[%s %s%s %.8f %.4f] <- ",bot->iQ.s.isask != 0 ? "sell" : "buy ",bot->iQ.base,bot->iQ.rel,price,volume); + for (i=0; ibuf+strlen(bot->buf),"[%s %s %.8f %.4f] ",jstr(trade,"exchange"),jstr(trade,"trade"),jdouble(trade,"orderprice"),jdouble(trade,"ordervolume")); + } + sprintf(bot->buf+strlen(bot->buf),"n.%d\n",n); + if ( bot->iQ.s.isask == 0 && bot->oppo != 0 && bot->price > 0. && bot->oppo->price > 0 ) + { + //if ( bot->price < bot->oppo->price ) + { + printf("%s%s%.8f -> %.8f = gain %.3f%%\n\n",bot->buf,bot->oppo->buf,bot->price,bot->oppo->price,(bot->oppo->price/bot->price - 1)*100); + } + } + } + //printf("%s: dir.%d price %.8f vol %f vs bot price %.8f vol %f\n",bot->name,dir,price,volume,bot->iQ.s.price,bot->iQ.s.vol); + //if ( (dir > 0 && price < bot->iQ.s.price) || (dir < 0 && price >= bot->iQ.s.price) ) + return(1); + return(0); +} + +int32_t tradebot_isvalidtrade(struct tradebot_info *bot,struct prices777_order *order,cJSON *retjson) +{ + cJSON *array,*item; char *resultval; double balance,required; int32_t i,n,valid = 0; + if ( (array= jarray(&n,retjson,"traderesults")) != 0 ) + { + for (i=0; ipend) != 0 && pend->finishtime != 0 ) + return(1); + else return(0); +} + +int32_t tradebot_haspending(struct tradebot_info *bot) +{ + int32_t i,finished; + for (i=finished=0; inumtrades; i++) + { + if ( tradebot_tradedone(bot,&bot->trades[i]) > 0 ) + finished++; + } + return(finished < bot->numtrades); +} + +void tradebot_free(struct tradebot_info *bot) +{ + int32_t i; struct pending_trade *pend; + for (i=0; inumtrades; i++) + { + if ( (pend= bot->trades[i].pend) != 0 ) + free_pending(pend); + if ( bot->trades[i].retitem != 0 ) + free_json(bot->trades[i].retitem); + if ( bot->cHandles[i] != 0 ) + { + while ( bot->curlings[i] != 0 ) + { + fprintf(stderr,"%s: wait for curlrequest[%d] to finish\n",bot->name,i); + sleep(3); + } + curlhandle_free(bot->cHandles[i]); + } + } + if ( bot->prevobookstr != 0 ) + free(bot->prevobookstr); + free(bot); +} + +void Tradebot_loop(void *ptr) +{ + int32_t i,n,dotrade; char *obookstr,*retstr; cJSON *json,*array,*item,*retjson,*submit; + char jsonstr[1024]; struct tradebot_info *bot = ptr; + printf("START Tradebot.(%s)\n",bot->name); + while ( bot->finishtime == 0 && time(NULL) < bot->expiration ) + { + if ( bot->startedtrades == 0 ) + { + sprintf(jsonstr,"{\"allfields\":1,\"agent\":\"InstantDEX\",\"method\":\"orderbook\",\"exchange\":\"active\",\"base\":\"%s\",\"rel\":\"%s\"}",bot->iQ.base,bot->iQ.rel); + if ( (json= cJSON_Parse(jsonstr)) == 0 ) + { + printf("cant parse.(%s)\n",jsonstr); + exit(-1); + } + obookstr = SuperNET_SNapi(bot->api,json,0,1); + //printf("GOT.(%s)\n",obookstr); + free_json(json); + if ( bot->prevobookstr == 0 || strcmp(obookstr,bot->prevobookstr) != 0 ) + { + if ( bot->prevobookstr != 0 ) + free(bot->prevobookstr); + bot->prevobookstr = obookstr; + //printf("UPDATE.(%s)\n",obookstr); + submit = 0; + if ( (json= cJSON_Parse(obookstr)) != 0 ) + { + array = (bot->iQ.s.isask != 0) ? jarray(&n,json,"bids") : jarray(&n,json,"asks"); + if ( array != 0 && n > 0 ) + { + dotrade = 0; + for (i=0; i<1; i++) + { + item = jitem(array,i); + if ( tradebot_acceptable(bot,item) > 0 ) + { + submit = cJSON_Duplicate(item,1); + if ( jobj(submit,"dotrade") == 0 ) + jaddnum(submit,"dotrade",0); + else cJSON_ReplaceItemInObject(submit,"dotrade",cJSON_CreateNumber(0)); + retstr = SuperNET_SNapi(bot->api,submit,0,1); + free_json(submit); + //retstr = InstantDEX_tradesequence(bot->curlings,bot,bot->cHandles,&bot->numtrades,bot->trades,(int32_t)( sizeof(bot->trades)/sizeof(*bot->trades)),dotrade,bot->NXTADDR,bot->NXTACCTSECRET,item); + if ( retstr != 0 ) + { + if ( (retjson= cJSON_Parse(retstr)) != 0 ) + { + if ( tradebot_isvalidtrade(bot,&bot->trades[i],retjson) > 0 ) + bot->havetrade = 1; + free_json(retjson); + } + free(retstr); + if ( bot->havetrade == 0 ) + continue; + } + } + break; + } + if ( 0 && submit != 0 && tradebot_havealltrades(bot) != 0 ) + { + dotrade = 1; + cJSON_ReplaceItemInObject(submit,"dotrade",cJSON_CreateNumber(1)); + bot->startedtrades = (uint32_t)time(NULL); + retstr = InstantDEX_tradesequence(bot->curlings,bot,bot->cHandles,&bot->numtrades,bot->trades,(int32_t)(sizeof(bot->trades)/sizeof(*bot->trades)),dotrade,bot->NXTADDR,bot->NXTACCTSECRET,item); + printf("TRADE RESULT.(%s)\n",retstr); + break; + } + } + free_json(json); + } + } + } + else if ( bot->startedtrades != 0 ) + { + if ( tradebot_haspending(bot) > 0 && bot->finishtime == 0 ) + bot->finishtime = (uint32_t)time(NULL); + } + usleep(5000000); + } + while ( tradebot_haspending(bot) != 0 ) + sleep(60); + printf("FINISHED Tradebot.(%s) at %u finishtime.%u expiration.%u\n",bot->name,(uint32_t)time(NULL),bot->finishtime,bot->expiration); + tradebot_free(bot); +} + +char *Tradebot_parser(cJSON *argjson,struct InstantDEX_quote *iQ,struct apitag_info *api) +{ + char *submethod,*exchange; struct tradebot_info *bot,*oppobot; + printf("InstantDEX_tradebot.(%s) (%s/%s)\n",jprint(argjson,0),iQ->base,iQ->rel); + if ( (submethod= jstr(argjson,"submethod")) != 0 && (exchange= jstr(argjson,"exchange")) != 0 && strcmp(exchange,"active") == 0 && iQ != 0 ) + { + if ( strcmp(submethod,"simplebot") == 0 ) + { + if ( (bot= tradebot_compile(argjson,iQ,api)) == 0 ) + return(clonestr("{\"error\":\"tradebot compiler error\"}")); + iQ->s.isask ^= 1; + if ( (oppobot= tradebot_compile(argjson,iQ,api)) == 0 ) + return(clonestr("{\"error\":\"tradebot compiler error\"}")); + bot->oppo = oppobot; + oppobot->oppo = bot; + iguana_launch("bot",(void *)Tradebot_loop,bot); + iguana_launch("oppobot",(void *)Tradebot_loop,oppobot); + return(clonestr("{\"result\":\"tradebot started\"}")); + } else return(clonestr("{\"error\":\"unrecognized tradebot command\"}")); + return(clonestr("{\"result\":\"tradebot command processed\"}")); + } else return(clonestr("{\"error\":\"no prices777 or no tradebot submethod or not active exchange\"}")); +} + +#endif diff --git a/iguana/InstantDEX/trades.h b/iguana/InstantDEX/trades.h new file mode 100755 index 000000000..9667c7da0 --- /dev/null +++ b/iguana/InstantDEX/trades.h @@ -0,0 +1,1583 @@ +/****************************************************************************** + * Copyright © 2014-2015 The SuperNET Developers. * + * * + * See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at * + * the top-level directory of this distribution for the individual copyright * + * holder information and the developer policies on copyright and licensing. * + * * + * Unless otherwise agreed in a custom licensing agreement, no part of the * + * SuperNET software, including this file may be copied, modified, propagated * + * or distributed except according to the terms contained in the LICENSE file * + * * + * Removal or modification of this copyright notice is prohibited. * + * * + ******************************************************************************/ + +#ifndef xcode_trades_h +#define xcode_trades_h + +struct tradehistory { uint64_t assetid,purchased,sold; }; + +struct tradehistory *_update_tradehistory(struct tradehistory *hist,uint64_t assetid,uint64_t purchased,uint64_t sold) +{ + int32_t i = 0; + if ( hist == 0 ) + hist = calloc(1,sizeof(*hist)); + if ( hist[i].assetid != 0 ) + { + for (i=0; hist[i].assetid!=0; i++) + if ( hist[i].assetid == assetid ) + break; + } + if ( hist[i].assetid == 0 ) + { + hist = realloc(hist,(i+2) * sizeof(*hist)); + memset(&hist[i],0,2 * sizeof(hist[i])); + hist[i].assetid = assetid; + } + if ( hist[i].assetid == assetid ) + { + hist[i].purchased += purchased; + hist[i].sold += sold; + printf("hist[%d] %llu +%llu -%llu -> (%llu %llu)\n",i,(long long)hist[i].assetid,(long long)purchased,(long long)sold,(long long)hist[i].purchased,(long long)hist[i].sold); + } else printf("_update_tradehistory: impossible case!\n"); + return(hist); +} + +struct tradehistory *update_tradehistory(struct tradehistory *hist,uint64_t srcasset,uint64_t srcamount,uint64_t destasset,uint64_t destamount) +{ + hist = _update_tradehistory(hist,srcasset,0,srcamount); + hist = _update_tradehistory(hist,destasset,destamount,0); + return(hist); +} + +cJSON *_tradehistory_json(struct tradehistory *asset) +{ + cJSON *json = cJSON_CreateObject(); + char numstr[64]; + sprintf(numstr,"%llu",(long long)asset->assetid), cJSON_AddItemToObject(json,"assetid",cJSON_CreateString(numstr)); + sprintf(numstr,"%.8f",dstr(asset->purchased)), cJSON_AddItemToObject(json,"purchased",cJSON_CreateString(numstr)); + sprintf(numstr,"%.8f",dstr(asset->sold)), cJSON_AddItemToObject(json,"sold",cJSON_CreateString(numstr)); + sprintf(numstr,"%.8f",dstr(asset->purchased) - dstr(asset->sold)), cJSON_AddItemToObject(json,"net",cJSON_CreateString(numstr)); + return(json); +} + +cJSON *tradehistory_json(struct tradehistory *hist,cJSON *array) +{ + int32_t i; char assetname[64],numstr[64]; cJSON *assets,*netpos,*item,*json = cJSON_CreateObject(); + cJSON_AddItemToObject(json,"rawtrades",array); + assets = cJSON_CreateArray(); + netpos = cJSON_CreateArray(); + for (i=0; hist[i].assetid!=0; i++) + { + cJSON_AddItemToArray(assets,_tradehistory_json(&hist[i])); + item = cJSON_CreateObject(); + get_assetname(assetname,hist[i].assetid); + cJSON_AddItemToObject(item,"asset",cJSON_CreateString(assetname)); + sprintf(numstr,"%.8f",dstr(hist[i].purchased) - dstr(hist[i].sold)), cJSON_AddItemToObject(item,"net",cJSON_CreateString(numstr)); + cJSON_AddItemToArray(netpos,item); + } + cJSON_AddItemToObject(json,"assets",assets); + cJSON_AddItemToObject(json,"netpositions",netpos); + return(json); +} + +cJSON *tabulate_trade_history(uint64_t mynxt64bits,cJSON *array) +{ + int32_t i,n; + cJSON *item; + long balancing; + struct tradehistory *hist = 0; + uint64_t src64bits,srcamount,srcasset,dest64bits,destamount,destasset,jump64bits,jumpamount,jumpasset; + //{"requestType":"processjumptrade","NXT":"5277534112615305538","assetA":"5527630","amountA":"6700000000","other":"1510821971811852351","assetB":"12982485703607823902","amountB":"100000000","feeA":"250000000","balancing":0,"feeAtxid":"1234468909119892020","triggerhash":"34ea5aaeeeb62111a825a94c366b4ae3d12bb73f9a3413a27d1b480f6029a73c"} + if ( array != 0 && is_cJSON_Array(array) != 0 && (n= cJSON_GetArraySize(array)) > 0 ) + { + for (i=0; i %llu) via %llu\n",(long long)mynxt64bits,(long long)src64bits,(long long)dest64bits,(long long)jump64bits); + } else printf("illegal tabulate_trade_entry %llu: %llu %llu %llu || %llu %llu %llu\n",(long long)mynxt64bits,(long long)src64bits,(long long)srcamount,(long long)srcasset,(long long)dest64bits,(long long)destamount,(long long)destasset); + } + } + if ( hist != 0 ) + { + array = tradehistory_json(hist,array); + free(hist); + } + return(array); +} + +cJSON *get_tradehistory(char *refNXTaddr,uint32_t timestamp) +{ + char cmdstr[1024],NXTaddr[64],*jsonstr; struct destbuf receiverstr,message,newtriggerhash,triggerhash; + cJSON *json,*array,*txobj,*msgobj,*attachment,*retjson = 0,*histarray = 0; int32_t i,j,n,m,duplicates = 0; uint64_t senderbits; + if ( timestamp == 0 ) + timestamp = 38785003; + sprintf(cmdstr,"requestType=getBlockchainTransactions&account=%s×tamp=%u&withMessage=true",refNXTaddr,timestamp); + if ( (jsonstr= issue_NXTPOST(cmdstr)) != 0 ) + { + if ( (json= cJSON_Parse(jsonstr)) != 0 ) + { + if ( (array= cJSON_GetObjectItem(json,"transactions")) != 0 && is_cJSON_Array(array) != 0 && (n= cJSON_GetArraySize(array)) > 0 ) + { + for (i=0; i ",message); + unstringify(message.buf); + if ( (msgobj= cJSON_Parse(message.buf)) != 0 ) + { + //printf("(%s)\n",message); + if ( histarray == 0 ) + histarray = cJSON_CreateArray(), j = m = 0; + else + { + copy_cJSON(&newtriggerhash,cJSON_GetObjectItem(msgobj,"triggerhash")); + m = cJSON_GetArraySize(histarray); + for (j=0; jquoteid)) != 0 ) + { + iQ->s.closed = 1; + delete_iQ(pend->quoteid); + } + else printf("free_pending: cant find pending tx for %llu\n",(long long)pend->quoteid); + if ( pend->triggertx != 0 ) + free(pend->triggertx); + if ( pend->txbytes != 0 ) + free(pend->txbytes); + if ( pend->tradesjson != 0 ) + free_json(pend->tradesjson); + free(pend); +} + +/*void oldInstantDEX_history(int32_t action,struct pending_trade *pend,char *str) +{ + uint8_t txbuf[32768]; char *tmpstr; uint16_t n; long len = 0; + // struct pending_trade { struct queueitem DL; struct prices777_order order; uint64_t triggertxid,txid,quoteid,orderid; struct prices777 *prices; char *triggertx,*txbytes; cJSON *tradesjson; double price,volume; uint32_t timestamp; int32_t dir,type; }; + memcpy(&txbuf[len],&action,sizeof(action)), len += sizeof(action); + if ( action == 0 ) + { + memcpy(&txbuf[len],pend,sizeof(*pend)), len += sizeof(*pend); + if ( pend->triggertx != 0 ) + { + n = (uint16_t)strlen(pend->triggertx) + 1; + memcpy(&txbuf[len],&n,sizeof(n)), len += sizeof(n); + memcpy(&txbuf[len],pend->triggertx,n), len += n; + } + if ( pend->txbytes != 0 ) + { + n = (uint16_t)strlen(pend->txbytes) + 1; + memcpy(&txbuf[len],&n,sizeof(n)), len += sizeof(n); + memcpy(&txbuf[len],pend->txbytes,n), len += n; + } + if ( pend->tradesjson != 0 ) + { + tmpstr = jprint(pend->tradesjson,0); + n = (uint16_t)strlen(tmpstr) + 1; + memcpy(&txbuf[len],&n,sizeof(n)), len += sizeof(n); + memcpy(&txbuf[len],tmpstr,n), len += n; + free(tmpstr); + } + } + else + { + memcpy(&txbuf[len],&pend->orderid,sizeof(pend->orderid)), len += sizeof(pend->orderid); + memcpy(&txbuf[len],&pend->quoteid,sizeof(pend->quoteid)), len += sizeof(pend->quoteid); + } + if ( str != 0 ) + { + n = (uint16_t)strlen(str) + 1; + memcpy(&txbuf[len],&n,sizeof(n)), len += sizeof(n); + memcpy(&txbuf[len],str,n), len += n; + } + else + { + n = 0; + memcpy(&txbuf[len],&n,sizeof(n)), len += sizeof(n); + } + txind777_create(INSTANTDEX.history,INSTANTDEX.numhist,pend->timestamp,txbuf,len); + txinds777_flush(INSTANTDEX.history,INSTANTDEX.numhist,pend->timestamp); + INSTANTDEX.numhist++; +}*/ + +char *InstantDEX_loadhistory(struct pending_trade *pend,int32_t *actionp,uint8_t *txbuf,int32_t size) +{ + char *tmpstr,*str = 0; uint16_t n; long len = 0; + memcpy(actionp,&txbuf[len],sizeof(*actionp)), len += sizeof(*actionp); + if ( *actionp == 0 ) + { + memcpy(pend,&txbuf[len],sizeof(*pend)), len += sizeof(*pend); + //printf("pendsize.%ld trigger.%p tx.%p json.%p\n",(long)sizeof(*pend),pend->triggertx,pend->txbytes,pend->tradesjson); + if ( pend->triggertx != 0 ) + { + memcpy(&n,&txbuf[len],sizeof(n)), len += sizeof(n); + pend->triggertx = calloc(1,n); + memcpy(pend->triggertx,&txbuf[len],n), len += n; + } + if ( pend->txbytes != 0 ) + { + memcpy(&n,&txbuf[len],sizeof(n)), len += sizeof(n); + pend->txbytes = calloc(1,n); + memcpy(pend->txbytes,&txbuf[len],n), len += n; + } + if ( pend->tradesjson != 0 ) + { + memcpy(&n,&txbuf[len],sizeof(n)), len += sizeof(n); + tmpstr = calloc(1,n); + memcpy(tmpstr,&txbuf[len],n), len += n; + if ( (pend->tradesjson= cJSON_Parse(tmpstr)) == 0 ) + printf("cant parse.(%s)\n",tmpstr); + free(tmpstr); + } + } + else + { + memcpy(&pend->orderid,&txbuf[len],sizeof(pend->orderid)), len += sizeof(pend->orderid); + memcpy(&pend->quoteid,&txbuf[len],sizeof(pend->quoteid)), len += sizeof(pend->quoteid); + } + memcpy(&n,&txbuf[len],sizeof(n)), len += sizeof(n); + if ( n != 0 ) + { + str = calloc(1,n); + memcpy(str,&txbuf[len],n), len += n; + } + if ( len != size ) + printf("loadhistory warning: len.%ld != size.%d\n",len,size); + return(str); +} + +struct pending_trade *InstantDEX_historyi(int32_t *actionp,char **strp,int32_t i,uint8_t *txbuf,int32_t maxsize) +{ + struct pending_trade *pend = 0; +/* void *ptr; int32_t size; + *strp = 0; + txinds777_seek(INSTANTDEX.history,i); + if ( (ptr= txinds777_read(&size,txbuf,INSTANTDEX.history)) == 0 || size <= 0 || size > maxsize ) + { + printf("InstantDEX_inithistory: error reading entry.%d | ptr.%p size.%d\n",i,ptr,maxsize); + return(0); + } + pend = calloc(1,sizeof(*pend)); + *strp = InstantDEX_loadhistory(pend,actionp,ptr,size);*/ + return(pend); +} + +int32_t oldInstantDEX_inithistory(int32_t firsti,int32_t endi) +{ + int32_t i,action; uint8_t txbuf[32768]; char *str; struct pending_trade *pend; + printf("InstantDEX_inithistory firsti.%d endi.%d\n",firsti,endi); + for (i=firsti; itype,pend->type!=0?pend->type:'0',action,(long long)pend->orderid,(long long)pend->quoteid,str!=0?str:""); + if ( str != 0 ) + free(str); + free_pending(pend); + } + } + return(i); +} + +cJSON *InstantDEX_tradeitem(struct pending_trade *pend) +{ + // struct pending_trade { struct queueitem DL; struct prices777_order order; uint64_t triggertxid,txid,quoteid,orderid; struct prices777 *prices; char *triggertx,*txbytes; cJSON *tradesjson; double price,volume; uint32_t timestamp; int32_t dir,type; }; + struct InstantDEX_quote *iQ; char str[64]; cJSON *json = cJSON_CreateObject(); + str[0] = (pend->type == 0) ? '0' : pend->type; + str[1] = 0; + jaddstr(json,"type",str); + jaddnum(json,"timestamp",pend->timestamp); + jadd64bits(json,"orderid",pend->orderid), jadd64bits(json,"quoteid",pend->quoteid); + if ( (iQ= find_iQ(pend->quoteid)) != 0 ) + { + if ( iQ->s.baseid != 0 && iQ->s.relid != 0 ) + jadd64bits(json,"baseid",iQ->s.baseid), jadd64bits(json,"relid",iQ->s.relid); + if ( iQ->s.baseamount != 0 && iQ->s.relamount != 0 ) + jaddnum(json,"baseqty",iQ->s.baseamount), jaddnum(json,"relqty",iQ->s.relamount); + } else printf("tradeitem cant find quoteid.%llu\n",(long long)pend->quoteid); + if ( pend->dir != 0 ) + jaddnum(json,"dir",pend->dir); + if ( pend->price > SMALLVAL && pend->volume > SMALLVAL ) + jaddnum(json,"price",pend->price), jaddnum(json,"volume",pend->volume); + if ( pend->triggertxid != 0 ) + jadd64bits(json,"triggertxid",pend->triggertxid); + if ( pend->txid != 0 ) + jadd64bits(json,"txid",pend->txid); + if ( pend->triggertx != 0 ) + jaddstr(json,"triggertx",pend->triggertx); + if ( pend->txbytes != 0 ) + jaddstr(json,"txbytes",pend->txbytes); + return(json); +} + +char *InstantDEX_withdraw(cJSON *argjson) +{ + char *exchangestr,*str; struct exchange_info *exchange; int32_t exchangeid; + if ( (exchangestr= jstr(argjson,"exchange")) != 0 && (exchange= find_exchange(&exchangeid,exchangestr)) != 0 ) + { + if ( exchange->issue.withdraw != 0 ) + { + if ( (str= (*exchange->issue.withdraw)(&exchange->cHandle,exchange,argjson)) == 0 ) + str = clonestr("{\"result\":\"nothing returned from exchange\"}"); + return(str); + } + else return(clonestr("{\"error\":\"no withdraw function\"}")); + } + return(clonestr("{\"error\":\"withdraw is not yet\"}")); +} + +char *InstantDEX_tradehistory(cJSON *argjson,int32_t firsti,int32_t endi) +{ + /* + cJSON *json,*array,*item,*tmp; int32_t exchangeid,i,action; uint8_t txbuf[32768]; + char *str,*exchangestr; struct pending_trade *pend; struct exchange_info *exchange; + if ( (exchangestr= jstr(argjson,"exchange")) != 0 && (exchange= find_exchange(&exchangeid,exchangestr)) != 0 ) + { + if ( exchange->issue.tradehistory != 0 ) + { + if ( (str= (*exchange->issue.tradehistory)(&exchange->cHandle,exchange,argjson)) == 0 ) + str = clonestr("{\"result\":\"nothing returned from exchange\"}"); + return(str); + } + else return(clonestr("{\"error\":\"no tradehistory function\"}")); + } + json = cJSON_CreateObject(); + array = cJSON_CreateArray(); + if ( endi == 0 ) + endi = INSTANTDEX.numhist-1; + if ( endi < firsti ) + endi = firsti; + for (i=firsti; i<=endi; i++) + { + if ( (pend= InstantDEX_historyi(&action,&str,i,txbuf,sizeof(txbuf))) != 0 ) + { + item = cJSON_CreateObject(); + jaddnum(item,"i",i); + jaddnum(item,"action",action); + jadd(item,"trade",InstantDEX_tradeitem(pend)); + if ( pend->tradesjson != 0 ) + jadd(item,"trades",cJSON_Duplicate(pend->tradesjson,1)); + if ( str != 0 ) + { + if ( (tmp= cJSON_Parse(str)) != 0 ) + jadd(item,"str",tmp); + free(str); + } + free_pending(pend); + jaddi(array,item); + } + } + jadd(json,"tradehistory",array); + jaddnum(json,"numentries",INSTANTDEX.numhist); + return(jprint(json,1));*/ + return(0); +} + +int32_t substr128(char *dest,char *src) +{ + char zeroes[129],*match; int32_t i; + for (i=0; i<128; i++) + zeroes[i] = '0'; + zeroes[i] = 0; + strcpy(dest,src); + if ( (match= strstr(dest,zeroes)) != 0 ) + { + strcpy(match,"Z"); + for (i=0; match[128+i]!=0; i++) + match[i+1] = match[128+i]; + match[i+1] = 0; + } + //printf("substr128.(%s) -> (%s)\n",src,dest); + return(0); +} + +uint64_t gen_NXTtx(struct NXTtx *tx,uint64_t dest64bits,uint64_t assetidbits,uint64_t qty,uint64_t orderid,uint64_t quoteid,int32_t deadline,char *reftx,char *phaselink,uint32_t finishheight,char *phasesecret) +{ + char secret[8192],cmd[16384],destNXTaddr[64],assetidstr[64],hexstr[64],*retstr; uint8_t msgbuf[17]; cJSON *json; int32_t len; uint64_t phasecost = 0; + if ( deadline > 1000 ) + deadline = 1000; + expand_nxt64bits(destNXTaddr,dest64bits); + memset(tx,0,sizeof(*tx)); + if ( ((phasesecret != 0 && phasesecret[0] != 0) || (phaselink!= 0 && phaselink[0] != 0)) && finishheight <= _get_NXTheight(0) ) + { + printf("finish height.%u must be in the future.%u\n",finishheight,_get_NXTheight(0)); + return(0); + } + if ( phaselink != 0 || phasesecret != 0 ) + phasecost = MIN_NQTFEE; + cmd[0] = 0; + if ( assetidbits == NXT_ASSETID ) + sprintf(cmd,"requestType=sendMoney&amountNQT=%lld",(long long)qty); + else + { + expand_nxt64bits(assetidstr,assetidbits); + if ( is_mscoin(assetidstr) == 0 ) + sprintf(cmd,"requestType=transferAsset&asset=%s&quantityQNT=%lld",assetidstr,(long long)qty); + else sprintf(cmd,"requestType=transferCurrency¤cy=%s&units=%lld",assetidstr,(long long)qty); + } + if ( quoteid != 0 ) + { + len = 0; + printf("serialize buffer\n"); + //len = txind777_txbuf(msgbuf,len,orderid,sizeof(orderid)); + //len = txind777_txbuf(msgbuf,len,quoteid,sizeof(quoteid)); + init_hexbytes_noT(hexstr,msgbuf,len); + sprintf(cmd+strlen(cmd),"&messageIsText=true&message=%s",hexstr); + } + if ( cmd[0] != 0 ) + { + escape_code(secret,IGUANA_NXTACCTSECRET); + sprintf(cmd+strlen(cmd),"&deadline=%u&feeNQT=%lld&secretPhrase=%s&recipient=%s&broadcast=false",deadline,(long long)MIN_NQTFEE+phasecost,secret,destNXTaddr); + if ( reftx != 0 && reftx[0] != 0 ) + sprintf(cmd+strlen(cmd),"&referencedTransactionFullHash=%s",reftx); + if ( phaselink != 0 && phaselink[0] != 0 ) + sprintf(cmd+strlen(cmd),"&phased=true&phasingFinishHeight=%u&phasingVotingModel=4&phasingQuorum=1&phasingLinkedFullHash=%s",finishheight,phaselink); + else if ( phasesecret != 0 && phasesecret[0] != 0 ) + sprintf(cmd+strlen(cmd),"&phased=true&phasingFinishHeight=%u&phasingVotingModel=5&phasingHashedSecretAlgorithm=62&phasingQuorum=1&phasingHashedSecret=%s",finishheight,phasesecret); +//printf("generated cmd.(%s)\n",cmd); + if ( (retstr= issue_NXTPOST(cmd)) != 0 ) + { +//printf("(%s)\n",retstr); + if ( (json= cJSON_Parse(retstr)) != 0 ) + { + if ( extract_cJSON_str(tx->txbytes,MAX_JSON_FIELD,json,"transactionBytes") > 0 && + extract_cJSON_str(tx->utxbytes,MAX_JSON_FIELD,json,"unsignedTransactionBytes") > 0 && + extract_cJSON_str(tx->fullhash,MAX_JSON_FIELD,json,"fullHash") > 0 && + extract_cJSON_str(tx->sighash,MAX_JSON_FIELD,json,"signatureHash") > 0 ) + { + tx->txid = j64bits(json,"transaction"); + substr128(tx->utxbytes2,tx->utxbytes); + } + free_json(json); + } + free(retstr); + } + } + return(tx->txid); +} + +struct NXTtx *fee_triggerhash(char *triggerhash,uint64_t orderid,uint64_t quoteid,int32_t deadline) +{ + static struct NXTtx fee; + if ( fee.fullhash[0] == 0 ) + gen_NXTtx(&fee,calc_nxt64bits(INSTANTDEX_ACCT),NXT_ASSETID,INSTANTDEX_FEE,orderid,quoteid,deadline,0,0,0,0); + strcpy(triggerhash,fee.fullhash); + return(&fee); +} + +uint64_t InstantDEX_swapstr(char *sendphased,char *phasesecret,uint64_t *txidp,char *triggertx,char *txbytes,char *swapstr,uint64_t orderid,struct prices777_order *order,char *triggerhash,char *phaselink,int32_t finishheight) +{ + struct NXTtx fee,sendtx; uint64_t otherqty = 0,otherassetbits = 0,assetidbits = 0,qty = 0; int32_t deadline = INSTANTDEX_TRIGGERDEADLINE; + if ( finishheight != 0 ) + { + if ( finishheight > FINISH_HEIGHT ) + deadline *= (finishheight / FINISH_HEIGHT); + finishheight += _get_NXTheight(0); + } + swapstr[0] = triggertx[0] = txbytes[0] = 0; + *txidp = 0; + gen_NXTtx(&fee,calc_nxt64bits(INSTANTDEX_ACCT),NXT_ASSETID,INSTANTDEX_FEE,orderid,order->s.quoteid,deadline,triggerhash,0,0,0); + strcpy(triggertx,fee.txbytes); + if ( order->s.baseamount < 0 ) + assetidbits = order->s.baseid, qty = -order->s.baseamount, otherassetbits = order->s.relid, otherqty = order->s.relamount; + else if ( order->s.relamount < 0 ) + assetidbits = order->s.relid, qty = -order->s.relamount, otherassetbits = order->s.baseid, otherqty = order->s.baseamount; + printf("genNXTtx.(%llu/%llu) finish at %u vs %u lag %u deadline %d assetidbits.%llu sendphased.(%s)\n",(long long)orderid,(long long)order->s.quoteid,finishheight,_get_NXTheight(0),finishheight-_get_NXTheight(0),deadline,(long long)assetidbits,sendphased!=0?sendphased:""); + if ( sendphased != 0 && assetidbits != 0 && qty != 0 ) + { + if ( triggerhash == 0 || triggerhash[0] == 0 ) + triggerhash = fee.fullhash; + gen_NXTtx(&sendtx,order->s.offerNXT,assetidbits,qty,orderid,order->s.quoteid,deadline,triggerhash,phaselink,finishheight,phasesecret); + *txidp = sendtx.txid; + strcpy(txbytes,sendtx.txbytes); + sprintf(swapstr,",\"F\":\"%u\",\"T\":\"%s\",\"FH\":\"%s\",\"U\":\"%s\",\"S\":\"%s\",\"a\":\"%llu\",\"q\":\"%llu\"}",finishheight,fee.fullhash,sendtx.fullhash,sendtx.utxbytes2,sendtx.sighash,(long long)otherassetbits,(long long)otherqty); + } + else sprintf(swapstr,",\"F\":\"%u\",\"T\":\"%s\",\"a\":\"%llu\",\"q\":\"%llu\"}",finishheight,fee.fullhash,(long long)otherassetbits,(long long)otherqty); + return(fee.txid); +} + +uint64_t prices777_swapbuf(char *sendphased,char *phasesecret,uint64_t *txidp,char *triggertx,char *txbytes,char *swapbuf,char *exchangestr,char *base,char *rel,struct prices777_order *order,uint64_t orderid,int32_t finishoffset,char *triggerhash) +{ + char swapstr[4096],*str; uint64_t txid = 0; + *txidp = 0; + if ( strcmp(exchangestr,"wallet") == 0 ) + str = "swap"; + else + { + str = order->wt > 0. ? "buy" : (order->wt < 0. ? "sell" : "swap"); + //printf("not wallet!\n"); getchar(); + } + if ( finishoffset == 0 ) + finishoffset = FINISH_HEIGHT; + sprintf(swapbuf,"{\"orderid\":\"%llu\",\"quoteid\":\"%llu\",\"offerNXT\":\"%llu\",\"fillNXT\":\"%s\",\"plugin\":\"relay\",\"destplugin\":\"InstantDEX\",\"method\":\"busdata\",\"submethod\":\"%s\",\"exchange\":\"%s\",\"base\":\"%s\",\"rel\":\"%s\",\"baseid\":\"%llu\",\"relid\":\"%llu\",\"baseqty\":\"%lld\",\"relqty\":\"%lld\"}",(long long)orderid,(long long)order->s.quoteid,(long long)order->s.offerNXT,IGUANA_NXTADDR,str,exchangestr,base,rel,(long long)order->s.baseid,(long long)order->s.relid,(long long)order->s.baseamount,(long long)order->s.relamount); + if ( order->s.price > SMALLVAL ) + sprintf(swapbuf + strlen(swapbuf) - 1,",\"price\":%.8f,\"volume\":%.8f}",order->s.price,order->s.vol); + txid = InstantDEX_swapstr(sendphased,phasesecret,txidp,triggertx,txbytes,swapstr,orderid,order,triggerhash,0,finishoffset); + strcpy(swapbuf+strlen(swapbuf)-1,swapstr); + //printf("swapbuf.(%s)\n",swapbuf); + return(txid); +} + +char *prices777_finishswap(int32_t dotrade,int32_t type,struct pending_trade *pend,char *swapbuf,char *triggertx,char *txbytes) +{ + uint32_t nonce; char *str; + if ( triggertx[0] != 0 ) + pend->triggertx = clonestr(triggertx); + if ( txbytes[0] != 0 ) + pend->txbytes = clonestr(txbytes); + pend->order.s.swap = 1; + pend->tradesjson = cJSON_Parse(swapbuf); + pend->type = type; + printf("quoteid.%llu and pending.%d\n",(long long)pend->order.s.quoteid,pend->order.s.pending); + if ( dotrade != 0 ) + { + if ( (str= busdata_sync(&nonce,swapbuf,"allnodes",0)) != 0 ) + free(str); + pend->queueflag = 1; + queue_enqueue("PendingQ",&Pending_offersQ,&pend->DL,0); + } + //InstantDEX_history(0,pend,swapbuf); + return(clonestr(swapbuf)); +} + +/*int32_t subatomic_pubkeyhash(char *pubkeystr,char *pkhash,struct coin777 *coin,uint64_t quoteid) +{ + printf("subatomic pubkeyhash not yet\n"); + char tmpswapaddr[128],swapacct[128]; uint8_t tmpbuf[128]; struct destbuf pubkey; + sprintf(swapacct,"atomic.%llu",(long long)quoteid); + pkhash[0] = pubkeystr[0] = 0; + if ( get_acct_coinaddr(tmpswapaddr,coin->name,coin->serverport,coin->userpass,swapacct) != 0 ) + { + get_pubkey(&pubkey,coin->name,coin->serverport,coin->userpass,tmpswapaddr); + strcpy(pubkeystr,pubkey.buf); + calc_OP_HASH160(pkhash,tmpbuf,pubkey.buf); + return(0); + } + return(-1); +}*/ + +int32_t complete_swap(struct InstantDEX_quote *iQ,uint64_t orderid,uint64_t quoteid,int32_t err) +{ + /*int32_t errcode=-1,errcode2=-2; char *txstr,*txstr2; int32_t iter; struct pending_trade *pend; + for (iter=0; iter<2; iter++) + { + while ( (pend= queue_dequeue(&Pending_offersQ.pingpong[iter],0)) != 0 ) + { + if ( pend->quoteid == quoteid ) + { + if ( err == 0 && issue_broadcastTransaction(&errcode2,&txstr2,pend->txbytes,IGUANA_NXTACCTSECRET) == pend->txid && errcode2 == 0 ) + { + if ( err == 0 && (issue_broadcastTransaction(&errcode,&txstr,pend->triggertx,IGUANA_NXTACCTSECRET) != pend->triggertxid || errcode != 0) ) + err = -13; + } + if ( err == 0 && errcode == 0 && errcode2 == 0 ) + { + iQ->s.matched = 1; + //InstantDEX_history(1,pend,0); + } //else InstantDEX_history(-1,pend,0); + printf("errs.(%d %d %d) COMPLETED %llu/%llu %d %f %f with txids %llu %llu\n",err,errcode,errcode2,(long long)pend->orderid,(long long)pend->quoteid,pend->dir,pend->price,pend->volume,(long long)pend->triggertxid,(long long)pend->txid); + pend->queueflag = 1; + pend->finishtime = (uint32_t)time(NULL); + return(1); + } + queue_enqueue("requeue",&Pending_offersQ.pingpong[iter ^ 1],&pend->DL,0); + } + }*/ + printf("complete swap is notyet\n"); + return(-1); +} + +char *prices777_tradewallet(struct pending_trade *pend) +{ + printf("tradewallet is not yet\n"); + return(0); + /* + struct coin777 *recvcoin,*sendcoin; cJSON *walletitem,*item; + char fieldA[64],fieldB[64],triggertx[4096],txbytes[4096],fieldpkhash[64],refredeemscript[2048],scriptPubKey[128],p2shaddr[64]; + char swapbuf[8192],buf[1024],*rpubA=0,*rpubB=0,*rpkhash=0,*spubA=0,*spubB=0,*spkhash=0,*recvstr=0; + char *sendstr=0,*refundtx,*redeemscript,*str; int32_t finishin,deadline; uint32_t nonce; + uint64_t sendamount,recvamount,sendasset,recvasset; struct destbuf base,rel; + if ( pend->item != 0 && (item= jitem(pend->item,0)) != 0 && (walletitem= jobj(item,"wallet")) != 0 ) + { + finishin = (pend->extra[0] == 0) ? 200 : myatoi(pend->extra,10000); + if ( finishin < FINISH_HEIGHT ) + finishin = FINISH_HEIGHT; + copy_cJSON(&base,jobj(item,"base")); + copy_cJSON(&rel,jobj(item,"rel")); + if ( (recvamount= j64bits(item,"recvbase")) != 0 && (sendamount= j64bits(item,"sendrel")) != 0 ) + recvstr = base.buf, sendstr = rel.buf, recvasset = pend->order.s.baseid, sendasset = pend->order.s.relid; + else if ( (recvamount= j64bits(item,"recvrel")) != 0 && (sendamount= j64bits(item,"sendbase")) != 0 ) + recvstr = rel.buf, sendstr = base.buf, recvasset = pend->order.s.relid, sendasset = pend->order.s.baseid; + else + { + return(clonestr("{\"error\":\"need recvbase/sendrel or recvrel/sendbase\"}\n")); + } + recvcoin = coin777_find(recvstr,1), sendcoin = coin777_find(sendstr,1); + // placeask -> recvbase/sendrel, placebid -> sendbase/recvrel, it is relative to the one that placed quote + if ( strcmp(recvstr,"NXT") != 0 ) // placeask COIN/NXT or placebid NXT/COIN + { + if ( recvamount < recvcoin->mgw.txfee ) + { + printf("recvamount %.8f < txfee %.8f\n",dstr(recvamount),dstr(recvcoin->mgw.txfee)); + return(clonestr("{\"error\":\"amount too small\"}\n")); + } + sprintf(fieldA,"%spubA",recvstr), rpubA = jstr(walletitem,fieldA); + sprintf(fieldB,"%spubB",recvstr), rpubB = jstr(walletitem,fieldB); + sprintf(fieldpkhash,"%spkhash",recvstr), rpkhash = jstr(walletitem,fieldpkhash); + if ( rpubA[0] != 0 && rpubB != 0 && rpkhash != 0 ) // Alice for recvcoin -> Bob, Bob sends NXT -> Alice + { + if ( recvcoin->funding.signedtransaction[0] == 0 && (refundtx= subatomic_fundingtx(refredeemscript,&recvcoin->funding,recvcoin,rpubA,rpubB,rpkhash,recvamount,finishin)) != 0 ) + { + deadline = 3600; + gen_NXTtx(&recvcoin->trigger,calc_nxt64bits(INSTANTDEX_ACCT),NXT_ASSETID,INSTANTDEX_FEE,pend->orderid,pend->order.s.quoteid,deadline,0,0,0,0); + sprintf(swapbuf,"{\"orderid\":\"%llu\",\"quoteid\":\"%llu\",\"offerNXT\":\"%llu\",\"fillNXT\":\"%s\",\"plugin\":\"relay\",\"destplugin\":\"InstantDEX\",\"method\":\"busdata\",\"submethod\":\"swap\",\"exchange\":\"wallet\",\"recvamount\":\"%lld\",\"rtx\":\"%s\",\"rs\":\"%s\",\"recvcoin\":\"%s\",\"%s\":\"%s\",\"%s\":\"%s\",\"%s\":\"%s\",\"trigger\":\"%s\",\"sendasset\":\"%llu\",\"sendqty\":\"%llu\",\"base\":\"%s\",\"rel\":\"%s\"}",(long long)pend->orderid,(long long)pend->order.s.quoteid,(long long)pend->order.s.offerNXT,SUPERNET.NXTADDR,(long long)recvamount,refundtx,refredeemscript,recvstr,fieldA,rpubA,fieldB,rpubB,fieldpkhash,rpkhash,recvcoin->trigger.fullhash,(long long)sendasset,(long long)sendamount,pend->prices->base,pend->prices->rel); + recvcoin->refundtx = refundtx; + pend->order.s.swap = 1; + if ( pend->dotrade != 0 && (str= busdata_sync(&nonce,swapbuf,"allnodes",0)) != 0 ) + { + pend->queueflag = 1; + queue_enqueue("PendingQ",&Pending_offersQ.pingpong[0],&pend->DL,0); + } + return(clonestr(swapbuf)); + } else return(clonestr("{\"error\":\"cant create refundtx, maybe already pending\"}\n")); + } + else + { + sprintf(buf,"{\"error\":\"sendNXT recvstr.(%s) rpubA.(%s) without %s rpubB.%p or %s rpkhash.%p\"}\n",recvstr,rpubA,fieldB,rpubB,fieldpkhash,rpkhash); + return(clonestr(buf)); + } + } + else if ( strcmp(sendstr,"NXT") != 0 ) + { + if ( sendamount < sendcoin->mgw.txfee ) + { + printf("sendamount %.8f < txfee %.8f\n",dstr(sendamount),dstr(sendcoin->mgw.txfee)); + return(clonestr("{\"error\":\"amount too small\"}\n")); + } + sprintf(fieldA,"%spubA",sendstr), spubA = jstr(walletitem,fieldA); + sprintf(fieldB,"%spubB",sendstr), spubB = jstr(walletitem,fieldB); + sprintf(fieldpkhash,"%spkhash",sendstr), spkhash = jstr(walletitem,fieldpkhash); + if ( spubA != 0 && spubB != 0 && spkhash[0] != 0 ) // Bob <- sendcoin from Alice, send NXT -> Alice + { + if ( (redeemscript= create_atomictx_scripts(sendcoin->p2shtype,scriptPubKey,p2shaddr,spubA,spubB,spkhash)) != 0 ) + { + pend->triggertxid = prices777_swapbuf("yes",spkhash,&pend->txid,triggertx,txbytes,swapbuf,"wallet",pend->prices->base,pend->prices->rel,&pend->order,pend->orderid,finishin,0); + sprintf(swapbuf+strlen(swapbuf)-1,",\"sendcoin\":\"%s\",\"sendamount\":\"%llu\",\"%s\":\"%s\",\"%s\":\"%s\",\"%s\":\"%s\",\"recvasset\":\"%llu\",\"recvqty\":\"%llu\"}",sendstr,(long long)sendamount,fieldA,spubA,fieldB,spubB,fieldpkhash,spkhash,(long long)recvasset,(long long)recvamount); + free(redeemscript); + pend->order.s.swap = 1; + if ( pend->dotrade != 0 && (str= busdata_sync(&nonce,swapbuf,"allnodes",0)) != 0 ) + { + free(str); + pend->queueflag = 1; + queue_enqueue("PendingQ",&Pending_offersQ.pingpong[0],&pend->DL,0); + } + return(clonestr(swapbuf)); + } + } + else + { + sprintf(buf,"{\"error\":\"recvNXT sendstr.(%s) spubA.(%s) without %s spubB.(%s) or %s spkhash.(%s)\"}\n",sendstr,spubA,fieldB,spubB,fieldpkhash,spkhash); + return(clonestr(buf)); + } + } + else if ( rpubA[0] != 0 && rpubB != 0 && rpkhash != 0 && spubA != 0 && spubB != 0 && spkhash[0] != 0 && (strcmp(sendstr,"BTC") == 0 || strcmp(recvstr,"BTC") == 0) ) + { + if ( recvcoin->funding.signedtransaction[0] == 0 && (refundtx= subatomic_fundingtx(refredeemscript,&recvcoin->funding,recvcoin,rpubA,rpubB,rpkhash,recvamount,finishin)) != 0 ) + { + if ( (redeemscript= create_atomictx_scripts(sendcoin->p2shtype,scriptPubKey,p2shaddr,spubA,spubB,spkhash)) != 0 ) + { + pend->triggertxid = prices777_swapbuf(0,0,&pend->txid,triggertx,txbytes,swapbuf,"wallet",pend->prices->base,pend->prices->rel,&pend->order,pend->orderid,finishin,0); + sprintf(swapbuf,"{\"orderid\":\"%llu\",\"quoteid\":\"%llu\",\"offerNXT\":\"%llu\",\"fillNXT\":\"%s\",\"plugin\":\"relay\",\"destplugin\":\"InstantDEX\",\"method\":\"busdata\",\"submethod\":\"swap\",\"exchange\":\"wallet\",\"sendcoin\":\"%s\",\"recvcoin\":\"%s\",\"sendamount\":\"%lld\",\"recvamount\":\"%lld\",\"base\":\"%s\",\"rel\":\"%s\"}",(long long)pend->orderid,(long long)pend->order.s.quoteid,(long long)pend->order.s.offerNXT,SUPERNET.NXTADDR,sendstr,recvstr,(long long)sendamount,(long long)recvamount,pend->prices->base,pend->prices->rel); + sprintf(swapbuf+strlen(swapbuf)-1,",\"rtx\":\"%s\",\"rs\":\"%s\",\"rpubA\":\"%s\",\"rpubB\":\"%s\",\"rpkhash\":\"%s\",\"pubA\":\"%s\",\"pubB\":\"%s\",\"pkhash\":\"%s\"}",refundtx,refredeemscript,rpubA,rpubB,rpkhash,spubA,spubB,spkhash); + free(redeemscript); + free(refundtx); + pend->order.s.swap = 1; + if ( pend->dotrade != 0 && (str= busdata_sync(&nonce,swapbuf,"allnodes",0)) != 0 ) + { + free(str); + pend->queueflag = 1; + queue_enqueue("PendingQ",&Pending_offersQ.pingpong[0],&pend->DL,0); + } + return(clonestr(swapbuf)); + } + free(refundtx); + } + else return(clonestr("{\"error\":\"cant create refundtx, maybe already pending\"}\n")); + } + else return(clonestr("{\"error\":\"one of wallets must be NXT or BTC\"}\n")); + printf("wallet swap finishin.%d trigger.%llu swapbuf.(%s)\n",finishin,(long long)pend->triggertxid,swapbuf); + return(prices777_finishswap(pend->dotrade,'A',pend,swapbuf,triggertx,txbytes)); + } + else return(clonestr("{\"error\":\"need to have trades[] json item\"}\n"));*/ +} + +struct pending_trade *prices777_createpending(int32_t *curlingp,void *bot,void **cHandlep,int32_t dotrade,cJSON *item,char *activenxt,char *secret,struct prices777 *prices,int32_t dir,double price,double volume,struct InstantDEX_quote *iQ,struct prices777_order *order,uint64_t orderid,char *extra) +{ + struct InstantDEX_quote _iQ; struct exchange_info *exchange; struct pending_trade *pend; + char swapbuf[8192],triggertx[4096],txbytes[4096]; + if ( (exchange= find_exchange(0,prices->exchange)) == 0 && exchange->issue.trade != 0 ) + { + printf("prices777_trade: need to have supported exchange\n"); + return(0); + } + if ( cHandlep == 0 ) + cHandlep = &exchange->cHandle; + if ( iQ == 0 && order == 0 ) + { + printf("prices777_trade: need to have either iQ or order\n"); + return(0); + } + else if ( iQ == 0 && (iQ= find_iQ(order->s.quoteid)) == 0 ) + { + iQ = &_iQ; + memset(&_iQ,0,sizeof(_iQ)); + iQ->s = order->s; + iQ->exchangeid = prices->exchangeid; + if ( iQ->s.timestamp == 0 ) + iQ->s.timestamp = (uint32_t)time(NULL); + iQ = create_iQ(iQ,0); + } else iQ = create_iQ(iQ,0); + pend = calloc(1,sizeof(*pend)); + pend->bot = bot; + safecopy((char *)pend->nxtsecret,secret,sizeof(pend->nxtsecret)); + pend->size = (int32_t)sizeof(*pend); + pend->my64bits = calc_nxt64bits(activenxt); + triggertx[0] = txbytes[0] = swapbuf[0] = 0; + pend->prices = prices, pend->dir = dir, pend->price = price, pend->volume = volume, pend->orderid = orderid; + iQ->s.pending = 1; + pend->curlingp = curlingp; + pend->quoteid = iQ->s.quoteid; + if ( order != 0 ) + pend->order = *order; + else pend->order.s = iQ->s; + pend->timestamp = (uint32_t)time(NULL); + pend->expiration = pend->timestamp + 60; + pend->cHandlep = cHandlep; + pend->dotrade = dotrade; + pend->item = item; + pend->exchange = exchange; + safecopy(pend->extra,extra,sizeof(pend->extra)); + return(pend); +} + +char *prices777_issuepending(struct pending_trade *pend) +{ + char swapbuf[8192],triggertx[4096],txbytes[4096],*retstr; + struct prices777 *prices; struct exchange_info *exchange; + if ( (prices= pend->prices) == 0 || (exchange= pend->exchange) == 0 ) + retstr = clonestr("{\"error\":\"no prices ptr\"}"); + else if ( strcmp(prices->exchange,"wallet") == 0 ) + retstr = prices777_tradewallet(pend); + else if ( strcmp(prices->exchange,INSTANTDEX_NAME) == 0 ) + { + pend->expiration = pend->timestamp + INSTANTDEX_TRIGGERDEADLINE*60; + pend->triggertxid = prices777_swapbuf("yes",0,&pend->txid,triggertx,txbytes,swapbuf,prices->exchange,prices->base,prices->rel,&pend->order,pend->orderid,myatoi(pend->extra,10000),0); + retstr = prices777_finishswap(pend->dotrade,'T',pend,swapbuf,triggertx,txbytes); + } + else if ( strcmp(prices->exchange,"nxtae") == 0 ) + { + pend->type = 'N'; + retstr = fill_nxtae(pend->dotrade,&pend->txid,pend->my64bits,(char *)pend->nxtsecret,pend->dir,pend->price,pend->volume,prices->baseid,prices->relid); + if ( pend->dotrade != 0 ) + { + pend->queueflag = 1; + queue_enqueue("PendingQ",&Pending_offersQ,&pend->DL,0); + } + } + else + { + if ( exchange->issue.trade != 0 ) + { + printf(" issue dir.%d %s/%s price %f vol %f -> %s\n",pend->dir,prices->base,prices->rel,pend->price,pend->volume,prices->exchange); + retstr = pend->extra; + if ( pend->curlingp != 0 ) + *pend->curlingp = 1; + if ( (pend->txid= (*exchange->issue.trade)(pend->cHandlep,pend->dotrade,&retstr,exchange,prices->base,prices->rel,pend->dir,pend->price,pend->volume)) != 0 ) + { + pend->queueflag = 1; + pend->finishtime = (uint32_t)time(NULL); + } + else printf("no txid from trade\n"); + if ( pend->curlingp != 0 ) + *pend->curlingp = 0; + if ( retstr != 0 ) + { + if ( pend->dotrade != 0 ) + { + pend->queueflag = 1; + queue_enqueue("PendingQ",&Pending_offersQ,&pend->DL,0); + } + printf("returning.%p (%s)\n",retstr,retstr); + } + } else retstr = clonestr("{\"error\":\"no trade function for exchange\"}\n"); + } + if ( retstr == 0 ) + retstr = clonestr("{\"error\":\"no response\"}"); + return(retstr); +} + +char *prices777_trade(int32_t *curlingp,void *bot,struct pending_trade **pendp,void **cHandlep,int32_t dotrade,cJSON *item,char *activenxt,char *secret,struct prices777 *prices,int32_t dir,double price,double volume,struct InstantDEX_quote *iQ,struct prices777_order *order,uint64_t orderid,char *extra) +{ + struct pending_trade *pend; char *retstr; + if ( pendp != 0 ) + *pendp = 0; + if ( (pend= prices777_createpending(curlingp,bot,cHandlep,dotrade,item,activenxt,secret,prices,dir,price,volume,iQ,order,orderid,extra)) != 0 ) + { + if ( bot == 0 || dotrade == 0 ) + retstr = prices777_issuepending(pend); + else if ( pend->queueflag != 0 ) + retstr = clonestr("{\"result\":\"pending_trade created\"}"); + else retstr = clonestr("{\"error\":\"pending_trade couldnt be created\"}"); + if ( pend->queueflag == 0 ) + free_pending(pend), pend = 0; + else if ( pendp != 0 ) + *pendp = pend; + return(retstr); + } + else return(clonestr("{\"error\":\"couldnt createpending\"}")); +} + +char *issue_calculateFullHash(char *unsignedtxbytes,char *sighash) +{ + char cmd[4096]; + sprintf(cmd,"requestType=calculateFullHash&unsignedTransactionBytes=%s&signatureHash=%s",unsignedtxbytes,sighash); + return(issue_NXTPOST(cmd)); +} + +char *issue_parseTransaction(char *txbytes) +{ + char cmd[4096],*retstr = 0; + sprintf(cmd,"requestType=parseTransaction&transactionBytes=%s",txbytes); + retstr = issue_NXTPOST(cmd); + //printf("issue_parseTransaction.%s %s\n",txbytes,retstr); + if ( retstr != 0 ) + { + //printf("(%s) -> (%s)\n",cmd,retstr); + //retstr = parse_NXTresults(0,"sender","",results_processor,jsonstr,strlen(jsonstr)); + //free(jsonstr); + } else printf("error getting txbytes.%s\n",txbytes); + return(retstr); +} + +uint64_t issue_broadcastTransaction(int32_t *errcodep,char **retstrp,char *txbytes,char *NXTACCTSECRET) +{ + cJSON *json,*errjson; + uint64_t txid = 0; + char cmd[4096],secret[8192],*retstr; + escape_code(secret,NXTACCTSECRET); + sprintf(cmd,"requestType=broadcastTransaction&secretPhrase=%s&transactionBytes=%s",secret,txbytes); + retstr = issue_NXTPOST(cmd); + *errcodep = -1; + if ( retstrp != 0 ) + *retstrp = retstr; + if ( retstr != 0 ) + { + //printf("(%s) -> (%s)\n",cmd,retstr); + //printf("broadcast got.(%s)\n",retstr); + if ( (json= cJSON_Parse(retstr)) != 0 ) + { + errjson = cJSON_GetObjectItem(json,"errorCode"); + if ( errjson != 0 ) + { + //printf("ERROR broadcasting.(%s)\n",retstr); + *errcodep = (int32_t)get_cJSON_int(json,"errorCode"); + } + else + { + if ( (txid = get_satoshi_obj(json,"transaction")) != 0 ) + *errcodep = 0; + } + } + if ( retstrp == 0 ) + free(retstr); + } + return(txid); +} + +char *issue_signTransaction(char *txbytes,char *NXTACCTSECRET) +{ + char cmd[4096],secret[8192]; + escape_code(secret,NXTACCTSECRET); + sprintf(cmd,"requestType=signTransaction&secretPhrase=%s&unsignedTransactionBytes=%s",secret,txbytes); + return(issue_NXTPOST(cmd)); +} + +char *issue_approveTransaction(char *fullhash,char *revealed,char *message,char *NXTACCTSECRET) +{ + char cmd[4096],secret[8192]; + escape_code(secret,NXTACCTSECRET); + sprintf(cmd,"requestType=approveTransaction&secretPhrase=%s&transactionFullHash=%s&revealedSecret=%s&messageIsText=true&feeNQT=%lld&deadline=%d&message=%s",secret,fullhash,revealed,(long long)MIN_NQTFEE,DEFAULT_NXT_DEADLINE,message); + printf("submit approve.(%s)\n",cmd); + return(issue_NXTPOST(cmd)); +} + +uint32_t issue_getTime() +{ + char cmd[4096],*jsonstr; cJSON *json; uint32_t timestamp = 0; + //sprintf(cmd,"requestType=getAsset&asset=%s",assetidstr); + sprintf(cmd,"requestType=getTime"); + if ( (jsonstr= issue_NXTPOST(cmd)) != 0 ) + { + if ( (json= cJSON_Parse(jsonstr)) != 0 ) + timestamp = juint(json,"time"), free_json(json); + free(jsonstr); + } + return(timestamp); +} + +int32_t swap_verifyNXT(uint32_t *finishp,uint32_t *deadlinep,cJSON *origjson,char *offerNXT,char *exchangestr,uint64_t orderid,uint64_t quoteid,struct InstantDEX_quote *iQ,char *phasedtx) +{ + char UTX[32768],*triggerhash,*utx,*sighash,*jsonstr=0,*parsed,*fullhash,*cmpstr; cJSON *json=0,*txobj,*attachment; int32_t retval = -1; + uint64_t otherbits,otherqty,recvasset; struct destbuf calchash; int64_t recvqty; uint32_t i,j,timestamp,now,finishheight; + *finishp = 0; + if ( (triggerhash= jstr(origjson,"T")) == 0 ) + triggerhash = jstr(origjson,"trigger"); + otherbits = j64bits(origjson,"a"); + otherqty = j64bits(origjson,"q"); + fullhash = jstr(origjson,"FH"); + finishheight = juint(origjson,"F"); + if ( phasedtx == 0 ) + { + utx = jstr(origjson,"U"); + if ( utx != 0 && strlen(utx) > sizeof(UTX) ) + { + printf("UTX overflow\n"); + return(-1); + } + else if ( utx != 0 ) + { + for (i=0; utx[i]!=0; i++) + if ( utx[i] == 'Z' ) + { + memcpy(UTX,utx,i); + for (j=0; j<128; j++) + UTX[i+j] = '0'; + UTX[i+j] = 0; + strcat(UTX,utx+i+1); + break; + } + } + sighash = jstr(origjson,"S"); + if ( iQ->s.isask == 0 ) + recvasset = iQ->s.baseid, recvqty = iQ->s.baseamount / get_assetmult(recvasset); + else recvasset = iQ->s.relid, recvqty = iQ->s.relamount / get_assetmult(recvasset); + printf("utx.(%s) -> UTX.(%s) sighash.(%s)\n",utx,UTX,sighash); + } + else + { + recvqty = otherqty; + recvasset = otherbits; + } + if ( phasedtx != 0 || (jsonstr= issue_calculateFullHash(UTX,sighash)) != 0 ) + { + if ( phasedtx != 0 || (json= cJSON_Parse(jsonstr)) != 0 ) + { + copy_cJSON(&calchash,jobj(json,"fullHash")); + if ( phasedtx != 0 || strcmp(calchash.buf,fullhash) == 0 ) + { + if ( (parsed= issue_parseTransaction(phasedtx != 0 ? phasedtx : UTX)) != 0 ) + { + _stripwhite(parsed,' '); + //printf("iQ (%llu/%llu) otherbits.%llu qty %llu PARSED OFFER.(%s) triggerhash.(%s) (%s) offer sender.%s\n",(long long)iQ->s.baseid,(long long)iQ->s.relid,(long long)otherbits,(long long)otherqty,parsed,fullhash,calchash,sender); + if ( (txobj= cJSON_Parse(parsed)) != 0 ) + { + *deadlinep = juint(txobj,"deadline"); + timestamp = juint(txobj,"timestamp"); + now = issue_getTime(); + if ( (attachment= jobj(txobj,"attachment")) != 0 ) + *finishp = juint(attachment,"phasingFinishHeight"); + cmpstr = jstr(txobj,"referencedTransactionFullHash"); + if ( *deadlinep >= INSTANTDEX_TRIGGERDEADLINE/2 && ((long)now - timestamp) < 60 && (cmpstr == 0 || triggerhash == 0 || (cmpstr != 0 && triggerhash != 0 && strcmp(cmpstr,triggerhash) == 0)) ) + { + // https://nxtforum.org/nrs-releases/nrs-v1-5-15/msg191715/#msg191715 + printf("GEN RESPONDTX lag.%d deadline.%d (recv.%llu %lld) recv.(%llu %lld) orderid.%llu/%llx quoteid.%llu/%llx\n",now-timestamp,*deadlinep,(long long)recvasset,(long long)recvqty,(long long)recvasset,(long long)recvqty,(long long)orderid,(long long)orderid,(long long)quoteid,(long long)quoteid); + if ( InstantDEX_verify(IGUANA_MY64BITS,recvasset,recvqty,txobj,recvasset,recvqty) == 0 ) + retval = 0; + else printf("(%s) didnt validate against quoteid.%llu\n",parsed,(long long)quoteid); + } else fprintf(stderr,"swap rejects tx deadline %d >= INSTANTDEX_TRIGGERDEADLINE/2 && (now %d - %d timestamp) %d < 60\n",*deadlinep,now,timestamp,now-timestamp); + free_json(txobj); + } else fprintf(stderr,"swap cant parse tx.(%s)\n",parsed); + free(parsed); + } else fprintf(stderr,"swap cant parse UTX.(%s)\n",UTX); + } else fprintf(stderr,"mismatch (%s) != (%s)\n",calchash.buf,fullhash); + if ( json != 0 ) + free_json(json); + } else fprintf(stderr,"swap cant parse.(%s)\n",jsonstr); + if ( jsonstr != 0 ) + free(jsonstr); + } else fprintf(stderr,"calchash.(%s)\n",jsonstr); + return(retval); +} + +struct pending_trade *pending_swap(char **strp,int32_t type,uint64_t orderid,uint64_t quoteid,char *triggerhash,char *fullhash,char *txstr,char *txstr2) +{ + struct pending_trade *pend; cJSON *retjson; + pend = calloc(1,sizeof(*pend)); + pend->orderid = orderid, pend->quoteid = quoteid; + if ( triggerhash != 0 ) + pend->triggertx = clonestr(triggerhash); + if ( fullhash != 0 ) + pend->txbytes = clonestr(fullhash); + pend->type = type; + if ( txstr != 0 && txstr2 != 0 ) + { + retjson = cJSON_CreateObject(); + jadd(retjson,"fee",cJSON_Parse(txstr)); + jadd(retjson,"responsetx",cJSON_Parse(txstr2)); + *strp = jprint(retjson,0); + pend->tradesjson = retjson; + } + pend->timestamp = (uint32_t)time(NULL); + return(pend); +} + +char *swap_responseNXT(int32_t type,char *offerNXT,uint64_t otherbits,uint64_t otherqty,uint64_t orderid,uint64_t quoteid,int32_t deadline,char *triggerhash,char *phaselink,int32_t finishheight,struct InstantDEX_quote *iQ) +{ + struct NXTtx fee,responsetx; int32_t errcode,errcode2; char *txstr,*txstr2,*str = 0; struct pending_trade *pend; + gen_NXTtx(&fee,calc_nxt64bits(INSTANTDEX_ACCT),NXT_ASSETID,INSTANTDEX_FEE,orderid,quoteid,deadline,triggerhash,0,0,0); + gen_NXTtx(&responsetx,calc_nxt64bits(offerNXT),otherbits,otherqty,orderid,quoteid,deadline,triggerhash,phaselink,finishheight,0); + if ( (fee.txid= issue_broadcastTransaction(&errcode,&txstr,fee.txbytes,IGUANA_NXTACCTSECRET)) != 0 ) + { + if ( (responsetx.txid= issue_broadcastTransaction(&errcode2,&txstr2,responsetx.txbytes,IGUANA_NXTACCTSECRET)) != 0 ) + { + if ( (pend= pending_swap(&str,type,orderid,quoteid,triggerhash,phaselink,txstr,txstr2)) != 0 && str != 0 ) + { + iQ->s.pending = iQ->s.swap = 1; + //InstantDEX_history(0,pend,str); + pend->queueflag = 1; + queue_enqueue("PendingQ",&Pending_offersQ,&pend->DL,0); + printf("BROADCAST fee.txid %llu and %llu (%s %s)\n",(long long)fee.txid,(long long)responsetx.txid,fee.fullhash,responsetx.fullhash); + } + } else printf("error.%d broadcasting responsetx.(%s) %s\n",errcode2,responsetx.txbytes,txstr2); + } else printf("error.%d broadcasting feetx.(%s) %s\n",errcode,fee.txbytes,txstr); + if ( str == 0 ) + str = clonestr("{\"error\":\"swap_responseNXT error responding\"}"); + return(str); +} + +int32_t extract_pkhash(char *pubkeystr,char *pkhash,char *script) +{ + int32_t len; uint8_t rmd160[20],data[4096],*ptr; + decode_hex(data,(int32_t)strlen(script)>>1,script); + len = data[0]; + ptr = &data[len + 1]; + len = *ptr++; + if ( len == 33 ) + { + init_hexbytes_noT(pubkeystr,ptr,33); + calc_OP_HASH160(pkhash,rmd160,pubkeystr); + printf("pkhash.(%s)\n",pkhash); + return(0); + } + return(-1); +} + +char *swap_func(int32_t localaccess,int32_t valid,char *sender,cJSON *origjson,char *origargstr) +{ + /*char script[4096],hexstr[128],*str,*base,*rel,*txstr,*phasedtx,*cointxid,*signedtx,*jsonstr; uint8_t msgbuf[512]; + struct pending_trade *pend; struct prices777_order order; struct InstantDEX_quote *iQ,_iQ; cJSON *json; + uint32_t deadline,finishheight,nonce,isask; int32_t errcode,myoffer,myfill,len; struct NXTtx sendtx,fee; struct destbuf spendtxid,reftx; + struct destbuf offerNXT,exchange; uint64_t otherbits,otherqty,quoteid,orderid,recvasset,recvqty,sendasset,sendqty,fillNXT,destbits,value; + char pubkeystr[128],pkhash[64],swapbuf[4096],refredeemscript[1024],vintxid[128],*triggerhash,*fullhash,*dest,deststr[64];*/ + struct destbuf offerNXT,exchange; uint32_t deadline,finishheight,isask; char *triggerhash,*fullhash; int32_t myoffer,myfill; struct InstantDEX_quote *iQ,_iQ; struct prices777_order order; + uint64_t otherbits,otherqty,quoteid,orderid,fillNXT; + copy_cJSON(&offerNXT,jobj(origjson,"offerNXT")); + fillNXT = j64bits(origjson,"fillNXT"); + copy_cJSON(&exchange,jobj(origjson,"exchange")); + finishheight = juint(origjson,"F"); + if ( (triggerhash= jstr(origjson,"T")) == 0 ) + triggerhash = jstr(origjson,"trigger"); + myoffer = strcmp(IGUANA_NXTADDR,offerNXT.buf) == 0; + myfill = (IGUANA_MY64BITS == fillNXT); +//printf("swap_func got (%s)\n",origargstr); + if ( myoffer+myfill != 0 ) + { + orderid = j64bits(origjson,"orderid"); + quoteid = j64bits(origjson,"quoteid"); + if ( (iQ= find_iQ(quoteid)) == 0 ) + { + fprintf(stderr,"swap_func: cant find quoteid.%llu\n",(long long)quoteid); + iQ = &_iQ, memset(iQ,0,sizeof(*iQ)); + //return(clonestr("{\"error\":\"cant find quoteid\"}")); + } + if ( iQ->s.responded != 0 ) + { + fprintf(stderr,"already responded quoteid.%llu\n",(long long)iQ->s.quoteid); + return(0); + } + isask = iQ->s.isask; + memset(&order,0,sizeof(order)); + order.s = iQ->s; +#ifdef notyet + if ( strcmp("wallet",exchange.buf) == 0 ) + { + uint64_t sendamount,recvamount; struct coin777 *recvcoin,*sendcoin; + char refundsig[512],fieldA[64],fieldB[64],fieldpkhash[64]; + char *recvstr,*sendstr,*spendtx,*refundtx,*redeemscript,*rpubA,*rpubB,*rpkhash,*spubA,*spubB,*spkhash; + recvcoin = sendcoin = 0; sendamount = recvamount = 0; + if ( (recvstr= jstr(origjson,"recvcoin")) != 0 ) + recvcoin = coin777_find(recvstr,0); + if ( (sendstr= jstr(origjson,"sendcoin")) != 0 ) + sendcoin = coin777_find(sendstr,0); + if ( iQ->s.baseid == NXT_ASSETID ) + isask ^= 1; + //printf("recvstr.%p sendstr.%p\n",recvstr,sendstr); + if ( recvstr != 0 && sendstr != 0 ) + { + if ( (sendamount= j64bits(origjson,"sendamount")) != 0 && (recvamount= j64bits(origjson,"recvamount")) != 0 && sendcoin != 0 && recvcoin != 0 && (refundtx= jstr(origjson,"rtx")) != 0 && (redeemscript= jstr(origjson,"rs")) != 0 && (rpubA= jstr(origjson,"rpubA")) != 0 && (rpubB= jstr(origjson,"rpubB")) != 0 && (rpkhash= jstr(origjson,"rpkhash")) != 0 && triggerhash != 0 && (spubA= jstr(origjson,"spubA")) != 0 && (spubB= jstr(origjson,"spubB")) != 0 && (spkhash= jstr(origjson,"spkhash")) != 0 ) + { + } + } + else if ( recvstr != 0 ) + { + //printf("INCOMINGRECV.(%s)\n",origargstr); + sprintf(fieldA,"%spubA",recvcoin->name); + sprintf(fieldB,"%spubB",recvcoin->name); + sprintf(fieldpkhash,"%spkhash",recvcoin->name); + if ( (recvamount= j64bits(origjson,"recvamount")) != 0 && recvcoin != 0 && (rpubA= jstr(origjson,fieldA)) != 0 && (rpubB= jstr(origjson,fieldB)) != 0 && (rpkhash= jstr(origjson,fieldpkhash)) != 0 ) + { + if ( ((isask != 0 && myoffer != 0) || (isask == 0 && myfill != 0)) && j64bits(origjson,"fill") != IGUANA_MY64BITS && (refundtx= jstr(origjson,"rtx")) != 0 && (redeemscript= jstr(origjson,"rs")) != 0 ) // Bob: sends NXT to Alice, recvs recvcoin + { + subatomic_pubkeyhash(pubkeystr,pkhash,recvcoin,quoteid); + //printf("CALC >>>>>>>>>> (%s) vs (%s)\n",pkhash,rpkhash); + if ( (base= jstr(origjson,"base")) != 0 && (rel= jstr(origjson,"rel")) != 0 && (sendasset= j64bits(origjson,"sendasset")) != 0 && (sendqty= j64bits(origjson,"sendqty")) != 0 ) + { + //printf("inside (%s/%s) sendasset.%llu sendqty.%llu rpkhash.(%s)\n",base,rel,(long long)sendasset,(long long)sendqty,rpkhash); + if ( (spendtx= subatomic_spendtx(&spendtxid,vintxid,refundsig,recvcoin,rpubA,rpubB,pubkeystr,recvamount,refundtx,redeemscript)) != 0 ) + { + finishheight = 60; deadline = 3600*4; + if ( (pend= pending_swap(&str,'A',orderid,quoteid,0,0,0,0)) != 0 ) + { + if ( isask == 0 ) + destbits = calc_nxt64bits(offerNXT.buf); + else destbits = fillNXT; + gen_NXTtx(&fee,calc_nxt64bits(INSTANTDEX_ACCT),NXT_ASSETID,INSTANTDEX_FEE,orderid,quoteid,deadline,triggerhash,0,0,0); + issue_broadcastTransaction(&errcode,&txstr,fee.txbytes,IGUANA_NXTACCTSECRET); + gen_NXTtx(&sendtx,destbits,sendasset,sendqty,orderid,quoteid,deadline,triggerhash,0,_get_NXTheight(0)+finishheight,rpkhash); + //issue_broadcastTransaction(&errcode,&txstr,sendtx.txbytes,IGUANA_NXTACCTSECRET); + printf(">>>>>>>>>>>> broadcast fee and phased.(%s) trigger.%s\n",sendtx.txbytes,triggerhash); + sprintf(swapbuf,"{\"orderid\":\"%llu\",\"quoteid\":\"%llu\",\"offerNXT\":\"%s\",\"fillNXT\":\"%llu\",\"plugin\":\"relay\",\"destplugin\":\"InstantDEX\",\"method\":\"busdata\",\"submethod\":\"swap\",\"exchange\":\"wallet\",\"recvcoin\":\"%s\",\"recvamount\":\"%lld\",\"%s\":\"%s\",\"%s\":\"%s\",\"%s\":\"%s\",\"refundsig\":\"%s\",\"phasedtx\":\"%s\",\"spendtxid\":\"%s\",\"a\":\"%llu\",\"q\":\"%llu\",\"trigger\":\"%s\",\"fill\":\"%llu\"}",(long long)orderid,(long long)quoteid,offerNXT.buf,(long long)fillNXT,recvcoin->name,(long long)recvamount,fieldA,rpubA,fieldB,rpubB,fieldpkhash,rpkhash,refundsig,sendtx.txbytes,spendtxid.buf,(long long)sendasset,(long long)sendqty,triggerhash,(long long)IGUANA_MY64BITS); + if ( (str= busdata_sync(&nonce,swapbuf,"allnodes",0)) != 0 ) + free(str); + // poll for vin then broadcast spendtx + printf(">>>>>>>>>>>>>>>>>>>> wait for (%s) then send SPENDTX.(%s)\n",vintxid,spendtx); + if ( (value= wait_for_txid(script,recvcoin,vintxid,0,recvamount,recvcoin->minconfirms,0)) != 0 ) + { + signedtx = malloc(strlen(spendtx) + 16); + sprintf(signedtx,"[\"%s\"]",spendtx); + if ( (cointxid= bitcoind_passthru(recvcoin->name,recvcoin->serverport,recvcoin->userpass,"sendrawtransaction",signedtx)) != 0 ) + { + printf(">>>>>>>>>>>>> BROADCAST SPENDTX.(%s) (%s)\n",signedtx,cointxid); + free(cointxid); + } + free(signedtx); + } + printf("ATOMIC SWAP.%llu finished\n",(long long)quoteid); + iQ->s.closed = 1; + delete_iQ(quoteid); + } else printf("cant get pending_swap pend.%p\n",pend); + free(spendtx); + return(clonestr(swapbuf)); + } else printf("error generating spendtx\n"); + } else printf("mismatched recv (%s vs %s) or (%s)\n",recvcoin->atomicrecvpubkey,rpubB,rpkhash); + } + else if ( j64bits(origjson,"fill") != IGUANA_MY64BITS && (str= jstr(origjson,"refundsig")) != 0 && str[0] != 0 && (phasedtx= jstr(origjson,"phasedtx")) != 0 && phasedtx[0] != 0 ) // Alice to verify NXTtx and send recvcoin + { + if ( isask != 0 ) + dest = offerNXT.buf; + else + { + expand_nxt64bits(deststr,fillNXT); + dest = deststr; + } + if ( swap_verifyNXT(&finishheight,&deadline,origjson,dest,exchange.buf,orderid,quoteid,iQ,phasedtx) == 0 ) + { + if ( recvcoin->refundtx != 0 && (recvcoin->signedrefund= subatomic_validate(recvcoin,rpubA,rpubB,rpkhash,recvcoin->refundtx,str)) != 0 ) + { + free(recvcoin->refundtx), recvcoin->refundtx = 0; + issue_broadcastTransaction(&errcode,&txstr,recvcoin->trigger.txbytes,IGUANA_NXTACCTSECRET); + issue_broadcastTransaction(&errcode,&txstr,phasedtx,IGUANA_NXTACCTSECRET); + printf(">>>>>>>>>>>>>>>>>>>>>>>>>>> ISSUE TRIGGER.(%s) phased.(%s).%d | signedrefund.(%s)\n",recvcoin->trigger.txbytes,txstr!=0?txstr:"phasedsubmit error",errcode,recvcoin->signedrefund); + signedtx = malloc(strlen(recvcoin->funding.signedtransaction) + 16); + sprintf(signedtx,"[\"%s\"]",recvcoin->funding.signedtransaction); + if ( (cointxid= bitcoind_passthru(recvcoin->name,recvcoin->serverport,recvcoin->userpass,"sendrawtransaction",signedtx)) != 0 ) + { + printf(">>>>>>>>>>>>> FUNDING BROADCAST.(%s) (%s)\n",recvcoin->funding.signedtransaction,cointxid); + free(cointxid); + } else printf("error sendrawtransaction.(%s)\n",recvcoin->funding.signedtransaction); + free(signedtx); + copy_cJSON(&spendtxid,jobj(origjson,"spendtxid")); + printf("wait for spendtx.(%s)\n",spendtxid.buf); + if ( (value= wait_for_txid(script,recvcoin,spendtxid.buf,0,recvamount-recvcoin->mgw.txfee,0,0)) != 0 ) + { + iQ->s.responded = 1; + if ( extract_pkhash(pubkeystr,pkhash,script) == 0 ) + { + if ( strcmp(pkhash,rpkhash) == 0 ) + { + reftx.buf[0] = 0; + if ( (jsonstr= issue_parseTransaction(phasedtx)) != 0 ) + { + if ( (json= cJSON_Parse(jsonstr)) != 0 ) + { + copy_cJSON(&reftx,jobj(json,"fullHash")); + free_json(json); + } + free(jsonstr); + } + len = 0; + len = txind777_txbuf(msgbuf,len,orderid,sizeof(orderid)); + len = txind777_txbuf(msgbuf,len,quoteid,sizeof(quoteid)); + init_hexbytes_noT(hexstr,msgbuf,len); + if ( (str= issue_approveTransaction(reftx.buf,pubkeystr,hexstr,IGUANA_NXTACCTSECRET)) != 0 ) + { + printf("fullhash.(%s) pubkey.(%s) pkhash.(%s) APPROVED.(%s)\n",reftx.buf,pubkeystr,pkhash,str); + free(str); + } else printf("error sending in approval\n"); + + } else printf("script.(%s) -> pkhash.(%s) vs rpkhash.(%s)\n",script,pkhash,rpkhash); + } else printf("unexpected end of script.(%s) (%s)\n",script,str); + } + printf("FINISHED ATOMIC SWAP of quoteid.%llu\n",(long long)quoteid); + iQ->s.closed = 1; + memset(&recvcoin->trigger,0,sizeof(recvcoin->trigger)); + memset(&recvcoin->funding,0,sizeof(recvcoin->funding)); + free(recvcoin->signedrefund), recvcoin->signedrefund = 0; + delete_iQ(quoteid); + } else printf("refund tx didnt verify\n"); + } else printf("NXT tx didnt verify\n"); + } //else printf("myfill.%d myoffer.%d recv mismatch isask.%d\n",myfill,myoffer,iQ->s.isask); + //printf("recv failed\n"); + return(clonestr("{\"result\":\"recv failed\"}")); + } + } + else if ( sendstr != 0 ) // Alice sendcoin -> Bob, recvs NXT + { + //printf("INCOMINGSEND.(%s)\n",origargstr); + sprintf(fieldA,"%spubA",sendcoin->name); + sprintf(fieldB,"%spubB",sendcoin->name); + sprintf(fieldpkhash,"%spkhash",sendcoin->name); + if ( ((isask == 0 && myoffer != 0) || (isask != 0 && myfill != 0)) && (sendamount= j64bits(origjson,"sendamount")) != 0 && sendcoin != 0 && triggerhash != 0 && (spubA= jstr(origjson,fieldA)) != 0 && (spubB= jstr(origjson,fieldB)) != 0 && (spkhash= jstr(origjson,fieldpkhash)) != 0 ) + { + if ( (base= jstr(origjson,"base")) != 0 && (rel= jstr(origjson,"rel")) != 0 && (recvasset= j64bits(origjson,"recvasset")) != 0 && (recvqty= j64bits(origjson,"recvqty")) != 0 ) + { + if ( sendcoin->funding.signedtransaction[0] == 0 && (refundtx= subatomic_fundingtx(refredeemscript,&sendcoin->funding,sendcoin,spubA,spubB,spkhash,sendamount,10)) != 0 ) + { + deadline = 3600; + gen_NXTtx(&sendcoin->trigger,calc_nxt64bits(INSTANTDEX_ACCT),NXT_ASSETID,INSTANTDEX_FEE,orderid,quoteid,deadline,0,0,0,0); + sprintf(swapbuf,"{\"orderid\":\"%llu\",\"quoteid\":\"%llu\",\"offerNXT\":\"%s\",\"fillNXT\":\"%llu\",\"plugin\":\"relay\",\"destplugin\":\"InstantDEX\",\"method\":\"busdata\",\"submethod\":\"swap\",\"exchange\":\"%s\",\"recvamount\":\"%lld\",\"rtx\":\"%s\",\"rs\":\"%s\",\"recvcoin\":\"%s\",\"%s\":\"%s\",\"%s\":\"%s\",\"%s\":\"%s\",\"trigger\":\"%s\",\"sendasset\":\"%llu\",\"sendqty\":\"%llu\",\"base\":\"%s\",\"rel\":\"%s\",\"fill\":\"%llu\"}",(long long)orderid,(long long)quoteid,offerNXT.buf,(long long)fillNXT,exchange.buf,(long long)sendamount,refundtx,refredeemscript,sendstr,fieldA,spubA,fieldB,spubB,fieldpkhash,spkhash,sendcoin->trigger.fullhash,(long long)recvasset,(long long)recvqty,base,rel,(long long)IGUANA_MY64BITS); + sendcoin->refundtx = refundtx; + if ( (str= busdata_sync(&nonce,swapbuf,"allnodes",0)) != 0 ) + free(str); + return(clonestr(swapbuf)); + //printf("BUSDATA.(%s)\n",swapbuf); + } else return(clonestr("{\"error\":\"cant create refundtx, maybe already pending\"}\n")); + } //else printf("mismatched send (%s vs %s) or (%s)\n",sendcoin->atomicrecvpubkey,spubB,spkhash); + } else printf("myfill.%d myoffer.%d send mismatch isask.%d\n",myfill,myoffer,iQ->s.isask); + } + return(clonestr("{\"result\":\"processed wallet swap\"}")); + } +#endif + if ( myoffer != 0 && swap_verifyNXT(&finishheight,&deadline,origjson,offerNXT.buf,exchange.buf,orderid,quoteid,iQ,0) == 0 ) + { + otherbits = j64bits(origjson,"a"); + otherqty = j64bits(origjson,"q"); + fullhash = jstr(origjson,"FH"); + finishheight = juint(origjson,"F"); + return(swap_responseNXT('R',offerNXT.buf,otherbits,otherqty,orderid,quoteid,deadline,triggerhash,fullhash,finishheight,iQ)); + } else printf("myfill.%d myoffer.%d swap mismatch\n",myfill,myoffer); + } + return(clonestr("{\"result\":\"processed swap\"}")); +} + +int32_t match_unconfirmed(char *sender,char *hexstr,cJSON *txobj,char *txidstr,char *account,uint64_t amount,uint64_t qty,uint64_t assetid,char *recipient) +{ + // ok, the bug here is that on a delayed respondtx, the originator should refuse to release the trigger (and the money tx) + uint64_t orderid,quoteid,recvasset,sendasset; int64_t recvqty,sendqty; uint32_t bidask,deadline,timestamp,now; struct InstantDEX_quote *iQ; + decode_hex((void *)&orderid,sizeof(orderid),hexstr); + decode_hex((void *)"eid,sizeof(quoteid),hexstr+16); + //printf("match_unconfirmed.(%s) orderid.%llu %llx quoteid.%llu %llx\n",hexstr,(long long)orderid,(long long)orderid,(long long)quoteid,(long long)quoteid); + deadline = juint(txobj,"deadline"); + timestamp = juint(txobj,"timestamp"); + now = issue_getTime(); + //printf("deadline.%u now.%u timestamp.%u lag %ld\n",deadline,now,timestamp,((long)now - timestamp)); + if ( deadline < INSTANTDEX_TRIGGERDEADLINE/2 || ((long)now - timestamp) > 60*2 ) + return(0); + if ( (iQ= find_iQ(quoteid)) != 0 && iQ->s.closed == 0 && iQ->s.pending != 0 && (iQ->s.responded == 0 || iQ->s.feepaid == 0) ) + { + if ( Debuglevel > 2 ) + printf("match unconfirmed %llu/%llu %p swap.%d feepaid.%d responded.%d sender.(%s) -> recv.(%s) me.(%s) offer.(%llu)\n",(long long)orderid,(long long)quoteid,iQ,iQ->s.swap,iQ->s.feepaid,iQ->s.responded,sender,recipient,IGUANA_NXTADDR,(long long)iQ->s.offerNXT); + if ( iQ->s.swap != 0 && (strcmp(recipient,INSTANTDEX_ACCT) == 0 || strcmp(recipient,IGUANA_NXTADDR) == 0) ) + { + if ( iQ->s.feepaid == 0 ) + { + if ( verify_NXTtx(txobj,NXT_ASSETID,INSTANTDEX_FEE,calc_nxt64bits(INSTANTDEX_ACCT)) == 0 ) + { + iQ->s.feepaid = 1; + printf("FEE DETECTED\n"); + } else printf("notfee: dest.%s src.%s amount.%llu qty.%llu assetid.%llu\n",recipient,sender,(long long)amount,(long long)qty,(long long)assetid); + } + if ( iQ->s.responded == 0 ) + { + bidask = iQ->s.isask; + if ( iQ->s.offerNXT == IGUANA_MY64BITS ) + bidask ^= 1; + if ( bidask != 0 ) + { + sendasset = iQ->s.relid, sendqty = iQ->s.relamount; + recvasset = iQ->s.baseid, recvqty = iQ->s.baseamount; + } + else + { + sendasset = iQ->s.baseid, sendqty = iQ->s.baseamount; + recvasset = iQ->s.relid, recvqty = iQ->s.relamount; + } + sendqty /= get_assetmult(sendasset); + recvqty /= get_assetmult(recvasset); + if ( Debuglevel > 2 ) + printf("sendasset.%llu sendqty.%llu mult.%llu, recvasset.%llu recvqty.%llu mult.%llu\n",(long long)sendasset,(long long)sendqty,(long long)get_assetmult(sendasset),(long long)recvasset,(long long)recvqty,(long long)get_assetmult(recvasset)); + if ( InstantDEX_verify(IGUANA_MY64BITS,sendasset,sendqty,txobj,recvasset,recvqty) == 0 ) + { + iQ->s.responded = 1; + printf("iQ: %llu/%llu %lld/%lld | recv %llu %lld offerNXT.%llu\n",(long long)iQ->s.baseid,(long long)iQ->s.relid,(long long)iQ->s.baseamount,(long long)iQ->s.relamount,(long long)recvasset,(long long)recvqty,(long long)iQ->s.offerNXT); + printf("RESPONSE DETECTED\n"); + } + } + if ( iQ->s.responded != 0 && iQ->s.feepaid != 0 ) + { + printf("both detected offer.%llu my64bits.%llu\n",(long long)iQ->s.offerNXT,(long long)IGUANA_MY64BITS); + complete_swap(iQ,orderid,quoteid,iQ->s.offerNXT == IGUANA_MY64BITS); + } + } + } + return(-1); +} + +int32_t is_unfunded_order(uint64_t nxt64bits,uint64_t assetid,uint64_t amount) +{ + char assetidstr[64],NXTaddr[64],cmd[1024],*jsonstr; + int64_t ap_mult,unconfirmed,balance = 0; + cJSON *json; + expand_nxt64bits(NXTaddr,nxt64bits); + if ( assetid == NXT_ASSETID ) + { + sprintf(cmd,"requestType=getAccount&account=%s",NXTaddr); + if ( (jsonstr= issue_NXTPOST(cmd)) != 0 ) + { + if ( (json= cJSON_Parse(jsonstr)) != 0 ) + { + balance = get_API_nxt64bits(cJSON_GetObjectItem(json,"balanceNQT")); + free_json(json); + } + free(jsonstr); + } + strcpy(assetidstr,"NXT"); + } + else + { + expand_nxt64bits(assetidstr,assetid); + if ( (ap_mult= assetmult(assetidstr)) != 0 ) + { + expand_nxt64bits(NXTaddr,nxt64bits); + balance = ap_mult * get_asset_quantity(&unconfirmed,NXTaddr,assetidstr); + } + } + if ( balance < amount ) + { + printf("balance %.8f < amount %.8f for asset.%s\n",dstr(balance),dstr(amount),assetidstr); + return(1); + } + return(0); +} + +cJSON *InstantDEX_tradejson(int32_t *curlingp,void *bot,struct pending_trade **pendp,void **cHandlep,cJSON *item,char *activenxt,char *secret,struct prices777_order *order,int32_t dotrade,uint64_t orderid,char *extra) +{ + char swapbuf[8192],buf[8192],triggertx[4096],txbytes[4096],*retstr,*exchange; uint64_t txid,qty,avail,priceNQT; + struct prices777 *prices; cJSON *json = 0; + if ( pendp != 0 ) + *pendp = 0; + if ( (prices= order->source) != 0 ) + { + exchange = prices->exchange; + swapbuf[0] = 0; + if ( dotrade == 0 ) + { + if ( strcmp(exchange,INSTANTDEX_NAME) != 0 && strcmp(exchange,"wallet") != 0 ) + { + sprintf(buf,"{\"orderid\":\"%llu\",\"trade\":\"%s\",\"exchange\":\"%s\",\"base\":\"%s\",\"rel\":\"%s\",\"baseid\":\"%llu\",\"relid\":\"%llu\",\"price\":%.8f,\"volume\":%.8f,\"extra\":\"%s\"}",(long long)orderid,order->wt > 0. ? "buy" : "sell",exchange,prices->base,prices->rel,(long long)prices->baseid,(long long)prices->relid,order->s.price,order->s.vol,extra!=0?extra:""); + if ( strcmp(exchange,"nxtae") == 0 ) + { + qty = calc_asset_qty(&avail,&priceNQT,activenxt,0,prices->baseid,order->s.price,order->s.vol); + sprintf(buf+strlen(buf)-1,",\"priceNQT\":\"%llu\",\"quantityQNT\":\"%llu\",\"avail\":\"%llu\"}",(long long)priceNQT,(long long)qty,(long long)avail); + if ( qty == 0 ) + sprintf(buf+strlen(buf)-1,",\"error\":\"insufficient balance\"}"); + } + return(cJSON_Parse(buf)); + } + else + { + //{"inverted":0,"contract":"MMNXT/Jay","baseid":"979292558519844732","relid":"8688289798928624137","bids":[{"plugin":"Inst + // antDEX","method":"tradesequence","dotrade":1,"price":2,"volume":2,"trades":[]}],"asks":[],"numbids":1,"numasks":0,"lastb + // id":2,"lastask":0,"NXT":"11471677413693100042","timestamp":1440587058,"maxdepth":25} + prices777_swapbuf("yes",0,&txid,triggertx,txbytes,swapbuf,prices->exchange,prices->base,prices->rel,order,orderid,extra==0?0:myatoi(extra,10000),0); + return(cJSON_Parse(swapbuf)); + } + } + retstr = prices777_trade(curlingp,bot,pendp,cHandlep,dotrade,item,activenxt,secret,prices,order->wt,order->s.price,order->s.vol,0,order,orderid,extra); + if ( retstr != 0 ) + { + json = cJSON_Parse(retstr); + free(retstr); + } + } + return(json); +} + +char *InstantDEX_dotrades(int32_t curlings[],void *bot,void *cHandles[],char *activenxt,char *secret,cJSON *json,struct prices777_order *trades,int32_t numtrades,int32_t dotrade,char *extra) +{ + struct destbuf exchangestr,gui,name,base,rel; struct InstantDEX_quote iQ; cJSON *retjson,*retarray; int32_t i; + bidask_parse(1,&exchangestr,&name,&base,&rel,&gui,&iQ,json); + retjson = cJSON_CreateObject(), retarray = cJSON_CreateArray(); + for (i=0; i maxtrades ) + return(clonestr("{\"error\":\"exceeded max trades possible in a tradesequence\"}")); + if ( n == 1 && is_cJSON_Array(jitem(array,0)) != 0 ) + { + //printf("NESTED ARRAY DETECTED\n"); + array = jitem(array,0); + n = cJSON_GetArraySize(array); + } + *nump = n; + timestamp = (uint32_t)time(NULL); + for (i=0; iid = orderid, order->s.quoteid = quoteid; + assetid = j64bits(item,"asset"), currency = j64bits(item,"currency"); + baseid = j64bits(item,"baseid"), relid = j64bits(item,"relid"); + sendbase = j64bits(item,"sendbase"), recvbase = j64bits(item,"recvbase"); + sendrel = j64bits(item,"sendrel"), recvrel = j64bits(item,"recvrel"); + order->s.baseamount = (recvbase - sendbase); + order->s.relamount = (recvrel - sendrel); + orderprice = jdouble(item,"orderprice"), ordervolume = jdouble(item,"ordervolume"); + order->s.timestamp = juint(item,"timestamp"); + order->s.duration = juint(item,"duration"); + order->s.minperc = juint(item,"minperc"); + order->s.baseid = baseid; + order->s.relid = relid; + //printf("ITEM.(%s)\n",jprint(item,0)); + if ( tradestr != 0 ) + { + if ( strcmp(tradestr,"buy") == 0 ) + dir = 1; + else if ( strcmp(tradestr,"sell") == 0 ) + dir = -1; + else if ( strcmp(tradestr,"swap") == 0 ) + dir = 0; + else return(clonestr("{\"error\":\"invalid trade direction\"}")); + if ( (prices= prices777_initpair(1,exchangestr,base.buf,rel.buf,0.,name.buf,baseid,relid,0)) != 0 ) + { + order->source = prices; + order->s.offerNXT = j64bits(item,"offerNXT"); + order->wt = dir, order->s.price = orderprice, order->s.vol = ordervolume; + printf("item[%d] dir.%d (price %.8f vol %.4f) %s/%s baseid.%llu relid.%llu sendbase.%llu recvbase.%llu sendrel.%llu recvrel.%llu | baseqty.%lld relqty.%lld\n",i,dir,order->s.price,order->s.vol,prices->base,prices->rel,(long long)order->s.baseid,(long long)order->s.relid,(long long)sendbase,(long long)recvbase,(long long)sendrel,(long long)recvrel,(long long)order->s.baseamount,(long long)order->s.relamount); + } else return(clonestr("{\"error\":\"invalid exchange or contract pair\"}")); + } + else + { + printf("item.(%s)\n",jprint(item,0)); + return(clonestr("{\"error\":\"no trade specified\"}")); + } + } + return(InstantDEX_dotrades(curlings,bot,cHandles,activenxt,secret,json,trades,n,dotrade,jstr(json,"extra"))); + } + printf("error parsing.(%s)\n",jprint(json,0)); + return(clonestr("{\"error\":\"couldnt process trades\"}")); +} + +#endif diff --git a/iguana/exchanges/bitfinex.c b/iguana/exchanges/bitfinex.c new file mode 100755 index 000000000..2d39df913 --- /dev/null +++ b/iguana/exchanges/bitfinex.c @@ -0,0 +1,262 @@ +/****************************************************************************** + * Copyright © 2014-2016 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. * + * * + ******************************************************************************/ + +#define EXCHANGE_NAME "bitfinex" +#define UPDATE bitfinex ## _price +#define SUPPORTS bitfinex ## _supports +#define SIGNPOST bitfinex ## _signpost +#define TRADE bitfinex ## _trade +#define ORDERSTATUS bitfinex ## _orderstatus +#define CANCELORDER bitfinex ## _cancelorder +#define OPENORDERS bitfinex ## _openorders +#define TRADEHISTORY bitfinex ## _tradehistory +#define BALANCES bitfinex ## _balances +#define PARSEBALANCE bitfinex ## _parsebalance +#define WITHDRAW bitfinex ## _withdraw +#define CHECKBALANCE bitfinex ## _checkbalance + +double UPDATE(struct exchange_info *exchange,char *base,char *rel,struct exchange_quote *quotes,int32_t maxdepth,cJSON *argjson) +{ + char url[1024]; + sprintf(url,"https://api.bitfinex.com/v1/book/%s%s",base,rel); + return(exchanges777_standardprices(exchange,base,rel,url,quotes,"price","amount",maxdepth,0)); +} + +int32_t SUPPORTS(struct exchange_info *exchange,char *base,char *rel,cJSON *argjson) +{ + char *baserels[][2] = { {"btc","usd"}, {"ltc","usd"}, {"ltc","btc"} }; + return(baserel_polarity(baserels,(int32_t)(sizeof(baserels)/sizeof(*baserels)),base,rel)); +} + +char *PARSEBALANCE(struct exchange_info *exchange,double *balancep,char *coinstr,cJSON *argjson) +{ + //[[{"type":"deposit","currency":"btc","amount":"0.0","available":"0.0"},{"type":"deposit","currency":"usd","amount":"0.0","available":"0.0"},{"type":"exchange","currency":"btc","amount":"0.01065851","available":"0.01065851"},{"type":"exchange","currency":"usd","amount":"23386.37278962","available":"0.00378962"},{"type":"trading","currency":"btc","amount":"0.0","available":"0.0"},{"type":"trading","currency":"usd","amount":"0.0","available":"0.0"}]] + int32_t i,n,ind; char field[64],*str,*typestr,*itemstr = 0; cJSON *item,*obj,*array; double amounts[3],avail[3],val0,val1; + *balancep = 0.; + strcpy(field,coinstr), tolowercase(field); + memset(amounts,0,sizeof(amounts)); + memset(avail,0,sizeof(avail)); + if ( argjson != 0 && is_cJSON_Array(argjson) != 0 && (n= cJSON_GetArraySize(argjson)) > 0 ) + { + for (i=0; i= 0 ) + { + amounts[ind] = val0; + avail[ind] = val1; + } + } + } + } + } + if ( (obj= cJSON_CreateObject()) != 0 ) + { + touppercase(field); + *balancep = avail[0] + avail[1] + avail[2]; + jaddstr(obj,"base",field); + jaddnum(obj,"balance",*balancep); + jaddnum(obj,"total",amounts[0]+amounts[1]+amounts[2]); + array = cJSON_CreateArray(), jaddinum(array,avail[0]), jaddinum(array,amounts[0]), jadd(obj,"deposit",array); + array = cJSON_CreateArray(), jaddinum(array,avail[1]), jaddinum(array,amounts[1]), jadd(obj,"exchange",array); + array = cJSON_CreateArray(), jaddinum(array,avail[2]), jaddinum(array,amounts[2]), jadd(obj,"trading",array); + itemstr = jprint(obj,1); + } + } + if ( itemstr == 0 ) + return(clonestr("{\"error\":\"cant find coin balance\"}")); + return(itemstr); +} + +cJSON *SIGNPOST(void **cHandlep,int32_t dotrade,char **retstrp,struct exchange_info *exchange,char *payload,char *method) +{ + char dest[1025],url[1024],hdr1[512],hdr2[512],hdr3[512],hdr4[512],req[1024],*sig,*data = 0; cJSON *json; + hdr1[0] = hdr2[0] = hdr3[0] = hdr4[0] = 0; + json = 0; + nn_base64_encode((void *)payload,strlen(payload),req,sizeof(req)); + if ( (sig= hmac_sha384_str(dest,exchange->apisecret,(int32_t)strlen(exchange->apisecret),req)) != 0 ) + { + sprintf(hdr1,"X-BFX-APIKEY:%s",exchange->apikey); + sprintf(hdr2,"X-BFX-PAYLOAD:%s",req); + sprintf(hdr3,"X-BFX-SIGNATURE:%s",sig); + //printf("req.(%s) H0.(%s) H1.(%s) H2.(%s)\n",req,hdr1,hdr2,hdr3); + sprintf(url,"https://api.bitfinex.com/v1/%s",method); + if ( dotrade == 0 ) + data = exchange_would_submit(req,hdr1,hdr2,hdr3,hdr4); + else if ( (data= curl_post(&exchange->cHandle,url,0,req,hdr1,hdr2,hdr3,hdr4)) != 0 ) + json = cJSON_Parse(data); + if ( retstrp != 0 ) + *retstrp = data; + else if ( data != 0 ) + free(data); + } + return(json); +} + +cJSON *BALANCES(struct exchange_info *exchange,cJSON *argjson) +{ + char payload[1024],*method; + method = "balances"; + sprintf(payload,"{\"request\":\"/v1/%s\",\"nonce\":\"%llu\"}",method,(long long)exchange_nonce(exchange)); + return(SIGNPOST(&exchange->cHandle,1,0,exchange,payload,method)); +} + +#include "checkbalance.c" + +uint64_t TRADE(int32_t dotrade,char **retstrp,struct exchange_info *exchange,char *base,char *rel,int32_t dir,double price,double volume,cJSON *argjson) +{ + char payload[1024],pairstr[512],*typestr,*method,*extra; cJSON *json; uint64_t txid = 0; + if ( (extra= *retstrp) != 0 ) + *retstrp = 0; + if ( (dir= flipstr_for_exchange(exchange,pairstr,"%s%s",dir,&price,&volume,base,rel,argjson)) == 0 ) + { + printf("cant find baserel (%s/%s)\n",base,rel); + return(0); + } + method = "order/new"; + //Either "market" / "limit" / "stop" / "trailing-stop" / "fill-or-kill" / "exchange market" / "exchange limit" / "exchange stop" / "exchange trailing-stop" / "exchange fill-or-kill". (type starting by "exchange " are exchange orders, others are margin trading orders) + if ( (typestr= extra) == 0 ) + typestr = "exchange limit"; + sprintf(payload,"{\"request\":\"/v1/%s\",\"nonce\":\"%llu\",\"exchange\":\"bitfinex\",\"side\":\"%s\",\"type\":\"%s\",\"price\":\"%.8f\",\"amount\":\"%.8f\",\"symbol\":\"%s\"}",method,(long long)exchange_nonce(exchange),dir>0?"buy":"sell",typestr,price,volume,pairstr); + if ( CHECKBALANCE(retstrp,dotrade,exchange,dir,base,rel,price,volume,argjson) == 0 && (json= SIGNPOST(&exchange->cHandle,dotrade,retstrp,exchange,payload,method)) != 0 ) + { + if ( (txid= j64bits(json,"order_id")) == 0 ) + { + if ( dir != 0 ) + printf("bitfinex: no txid error\n"); + } + free_json(json); + } + return(txid); +} + +char *ORDERSTATUS(struct exchange_info *exchange,uint64_t quoteid,cJSON *argjson) +{ + char payload[1024],*method,*retstr = 0; cJSON *json; + method = "order/status"; + sprintf(payload,"{\"request\":\"/v1/%s\",\"nonce\":\"%llu\",\"order_id\":%llu}",method,(long long)exchange_nonce(exchange),(long long)quoteid); + if ( (json= SIGNPOST(&exchange->cHandle,1,&retstr,exchange,payload,method)) != 0 ) + { + free_json(json); + } + return(retstr); // return standardized orderstatus +} + +char *CANCELORDER(struct exchange_info *exchange,uint64_t quoteid,cJSON *argjson) +{ + char payload[1024],*method,*retstr = 0; cJSON *json; + method = "order/cancel"; + sprintf(payload,"{\"request\":\"/v1/%s\",\"nonce\":\"%llu\",\"order_id\":%llu}",method,(long long)exchange_nonce(exchange),(long long)quoteid); + if ( (json= SIGNPOST(&exchange->cHandle,1,&retstr,exchange,payload,method)) != 0 ) + { + free_json(json); + } + return(retstr); // return standardized cancelorder +} + +char *OPENORDERS(struct exchange_info *exchange,cJSON *argjson) +{ + char payload[1024],*method,*retstr = 0; cJSON *json; + method = "orders"; + sprintf(payload,"{\"request\":\"/v1/%s\",\"nonce\":\"%llu\"}",method,(long long)exchange_nonce(exchange)); + if ( (json= SIGNPOST(&exchange->cHandle,1,&retstr,exchange,payload,method)) != 0 ) + { + free_json(json); + } + return(retstr); // return standardized open orders +} + +char *TRADEHISTORY(struct exchange_info *exchange,cJSON *argjson) +{ + char payload[1024],baserel[16],*method,*base,*rel,*retstr = 0; uint32_t timestamp; cJSON *json; + method = "mytrades"; + base = jstr(argjson,"base"); + rel = jstr(argjson,"rel"); + if ( base == 0 || rel == 0 ) + { + base = "BTC"; + rel = "USD"; + } + sprintf(baserel,"%s%s",base,rel); + timestamp = juint(argjson,"start"); + sprintf(payload,"{\"request\":\"/v1/%s\",\"nonce\":\"%llu\",\"symbol\":\"%s\",\"timestamp\":%u}",method,(long long)exchange_nonce(exchange),baserel,timestamp); + //printf("TRADEHISTORY.(%s)\n",payload); + if ( (json= SIGNPOST(&exchange->cHandle,1,&retstr,exchange,payload,method)) != 0 ) + { + free_json(json); + } + return(retstr); // return standardized tradehistory +} + +char *WITHDRAW(struct exchange_info *exchange,char *base,double amount,char *destaddr,cJSON *argjson) +{ + char payload[1024],*method,*type,*retstr = 0; cJSON *json; + if ( base == 0 || base[0] == 0 ) + return(clonestr("{\"error\":\"base not specified\"}")); + if ( destaddr == 0 || destaddr[0] == 0 ) + return(clonestr("{\"error\":\"destaddr not specified\"}")); + if ( amount < SMALLVAL ) + return(clonestr("{\"error\":\"amount not specified\"}")); + if ( base == 0 ) + base = "bitcoin"; + else if ( strcmp(base,"BTC") == 0 ) + base = "bitcoin"; + else if ( strcmp(base,"LTC") == 0 ) + base = "litecoin"; + else if ( strcmp(base,"DRK") == 0 ) + base = "darkcoin"; + else return(clonestr("{\"error\":\"invalid base specified\"}")); + if ( (type= jstr(argjson,"extra")) == 0 ) + type = "exchange"; + else if ( strcmp(type,"exchange") != 0 && strcmp(type,"trading") != 0 && strcmp(type,"deposit") != 0 ) + return(clonestr("{\"error\":\"invalid wallet type specified\"}")); + method = "withdraw"; + sprintf(payload,"{\"request\":\"/v1/%s\",\"nonce\":\"%llu\",\"amount\":\"%.6f\",\"withdraw_type\":\"%s\",\"walletselected\":\"%s\",\"address\":\"%s\"}",method,(long long)exchange_nonce(exchange),amount,base,type,destaddr); + if ( (json= SIGNPOST(&exchange->cHandle,1,&retstr,exchange,payload,method)) != 0 ) + { + free_json(json); + } + return(retstr); // return standardized withdraw +} + +struct exchange_funcs bitfinex_funcs = EXCHANGE_FUNCS(bitfinex,EXCHANGE_NAME); + +#undef UPDATE +#undef SUPPORTS +#undef SIGNPOST +#undef TRADE +#undef ORDERSTATUS +#undef CANCELORDER +#undef OPENORDERS +#undef TRADEHISTORY +#undef BALANCES +#undef PARSEBALANCE +#undef WITHDRAW +#undef EXCHANGE_NAME +#undef CHECKBALANCE diff --git a/iguana/exchanges/bitstamp.c b/iguana/exchanges/bitstamp.c new file mode 100755 index 000000000..7317f501d --- /dev/null +++ b/iguana/exchanges/bitstamp.c @@ -0,0 +1,170 @@ +/****************************************************************************** + * Copyright © 2014-2016 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. * + * * + ******************************************************************************/ + +#define EXCHANGE_NAME "bitstamp" +#define UPDATE bitstamp ## _price +#define SUPPORTS bitstamp ## _supports +#define SIGNPOST bitstamp ## _signpost +#define TRADE bitstamp ## _trade +#define ORDERSTATUS bitstamp ## _orderstatus +#define CANCELORDER bitstamp ## _cancelorder +#define OPENORDERS bitstamp ## _openorders +#define TRADEHISTORY bitstamp ## _tradehistory +#define BALANCES bitstamp ## _balances +#define PARSEBALANCE bitstamp ## _parsebalance +#define WITHDRAW bitstamp ## _withdraw +#define EXCHANGE_AUTHURL "https://www.bitstamp.net/api" +#define CHECKBALANCE bitstamp ## _checkbalance + +double UPDATE(struct exchange_info *exchange,char *base,char *rel,struct exchange_quote *quotes,int32_t maxdepth,cJSON *argjson) +{ + char url[1024]; + sprintf(url,"https://www.bitstamp.net/api/order_book/"); + return(exchanges777_standardprices(exchange,base,rel,url,quotes,0,0,maxdepth,0)); +} + +int32_t SUPPORTS(struct exchange_info *exchange,char *base,char *rel,cJSON *argjson) +{ + char *baserels[][2] = { {"btc","usd"} }; + return(baserel_polarity(baserels,(int32_t)(sizeof(baserels)/sizeof(*baserels)),base,rel)); +} + +cJSON *SIGNPOST(void **cHandlep,int32_t dotrade,char **retstrp,struct exchange_info *exchange,char *method,char *payload) +{ + /*signature is a HMAC-SHA256 encoded message containing: nonce, customer ID (can be found here) and API key. The HMAC-SHA256 code must be generated using a secret key that was generated with your API key. This code must be converted to it's hexadecimal representation (64 uppercase characters).Example (Python): + message = nonce + customer_id + api_key + signature = hmac.new(API_SECRET, msg=message, digestmod=hashlib.sha256).hexdigest().upper() + + key - API key + signature - signature + nonce - nonce + */ + char dest[1025],url[1024],req[1024],hdr1[512],hdr2[512],hdr3[512],hdr4[512],*sig,*data = 0; + cJSON *json; uint64_t nonce; + hdr1[0] = hdr2[0] = hdr3[0] = hdr4[0] = 0; + nonce = exchange_nonce(exchange); + sprintf(req,"%llu%s%s",(long long)nonce,exchange->userid,exchange->apikey); + json = 0; + if ( (sig= hmac_sha256_str(dest,exchange->apisecret,(int32_t)strlen(exchange->apisecret),req)) != 0 ) + { + //touppercase(sig); + //printf("req.(%s) sig.(%s)\n",req,sig); + //sprintf(req,"{\"key\":\"%s\",\"signature\":\"%s\",\"nonce\":%llu%s}",exchange->apikey,sig,(long long)nonce,payload); + sprintf(req,"key=%s&signature=%s&nonce=%llu%s",exchange->apikey,sig,(long long)nonce,payload); + //printf("submit.(%s)\n",req); + sprintf(url,"%s/%s/",EXCHANGE_AUTHURL,method); + if ( dotrade == 0 ) + data = exchange_would_submit(req,hdr1,hdr2,hdr3,hdr4); + else if ( (data= curl_post(&exchange->cHandle,url,0,req,req,hdr2,hdr3,hdr4)) != 0 ) + json = cJSON_Parse(data); + } + if ( retstrp != 0 ) + *retstrp = data; + else if ( data != 0 ) + free(data); + return(json); +} + +char *PARSEBALANCE(struct exchange_info *exchange,double *balancep,char *coinstr,cJSON *argjson) +{ + char field[128],*itemstr = 0; cJSON *obj,*item; + *balancep = 0.; + strcpy(field,coinstr); + tolowercase(field); + if ( argjson != 0 && (obj= jobj(argjson,"return")) != 0 && (item= jobj(obj,"funds")) != 0 ) + { + *balancep = jdouble(item,field); + obj = cJSON_CreateObject(); + touppercase(field); + jaddstr(obj,"base",field); + jaddnum(obj,"balance",*balancep); + itemstr = jprint(obj,1); + } + if ( itemstr == 0 ) + return(clonestr("{\"error\":\"cant find coin balance\"}")); + return(itemstr); +} + +cJSON *BALANCES(struct exchange_info *exchange,cJSON *argjson) +{ + return(SIGNPOST(&exchange->cHandle,1,0,exchange,"balance","")); +} + +#include "checkbalance.c" + +uint64_t TRADE(int32_t dotrade,char **retstrp,struct exchange_info *exchange,char *base,char *rel,int32_t dir,double price,double volume,cJSON *argjson) +{ + char payload[1024],url[512],pairstr[512],*extra; cJSON *json; uint64_t txid = 0; + if ( (extra= *retstrp) != 0 ) + *retstrp = 0; + if ( (dir= flipstr_for_exchange(exchange,pairstr,"%s%s",dir,&price,&volume,base,rel,argjson)) == 0 ) + { + printf("cant find baserel (%s/%s)\n",base,rel); + return(0); + } + sprintf(url,"%s/%s/",EXCHANGE_AUTHURL,dir>0 ? "buy" : "sell"); + if ( CHECKBALANCE(retstrp,dotrade,exchange,dir,base,rel,price,volume,argjson) == 0 && (json= SIGNPOST(&exchange->cHandle,dotrade,retstrp,exchange,url,payload)) != 0 ) + { + // parse json and set txid + free_json(json); + } + return(txid); +} + +char *ORDERSTATUS(struct exchange_info *exchange,uint64_t quoteid,cJSON *argjson) +{ + char jsonbuf[128]; + sprintf(jsonbuf,"&id=%llu",(long long)quoteid); + return(jprint(SIGNPOST(&exchange->cHandle,1,0,exchange,"order_status",jsonbuf),1)); +} + +char *CANCELORDER(struct exchange_info *exchange,uint64_t quoteid,cJSON *argjson) +{ + char jsonbuf[128]; + sprintf(jsonbuf,"&id=%llu",(long long)quoteid); + return(jprint(SIGNPOST(&exchange->cHandle,1,0,exchange,"cancel_order",jsonbuf),1)); +} + +char *OPENORDERS(struct exchange_info *exchange,cJSON *argjson) +{ + return(jprint(SIGNPOST(&exchange->cHandle,1,0,exchange,"open_orders",""),1)); +} + +char *TRADEHISTORY(struct exchange_info *exchange,cJSON *argjson) +{ + return(jprint(SIGNPOST(&exchange->cHandle,1,0,exchange,"user_transactions",""),1)); +} + +char *WITHDRAW(struct exchange_info *exchange,char *base,double amount,char *destaddr,cJSON *argjson) +{ + return(clonestr("{\"error\":\"withdraw not yet\"}")); +} + +struct exchange_funcs bitstamp_funcs = EXCHANGE_FUNCS(bitstamp,EXCHANGE_NAME); + +#undef UPDATE +#undef SUPPORTS +#undef SIGNPOST +#undef TRADE +#undef ORDERSTATUS +#undef CANCELORDER +#undef OPENORDERS +#undef TRADEHISTORY +#undef BALANCES +#undef PARSEBALANCE +#undef WITHDRAW +#undef EXCHANGE_NAME +#undef EXCHANGE_AUTHURL +#undef CHECKBALANCE diff --git a/iguana/exchanges/bittrex.c b/iguana/exchanges/bittrex.c new file mode 100755 index 000000000..a7cf592d2 --- /dev/null +++ b/iguana/exchanges/bittrex.c @@ -0,0 +1,245 @@ +/****************************************************************************** + * Copyright © 2014-2016 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. * + * * + ******************************************************************************/ + +#define EXCHANGE_NAME "bittrex" +#define UPDATE bittrex ## _price +#define SUPPORTS bittrex ## _supports +#define SIGNPOST bittrex ## _signpost +#define TRADE bittrex ## _trade +#define ORDERSTATUS bittrex ## _orderstatus +#define CANCELORDER bittrex ## _cancelorder +#define OPENORDERS bittrex ## _openorders +#define TRADEHISTORY bittrex ## _tradehistory +#define BALANCES bittrex ## _balances +#define PARSEBALANCE bittrex ## _parsebalance +#define WITHDRAW bittrex ## _withdraw +#define CHECKBALANCE bittrex ## _checkbalance + +double UPDATE(struct exchange_info *exchange,char *base,char *rel,struct exchange_quote *quotes,int32_t maxdepth,cJSON *argjson) +{ + cJSON *json,*obj; char *jsonstr,market[128],url[1024]; double hbla = 0.; + sprintf(market,"%s-%s",rel,base); + sprintf(url,"https://bittrex.com/api/v1.1/public/getorderbook?market=%s&type=both&depth=%d",market,maxdepth); + jsonstr = issue_curl(url); + if ( jsonstr != 0 ) + { + if ( (json = cJSON_Parse(jsonstr)) != 0 ) + { + if ( (obj= cJSON_GetObjectItem(json,"success")) != 0 && is_cJSON_True(obj) != 0 ) + hbla = exchanges777_json_orderbook(exchange,base,rel,quotes,maxdepth,json,"result","buy","sell","Rate","Quantity"); + free_json(json); + } + free(jsonstr); + } + return(hbla); +} + +int32_t SUPPORTS(struct exchange_info *exchange,char *base,char *rel,cJSON *argjson) +{ + if ( strlen(base) > 5 || strlen(rel) > 5 || strcmp(rel,"CNY") == 0 || strcmp(base,"CNY") == 0 || strcmp(rel,"USD") == 0 || strcmp(base,"USD") == 0 ) + return(0); + if ( strcmp(rel,"BTC") == 0 ) + return(1); + else if ( strcmp(base,"BTC") == 0 ) + return(-1); + else return(0); +} + +cJSON *SIGNPOST(void **cHandlep,int32_t dotrade,char **retstrp,struct exchange_info *exchange,char *url,char *payload) +{ + char dest[(512>>3)*2+1],hdr1[512],hdr2[512],hdr3[512],hdr4[512],*data,*sig; cJSON *json; + hdr1[0] = hdr2[0] = hdr3[0] = hdr4[0] = 0; + json = 0; + if ( (sig= hmac_sha512_str(dest,exchange->apisecret,(int32_t)strlen(exchange->apisecret),payload)) != 0 ) + sprintf(hdr1,"apisign:%s",sig); + if ( dotrade == 0 ) + data = exchange_would_submit(payload,hdr1,hdr2,hdr3,hdr4); + else if ( (data= curl_post(&exchange->cHandle,url,0,payload,hdr1,hdr2,hdr3,hdr4)) != 0 ) + json = cJSON_Parse(data); + if ( retstrp != 0 ) + *retstrp = data; + else if ( data != 0 ) + free(data); + return(json); +} + +cJSON *BALANCES(struct exchange_info *exchange,cJSON *argjson) +{ + char payload[1024]; + sprintf(payload,"https://bittrex.com/api/v1.1/account/getbalances?apikey=%s&nonce=%llu",exchange->apikey,(long long)exchange_nonce(exchange)); + return(SIGNPOST(&exchange->cHandle,1,0,exchange,payload,payload)); +} + +char *PARSEBALANCE(struct exchange_info *exchange,double *balancep,char *coinstr,cJSON *argjson) +{ + int32_t i,n; char *str,*itemstr = 0; cJSON *item,*array,*obj; double total,pending; + *balancep = 0.; + if ( argjson != 0 && (array= jarray(&n,argjson,"result")) != 0 ) + { + for (i=0; i0?"buy":"sell",exchange->apikey,(long long)exchange_nonce(exchange),pairstr,price,volume); + if ( CHECKBALANCE(retstrp,dotrade,exchange,dir,base,rel,price,volume,argjson) == 0 && (json= SIGNPOST(&exchange->cHandle,dotrade,retstrp,exchange,payload,payload)) != 0 ) + { + if ( is_cJSON_True(cJSON_GetObjectItem(json,"success")) != 0 && (resultobj= cJSON_GetObjectItem(json,"result")) != 0 ) + { + copy_cJSON(&uuidstr,cJSON_GetObjectItem(resultobj,"uuid")); + for (i=j=0; uuidstr.buf[i]!=0; i++) + if ( uuidstr.buf[i] != '-' ) + uuidstr.buf[j++] = uuidstr.buf[i]; + uuidstr.buf[j] = 0; + n = (int32_t)strlen(uuidstr.buf); + printf("-> uuidstr.(%s).%d\n",uuidstr.buf,n); + decode_hex(databuf,n/2,uuidstr.buf); + if ( n >= 16 ) + for (i=0; i<8; i++) + databuf[i] ^= databuf[8 + i]; + memcpy(&txid,databuf,8); + printf("-> %llx\n",(long long)txid); + } + free_json(json); + } + return(txid); +} + +char *ORDERSTATUS(struct exchange_info *exchange,uint64_t quoteid,cJSON *argjson) +{ + char payload[1024],*retstr = 0; cJSON *json; + sprintf(payload,"https://bittrex.com/api/v1.1/account/getorder?apikey=%s&nonce=%llu&uuid=%llu",exchange->apikey,(long long)exchange_nonce(exchange),(long long)quoteid); + if ( (json= SIGNPOST(&exchange->cHandle,1,&retstr,exchange,payload,payload)) != 0 ) + { + free_json(json); + } + return(retstr); // return standardized orderstatus +} + +char *CANCELORDER(struct exchange_info *exchange,uint64_t quoteid,cJSON *argjson) +{ + char payload[1024],*retstr = 0; cJSON *json; + sprintf(payload,"https://bittrex.com/api/v1.1/market/cancel?apikey=%s&nonce=%llu&uuid=%llu",exchange->apikey,(long long)exchange_nonce(exchange),(long long)quoteid); + if ( (json= SIGNPOST(&exchange->cHandle,1,&retstr,exchange,payload,payload)) != 0 ) + { + free_json(json); + } + return(retstr); // return standardized cancelorder +} + +char *OPENORDERS(struct exchange_info *exchange,cJSON *argjson) +{ + char payload[1024],market[64],*base,*rel,*retstr = 0; cJSON *json; + sprintf(payload,"https://bittrex.com/api/v1.1/market/getopenorders?apikey=%s&nonce=%llu",exchange->apikey,(long long)exchange_nonce(exchange)); + if ( (base= jstr(argjson,"base")) != 0 && (rel= jstr(argjson,"rel")) != 0 ) + { + sprintf(market,"%s-%s",rel,base); + sprintf(payload + strlen(payload),"&market=%s",market); + } + if ( (json= SIGNPOST(&exchange->cHandle,1,&retstr,exchange,payload,payload)) != 0 ) + { + free_json(json); + } + return(retstr); // return standardized open orders +} + +char *TRADEHISTORY(struct exchange_info *exchange,cJSON *argjson) +{ + char payload[1024],market[64],*base,*rel,*retstr = 0; cJSON *json; + sprintf(payload,"https://bittrex.com/api/v1.1/account/getorderhistory?apikey=%s&nonce=%llu",exchange->apikey,(long long)exchange_nonce(exchange)); + if ( (base= jstr(argjson,"base")) != 0 && (rel= jstr(argjson,"rel")) != 0 ) + { + sprintf(market,"%s-%s",rel,base); + sprintf(payload + strlen(payload),"&market=%s",market); + } + if ( (json= SIGNPOST(&exchange->cHandle,1,&retstr,exchange,payload,payload)) != 0 ) + { + free_json(json); + } + return(retstr); // return standardized tradehistory +} + +char *WITHDRAW(struct exchange_info *exchange,char *base,double amount,char *destaddr,cJSON *argjson) +{ + char payload[1024],*paymentid,*retstr = 0; cJSON *json; + if ( base == 0 || base[0] == 0 ) + return(clonestr("{\"error\":\"base not specified\"}")); + if ( destaddr == 0 || destaddr[0] == 0 ) + return(clonestr("{\"error\":\"destaddr not specified\"}")); + if ( amount < SMALLVAL ) + return(clonestr("{\"error\":\"amount not specified\"}")); + paymentid = jstr(argjson,"paymentid"); + sprintf(payload,"https://bittrex.com/api/v1.1/account/withdraw?apikey=%s&nonce=%llu¤cy=%s&amount=%.4f&address=%s",exchange->apikey,(long long)exchange_nonce(exchange),base,amount,destaddr); + if ( paymentid != 0 ) + sprintf(payload + strlen(payload),"&paymentid=%s",paymentid); + if ( (json= SIGNPOST(&exchange->cHandle,1,&retstr,exchange,payload,payload)) != 0 ) + { + free_json(json); + } + return(retstr); // return standardized withdraw +} + +struct exchange_funcs bittrex_funcs = EXCHANGE_FUNCS(bittrex,EXCHANGE_NAME); + +#undef UPDATE +#undef SUPPORTS +#undef SIGNPOST +#undef TRADE +#undef ORDERSTATUS +#undef CANCELORDER +#undef OPENORDERS +#undef TRADEHISTORY +#undef BALANCES +#undef PARSEBALANCE +#undef WITHDRAW +#undef EXCHANGE_NAME +#undef CHECKBALANCE diff --git a/iguana/exchanges/btc38.c b/iguana/exchanges/btc38.c new file mode 100755 index 000000000..d2d82082e --- /dev/null +++ b/iguana/exchanges/btc38.c @@ -0,0 +1,321 @@ +/****************************************************************************** + * Copyright © 2014-2016 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. * + * * + ******************************************************************************/ + +#define EXCHANGE_NAME "btc38" +#define UPDATE btc38 ## _price +#define SUPPORTS btc38 ## _supports +#define SIGNPOST btc38 ## _signpost +#define TRADE btc38 ## _trade +#define ORDERSTATUS btc38 ## _orderstatus +#define CANCELORDER btc38 ## _cancelorder +#define OPENORDERS btc38 ## _openorders +#define TRADEHISTORY btc38 ## _tradehistory +#define BALANCES btc38 ## _balances +#define PARSEBALANCE btc38 ## _parsebalance +#define WITHDRAW btc38 ## _withdraw +#define EXCHANGE_AUTHURL "http://www.btc38.com/trade/t_api" +#define CHECKBALANCE btc38 ## _checkbalance + +double UPDATE(struct exchange_info *exchange,char *base,char *rel,struct exchange_quote *quotes,int32_t maxdepth,cJSON *argjson) +{ + char url[1024],lrel[16],lbase[16]; + strcpy(lrel,rel), strcpy(lbase,base); + tolowercase(lrel), tolowercase(lbase); + if ( strcmp(lbase,"cny") == 0 && strcmp(lrel,"btc") == 0 ) + sprintf(url,"http://api.btc38.com/v1/depth.php?c=%s&mk_type=%s","btc","cny"); + else sprintf(url,"http://api.btc38.com/v1/depth.php?c=%s&mk_type=%s",lbase,lrel); + return(exchanges777_standardprices(exchange,base,rel,url,quotes,0,0,maxdepth,0)); +} + +int32_t SUPPORTS(struct exchange_info *exchange,char *_base,char *_rel,cJSON *argjson) +{ + char *cnypairs[] = { "BTC", "LTC", "DOGE", "XRP", "BTS", "STR", "NXT", "BLK", "BC", "VPN", "BILS", "BOST", "PPC", "APC", "ZCC", "XPM", "DGC", "MEC", "WDC", "QRK", "BEC", "ANC", "UNC", "RIC", "SRC", "TAG" }; + char *btcpairs[] = { "TMC", "LTC", "DOGE", "XRP", "BTS", "XEM", "VPN", "XCN", "VOOT", "SYS", "NRS", "NAS", "SYNC", "MED", "EAC" }; + int32_t i; char base[64],rel[64]; + strcpy(base,_base), strcpy(rel,_rel); + touppercase(base), touppercase(rel); + if ( strlen(base) > 5 || strlen(rel) > 5 ) + return(0); + if ( strcmp(base,"BTC") == 0 && strcmp(rel,"CNY") == 0 ) + return(1); + else if ( strcmp(base,"CNY") == 0 && strcmp(rel,"BTC") == 0 ) + return(-1); + else if ( strcmp(base,"BTC") == 0 ) + { + for (i=0; iapikey,exchange->userid,exchange->apisecret,(long long)nonce); + //printf("MD5.(%s)\n",buf); + calc_md5(digest,buf,(int32_t)strlen(buf)); + sprintf(cmdbuf,"key=%s&time=%llu&md5=%s%s",exchange->apikey,(long long)nonce,digest,payload); + sprintf(url,"%s/%s",EXCHANGE_AUTHURL,path); + if ( dotrade == 0 ) + data = exchange_would_submit(payload,hdr1,hdr2,hdr3,hdr4); + else if ( (data= curl_post(&exchange->cHandle,url,0,cmdbuf,hdr1,hdr2,hdr3,hdr4)) != 0 ) + json = cJSON_Parse(data); + if ( retstrp != 0 ) + *retstrp = data; + else if ( data != 0 ) + free(data); + return(json); +} + +/* $ Stamp = $ date-> getTimestamp (); + type, 1 for the purchase of Entry, 2 entry order to sell, can not be empty / the type of the order + + $ Mdt = "_ public here to write here write here to write user ID_ private _" $ stamp.; + $ Mdt = md5 ($ mdt); + + $ Data = array ("key" => "here to write public", "time" => $ stamp, "md5" => $ mdt, "type" => 1, "mk_type" => "cny", + "Price" => "0.0001", "amount" => "100", "coinname" => "XRP"); + // $ Data_string = json_encode ($ data); + $ Ch = curl_init (); + curl_setopt ($ ch, CURLOPT_URL, 'http://www.btc38.com/trade/t_api/submitOrder.php'); + curl_setopt ($ ch, CURLOPT_POST, 1); + curl_setopt ($ ch, CURLOPT_POSTFIELDS, $ data); + curl_setopt ($ ch, CURLOPT_RETURNTRANSFER, 1); + curl_setopt ($ ch, CURLOPT_HEADER, 0); */ +/* +static CURL *cHandle; +char *data,*path,url[1024],cmdbuf[8192],buf[512],digest[33],market[16],base[64],rel[64],coinname[16],fmtstr[512],*pricefmt,*volfmt = "%.3f"; +cJSON *json,*resultobj; uint64_t nonce,txid = 0; +if ( _base != 0 && _rel != 0 ) +{ + strcpy(base,_base), strcpy(rel,_rel); + touppercase(base), touppercase(rel); + if ( btc38_supports(base,rel) == 0 ) + { + *retstrp = clonestr("{\"error\":\"invalid contract pair\"}"); + return(0); + } +} +nonce = exchange_nonce(exchange); +sprintf(buf,"%s_%s_%s_%llu",exchange->apikey,exchange->userid,exchange->apisecret,(long long)nonce); +//printf("MD5.(%s)\n",buf); +calc_md5(digest,buf,(int32_t)strlen(buf)); +*retstrp = 0; +if ( dir == 0 ) +{ + path = "getMyBalance.php"; + sprintf(cmdbuf,"key=%s&time=%llu&md5=%s",exchange->apikey,(long long)nonce,digest); +} +else +{ +if ( (data= curl_post(&cHandle,url,0,cmdbuf,0,0,0,0)) != 0 ) +{ + //printf("submit cmd.(%s) [%s]\n",cmdbuf,data); + if ( (json= cJSON_Parse(data)) != 0 ) + { + if ( juint(json,"success") > 0 && (resultobj= cJSON_GetObjectItem(json,"return")) != 0 ) + { + if ( (txid= get_API_nxt64bits(cJSON_GetObjectItem(resultobj,"order_id"))) == 0 ) + { + if ( get_API_nxt64bits(cJSON_GetObjectItem(resultobj,"remains")) == 0 ) + txid = _crc32(0,cmdbuf,strlen(cmdbuf)); + } + } + free_json(json); + } +} else fprintf(stderr,"submit err cmd.(%s)\n",cmdbuf); +if ( retstrp != 0 && data != 0 ) +{ + if ( (json= cJSON_Parse(data)) == 0 ) + { + json = cJSON_CreateObject(); + jaddstr(json,"result",data); + data = jprint(json,1); + } else free_json(json); + //printf("btc38 returning.(%s) in %p\n",data,data); + *retstrp = data; + } +else if ( data != 0 ) +free(data); +return(txid); +*/ + +cJSON *BALANCES(struct exchange_info *exchange,cJSON *argjson) +{ + return(SIGNPOST(&exchange->cHandle,1,0,exchange,"","getMyBalance.php")); +} + +char *PARSEBALANCE(struct exchange_info *exchange,double *balancep,char *coinstr,cJSON *argjson) +{ + char field[128],*str,*itemstr = 0; cJSON *obj; double lockbalance,imma; + *balancep = 0.; + strcpy(field,coinstr); + tolowercase(field); + strcat(field,"_balance"); + if ( argjson != 0 && (str= jstr(argjson,field)) != 0 ) + { + *balancep = jdouble(argjson,field); + strcpy(field,coinstr), tolowercase(field), strcat(field,"_balance_lock"); + lockbalance = jdouble(argjson,field); + strcpy(field,coinstr), tolowercase(field), strcat(field,"_balance_imma"); + imma = jdouble(argjson,field); + obj = cJSON_CreateObject(); + jaddnum(obj,"balance",*balancep); + jaddnum(obj,"locked_balance",lockbalance); + jaddnum(obj,"imma_balance",imma); + itemstr = jprint(obj,1); + } + if ( itemstr == 0 ) + return(clonestr("{\"error\":\"cant find coin balance\"}")); + return(itemstr); +} + +#include "checkbalance.c" + +uint64_t TRADE(int32_t dotrade,char **retstrp,struct exchange_info *exchange,char *base,char *rel,int32_t dir,double price,double volume,cJSON *argjson) +{ + char payload[1024],market[16],coinname[16],fmtstr[512],*pricefmt,*extra,*volfmt = "%.3f"; + cJSON *json,*resultobj; uint64_t txid = 0; + if ( (extra= *retstrp) != 0 ) + *retstrp = 0; + if ( (dir= cny_flip(market,coinname,base,rel,dir,&price,&volume)) == 0 ) + { + fprintf(stderr,"btc38_trade illegal base.(%s) or rel.(%s)\n",base,rel); + return(0); + } + if ( strcmp(market,"cny") == 0 ) + pricefmt = "%.5f"; + else pricefmt = "%.6f"; + //sprintf(fmtstr,"key=%%s&time=%%llu&md5=%%s&type=%%s&mk_type=%%s&coinname=%%s&price=%s&amount=%s",pricefmt,volfmt); + //sprintf(payload,fmtstr,exchange->apikey,(long long)nonce,digest,dir>0?"1":"2",market,coinname,price,volume); + sprintf(fmtstr,"&type=%%s&mk_type=%%s&coinname=%%s&price=%s&amount=%s",pricefmt,volfmt); + sprintf(payload,fmtstr,dir>0?"1":"2",market,coinname,price,volume); + if ( CHECKBALANCE(retstrp,dotrade,exchange,dir,base,rel,price,volume,argjson) == 0 && (json= SIGNPOST(&exchange->cHandle,dotrade,retstrp,exchange,payload,"submitOrder.php")) != 0 ) + { + if ( juint(json,"success") > 0 && (resultobj= jobj(json,"return")) != 0 ) + { + if ( (txid= j64bits(resultobj,"order_id")) == 0 ) + { + if ( j64bits(resultobj,"remains") == 0 ) + txid = calc_crc32(0,payload,strlen(payload)); + } + } + free_json(json); + if ( retstrp != 0 && *retstrp != 0 ) + { + if ( (json= cJSON_Parse(*retstrp)) == 0 ) + { + json = cJSON_CreateObject(); + jaddstr(json,"result",*retstrp); + free(*retstrp); + *retstrp = jprint(json,1); + } else free_json(json); + } + } + return(txid); +} + +char *CANCELORDER(struct exchange_info *exchange,uint64_t quoteid,cJSON *argjson) +{ + char payload[1024],*rel,*retstr = 0; cJSON *json; + if ( (rel= jstr(argjson,"rel")) == 0 ) + rel = "cny"; + sprintf(payload,"&mk_type=%s&order_id=%llu",rel,(long long)quoteid); + if ( (json= SIGNPOST(&exchange->cHandle,1,&retstr,exchange,payload,"cancelOrder.php")) != 0 ) + { + free_json(json); + } + return(retstr); // return standardized cancelorder +} + +char *OPENORDERS(struct exchange_info *exchange,cJSON *argjson) +{ + char payload[1024],*base,*rel,*retstr = 0; cJSON *json; + if ( (rel= jstr(argjson,"rel")) == 0 ) + rel = "cny"; + sprintf(payload,"&mk_type=%s",rel); + if ( (base= jstr(argjson,"base")) != 0 ) + sprintf(payload + strlen(payload),"&coinname=%s",base); + if ( (json= SIGNPOST(&exchange->cHandle,1,&retstr,exchange,payload,"getOrderList.php")) != 0 ) + { + free_json(json); + } + return(retstr); // return standardized open orders +} + +char *TRADEHISTORY(struct exchange_info *exchange,cJSON *argjson) +{ + return(clonestr("{\"error\":\"btc38 doesnt seem to have trade history api!\"}")); +} + +char *WITHDRAW(struct exchange_info *exchange,char *base,double amount,char *destaddr,cJSON *argjson) +{ + return(clonestr("{\"error\":\"btc38 doesnt seem to have withdraw api!\"}")); +} + +char *ORDERSTATUS(struct exchange_info *exchange,uint64_t quoteid,cJSON *argjson) +{ + char *status,*retstr; + status = OPENORDERS(exchange,argjson); + if ( (retstr= exchange_extractorderid(0,status,quoteid,"order_id")) != 0 ) + { + free(status); + return(retstr); + } + free(status); + return(clonestr("{\"result\":\"order not pending\"}")); +} + +struct exchange_funcs btc38_funcs = EXCHANGE_FUNCS(btc38,EXCHANGE_NAME); + +#undef UPDATE +#undef SUPPORTS +#undef SIGNPOST +#undef TRADE +#undef ORDERSTATUS +#undef CANCELORDER +#undef OPENORDERS +#undef TRADEHISTORY +#undef BALANCES +#undef PARSEBALANCE +#undef WITHDRAW +#undef EXCHANGE_NAME +#undef EXCHANGE_AUTHURL +#undef CHECKBALANCE + diff --git a/iguana/exchanges/btce.c b/iguana/exchanges/btce.c new file mode 100755 index 000000000..89a6223d9 --- /dev/null +++ b/iguana/exchanges/btce.c @@ -0,0 +1,216 @@ +/****************************************************************************** + * Copyright © 2014-2016 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. * + * * + ******************************************************************************/ + +#define EXCHANGE_NAME "btce" +#define UPDATE btce ## _price +#define SUPPORTS btce ## _supports +#define SIGNPOST btce ## _signpost +#define TRADE btce ## _trade +#define ORDERSTATUS btce ## _orderstatus +#define CANCELORDER btce ## _cancelorder +#define OPENORDERS btce ## _openorders +#define TRADEHISTORY btce ## _tradehistory +#define BALANCES btce ## _balances +#define PARSEBALANCE btce ## _parsebalance +#define WITHDRAW btce ## _withdraw +#define EXCHANGE_AUTHURL "https://btc-e.com/tapi" +#define CHECKBALANCE btce ## _checkbalance + +double UPDATE(struct exchange_info *exchange,char *base,char *rel,struct exchange_quote *quotes,int32_t maxdepth,cJSON *argjson) +{ + char field[64],url[1024],lbase[16],lrel[16]; + strcpy(lrel,rel), strcpy(lbase,base); + tolowercase(lrel), tolowercase(lbase); + sprintf(field,"%s_%s",lbase,lrel); + sprintf(url,"https://btc-e.com/api/3/depth/%s",field); + return(exchanges777_standardprices(exchange,base,rel,url,quotes,0,0,maxdepth,field)); +} + +int32_t SUPPORTS(struct exchange_info *exchange,char *base,char *rel,cJSON *argjson) +{ + char *baserels[][2] = { {"btc","usd"}, {"btc","rur"}, {"btc","eur"}, {"ltc","btc"}, {"ltc","usd"}, {"ltc","rur"}, {"ltc","eur"}, {"nmc","btc"}, {"nmc","usd"}, {"nvc","btc"}, {"nvc","usd"}, {"eur","usd"}, {"eur","rur"}, {"ppc","btc"}, {"ppc","usd"} }; + return(baserel_polarity(baserels,(int32_t)(sizeof(baserels)/sizeof(*baserels)),base,rel)); +} + +cJSON *SIGNPOST(void **cHandlep,int32_t dotrade,char **retstrp,struct exchange_info *exchange,char *url,char *payload) +{ + char dest[(512>>3)*2+1],hdr1[512],hdr2[512],hdr3[512],hdr4[512],*data,*sig; cJSON *json; + hdr1[0] = hdr2[0] = hdr3[0] = hdr4[0] = 0; + json = 0; + if ( (sig= hmac_sha512_str(dest,exchange->apisecret,(int32_t)strlen(exchange->apisecret),payload)) != 0 ) + sprintf(hdr1,"Sign:%s",sig); + else hdr1[0] = 0; + sprintf(hdr2,"Key:%s",exchange->apikey); + if ( dotrade == 0 ) + data = exchange_would_submit(payload,hdr1,hdr2,hdr3,hdr4); + else if ( (data= curl_post(&exchange->cHandle,url,0,payload,hdr1,hdr2,hdr3,hdr4)) != 0 ) + json = cJSON_Parse(data); + if ( retstrp != 0 ) + *retstrp = data; + else if ( data != 0 ) + free(data); + return(json); +} + +cJSON *BALANCES(struct exchange_info *exchange,cJSON *argjson) +{ + char payload[1024]; + sprintf(payload,"method=getInfo&nonce=%llu",(long long)exchange_nonce(exchange)); + return(SIGNPOST(&exchange->cHandle,1,0,exchange,EXCHANGE_AUTHURL,payload)); +} + +char *PARSEBALANCE(struct exchange_info *exchange,double *balancep,char *coinstr,cJSON *argjson) +{ + //btce.({"success":1,"return":{"funds":{"usd":73.02571846,"btc":0,"ltc":0,"nmc":0,"rur":0,"eur":0,"nvc":0.0000322,"trc":0,"ppc":0.00000002,"ftc":0,"xpm":2.28605349,"cnh":0,"gbp":0},"rights":{"info":1,"trade":1,"withdraw":0},"transaction_count":0,"open_orders":3,"server_time":1441918649}}) + char field[128],*itemstr = 0; cJSON *obj,*item; + *balancep = 0.; + strcpy(field,coinstr); + tolowercase(field); + if ( argjson != 0 && (obj= jobj(argjson,"return")) != 0 && (item= jobj(obj,"funds")) != 0 ) + { + *balancep = jdouble(item,field); + obj = cJSON_CreateObject(); + touppercase(field); + jaddstr(obj,"base",field); + jaddnum(obj,"balance",*balancep); + itemstr = jprint(obj,1); + } + if ( itemstr == 0 ) + return(clonestr("{\"error\":\"cant find coin balance\"}")); + return(itemstr); +} + +#include "checkbalance.c" + +uint64_t TRADE(int32_t dotrade,char **retstrp,struct exchange_info *exchange,char *base,char *rel,int32_t dir,double price,double volume,cJSON *argjson) +{ + char payload[1024],pairstr[512],*extra; cJSON *json,*resultobj; uint64_t txid = 0; + if ( (extra= *retstrp) != 0 ) + *retstrp = 0; + if ( (dir= flipstr_for_exchange(exchange,pairstr,"%s_%s",dir,&price,&volume,base,rel,argjson)) == 0 ) + { + printf("cant find baserel (%s/%s)\n",base,rel); + return(0); + } + sprintf(payload,"method=Trade&nonce=%llu&pair=%s&type=%s&rate=%.3f&amount=%.6f",(long long)exchange_nonce(exchange),pairstr,dir>0?"buy":"sell",price,volume); + if ( CHECKBALANCE(retstrp,dotrade,exchange,dir,base,rel,price,volume,argjson) == 0 && (json= SIGNPOST(&exchange->cHandle,dotrade,retstrp,exchange,EXCHANGE_AUTHURL,payload)) != 0 ) + { + //{ "success":1, "return":{ "received":0.1, "remains":0, "order_id":0, "funds":{ "usd":325, "btc":2.498, } } } + if ( juint(json,"success") > 0 && (resultobj= jobj(json,"return")) != 0 ) + { + if ( (txid= j64bits(resultobj,"order_id")) == 0 ) + { + if ( j64bits(resultobj,"remains") == 0 ) + txid = calc_crc32(0,payload,strlen(payload)); + } + } + free_json(json); + } + return(txid); +} + +char *ORDERSTATUS(struct exchange_info *exchange,uint64_t quoteid,cJSON *argjson) +{ + char payload[1024],*retstr = 0; cJSON *json; + sprintf(payload,"method=OrderInfo&nonce=%llu&order_id=%llu",(long long)exchange_nonce(exchange),(long long)quoteid); + if ( (json= SIGNPOST(&exchange->cHandle,1,&retstr,exchange,EXCHANGE_AUTHURL,payload)) != 0 ) + { + free_json(json); + } + return(retstr); // return standardized orderstatus +} + +char *CANCELORDER(struct exchange_info *exchange,uint64_t quoteid,cJSON *argjson) +{ + char payload[1024],*retstr = 0; cJSON *json; + sprintf(payload,"method=CancelOrder&nonce=%llu&order_id=%llu",(long long)exchange_nonce(exchange),(long long)quoteid); + if ( (json= SIGNPOST(&exchange->cHandle,1,&retstr,exchange,EXCHANGE_AUTHURL,payload)) != 0 ) + { + free_json(json); + } + return(retstr); // return standardized cancelorder +} + +char *OPENORDERS(struct exchange_info *exchange,cJSON *argjson) +{ + char payload[1024],market[64],*base,*rel,*retstr = 0; cJSON *json; + sprintf(payload,"method=ActiveOrders&nonce=%llu",(long long)exchange_nonce(exchange)); + if ( (base= jstr(argjson,"base")) != 0 && (rel= jstr(argjson,"rel")) != 0 ) + { + sprintf(market,"%s_%s",base,rel); + tolowercase(market); + sprintf(payload + strlen(payload),"&pair=%s",market); + } + if ( (json= SIGNPOST(&exchange->cHandle,1,&retstr,exchange,EXCHANGE_AUTHURL,payload)) != 0 ) + { + free_json(json); + } + return(retstr); // return standardized open orders +} + +char *TRADEHISTORY(struct exchange_info *exchange,cJSON *argjson) +{ + char payload[1024],market[64],*base,*rel,*retstr = 0; cJSON *json; uint32_t starttime,endtime; + sprintf(payload,"method=TradeHistory&nonce=%llu",(long long)exchange_nonce(exchange)); + if ( (starttime= juint(argjson,"start")) != 0 ) + sprintf(payload + strlen(payload),"&since=%u",starttime); + if ( (endtime= juint(argjson,"end")) != 0 ) + sprintf(payload + strlen(payload),"&end=%u",endtime); + if ( (base= jstr(argjson,"base")) != 0 && (rel= jstr(argjson,"rel")) != 0 ) + { + sprintf(market,"%s_%s",base,rel); + tolowercase(market); + sprintf(payload + strlen(payload),"&pair=%s",market); + } + if ( (json= SIGNPOST(&exchange->cHandle,1,&retstr,exchange,EXCHANGE_AUTHURL,payload)) != 0 ) + { + free_json(json); + } + return(retstr); // return standardized tradehistory +} + +char *WITHDRAW(struct exchange_info *exchange,char *base,double amount,char *destaddr,cJSON *argjson) +{ + char payload[1024],*retstr = 0; cJSON *json; + if ( base == 0 || base[0] == 0 ) + return(clonestr("{\"error\":\"base not specified\"}")); + if ( destaddr == 0 || destaddr[0] == 0 ) + return(clonestr("{\"error\":\"destaddr not specified\"}")); + if ( amount < SMALLVAL ) + return(clonestr("{\"error\":\"amount not specified\"}")); + sprintf(payload,"method=WithdrawCoin&nonce=%llu&coinName=%s&amount=%.6f&address=%s",(long long)exchange_nonce(exchange),base,amount,destaddr); + if ( (json= SIGNPOST(&exchange->cHandle,1,&retstr,exchange,EXCHANGE_AUTHURL,payload)) != 0 ) + { + free_json(json); + } + return(retstr); // return standardized withdraw +} + +struct exchange_funcs btce_funcs = EXCHANGE_FUNCS(btce,EXCHANGE_NAME); + +#undef UPDATE +#undef SUPPORTS +#undef SIGNPOST +#undef TRADE +#undef ORDERSTATUS +#undef CANCELORDER +#undef OPENORDERS +#undef TRADEHISTORY +#undef BALANCES +#undef PARSEBALANCE +#undef WITHDRAW +#undef EXCHANGE_NAME +#undef EXCHANGE_AUTHURL +#undef CHECKBALANCE diff --git a/iguana/exchanges/checkbalance.c b/iguana/exchanges/checkbalance.c new file mode 100755 index 000000000..2fbd91267 --- /dev/null +++ b/iguana/exchanges/checkbalance.c @@ -0,0 +1,53 @@ +/****************************************************************************** + * 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. * + * * + ******************************************************************************/ + +int32_t CHECKBALANCE(char **retstrp,int32_t skipflag,struct exchange_info *exchange,int32_t dir,char *base,char *rel,double price,double volume,cJSON *argjson) +{ + cJSON *json; char *coinstr,*balancestr,*resultstr,*resultval; double balance; int32_t retval = -1; + if ( skipflag == 0 ) + { + coinstr = (dir > 0) ? rel : base; + if ( (balancestr= PARSEBALANCE(exchange,&balance,coinstr,argjson)) != 0 ) + { + json = cJSON_Parse(balancestr); + free(balancestr); + printf("%s balance.%s %f vs %f\n",exchange->name,coinstr,balance,dir > 0 ? volume : volume * price); + if ( (dir > 0 && balance < volume) || (dir < 0 && balance < (volume * price)) ) + { + resultstr = "error"; + resultval = "not enough balance"; + } + else + { + resultval = "balance"; + resultstr = "success"; + retval = 0; + } + if ( retstrp != 0 ) + { + if ( json == 0 ) + json = cJSON_CreateObject(); + jaddstr(json,"coin",coinstr); + jaddnum(json,"balance",balance); + jaddnum(json,"required",volume * (dir < 0 ? price : 1.)); + jaddstr(json,resultstr,resultval); + *retstrp = jprint(json,1); + } + else if ( json != 0 ) + free_json(json); + } + } else retval = 0; + return(retval); +} diff --git a/iguana/exchanges/coinbase.c b/iguana/exchanges/coinbase.c new file mode 100755 index 000000000..2f77a6dc1 --- /dev/null +++ b/iguana/exchanges/coinbase.c @@ -0,0 +1,229 @@ +/****************************************************************************** + * Copyright © 2014-2016 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. * + * * + ******************************************************************************/ + +#define EXCHANGE_NAME "coinbase" +#define UPDATE coinbase ## _price +#define SUPPORTS coinbase ## _supports +#define SIGNPOST coinbase ## _signpost +#define TRADE coinbase ## _trade +#define ORDERSTATUS coinbase ## _orderstatus +#define CANCELORDER coinbase ## _cancelorder +#define OPENORDERS coinbase ## _openorders +#define TRADEHISTORY coinbase ## _tradehistory +#define BALANCES coinbase ## _balances +#define PARSEBALANCE coinbase ## _parsebalance +#define WITHDRAW coinbase ## _withdraw +#define EXCHANGE_AUTHURL "https://api.exchange.coinbase.com" +#define CHECKBALANCE coinbase ## _checkbalance + +double UPDATE(struct exchange_info *exchange,char *base,char *rel,struct exchange_quote *quotes,int32_t maxdepth,cJSON *argjson) +{ + char url[1024]; + sprintf(url,"https://api.exchange.coinbase.com/products/%s-%s/book?level=2",base,rel); + return(exchanges777_standardprices(exchange,base,rel,url,quotes,0,0,maxdepth,0)); +} + +int32_t SUPPORTS(struct exchange_info *exchange,char *base,char *rel,cJSON *argjson) +{ + char *baserels[][2] = { {"btc","usd"} }; + return(baserel_polarity(baserels,(int32_t)(sizeof(baserels)/sizeof(*baserels)),base,rel)); +} + +cJSON *SIGNPOST(void **cHandlep,int32_t dotrade,char **retstrp,struct exchange_info *exchange,char *payload,uint64_t nonce,char *path,char *method) +{ + /*All REST requests must contain the following headers: + + CB-ACCESS-KEY The api key as a string. + CB-ACCESS-SIGN The base64-encoded signature (see Signing a Message). + CB-ACCESS-TIMESTAMP A timestamp for your request. + CB-ACCESS-PASSPHRASE The passphrase you specified when creating the API key. + All request bodies should have content type application/json and be valid JSON. + + Signing a Message + The CB-ACCESS-SIGN header is generated by creating a sha256 HMAC using the base64-decoded + secret key on the prehash string timestamp + method + requestPath + body (where + represents string concatenation) + and base64-encode the output. The timestamp value is the same as the CB-ACCESS-TIMESTAMP header. + + The body is the request body string or omitted if there is no request body (typically for GET requests). + + The method should be UPPER CASE + Remember to first base64-decode the alphanumeric secret string (resulting in 64 bytes) before using it as the key for HMAC. Also, base64-encode the digest output before sending in the header. + */ + /* def __call__(self, request): + timestamp = str(time.time()) + message = timestamp + request.method + request.path_url + (request.body or '') + hmac_key = base64.b64decode(self.secret_key) + signature = hmac.new(hmac_key, message, hashlib.sha256) + signature_b64 = signature.digest().encode('base64').rstrip('\n') + + request.headers.update({ + 'CB-ACCESS-SIGN': signature_b64, + 'CB-ACCESS-TIMESTAMP': timestamp, + 'CB-ACCESS-KEY': self.api_key, + 'CB-ACCESS-PASSPHRASE': self.passphrase, + 'Content-Type': 'application/json' + })*/ + char url[1024],hdr1[512],hdr2[512],hdr3[512],hdr4[512],dest[1024]; cJSON *json; int32_t n; + char prehash64[512],prehash[512],decodedsecret[512],sig64[512],*sig,*data = 0; + hdr1[0] = hdr2[0] = hdr3[0] = hdr4[0] = 0; + json = 0; + n = nn_base64_decode((void *)exchange->apisecret,strlen(exchange->apisecret),(void *)decodedsecret,sizeof(decodedsecret)); + sprintf(prehash,"%llu%s/%s%s",(long long)nonce,method,path,payload); + nn_base64_encode((void *)prehash,strlen(prehash),prehash64,sizeof(prehash64)); + if ( (sig= hmac_sha256_str(dest,decodedsecret,n,prehash64)) != 0 ) + { + nn_base64_encode((void *)sig,strlen(sig),sig64,sizeof(sig64)); + //CB-ACCESS-KEY The api key as a string. + //CB-ACCESS-SIGN The base64-encoded signature (see Signing a Message). + //CB-ACCESS-TIMESTAMP A timestamp for your request. + //CB-ACCESS-PASSPHRASE The passphrase you specified when creating the API key. + sprintf(hdr1,"CB-ACCESS-KEY:%s",exchange->apikey); + sprintf(hdr2,"CB-ACCESS-SIGN:%s",sig64); + sprintf(hdr3,"CB-ACCESS-TIMESTAMP:%llu",(long long)nonce); + //sprintf(hdr4,"CB-ACCESS-PASSPHRASE:%s; content-type:application/json; charset=utf-8",exchange->userid); + sprintf(hdr4,"CB-ACCESS-PASSPHRASE:%s",exchange->userid); + sprintf(url,"%s/%s",EXCHANGE_AUTHURL,path); + if ( dotrade == 0 ) + data = exchange_would_submit(payload,hdr1,hdr2,hdr3,hdr4); + else if ( (data= curl_post(&exchange->cHandle,url,0,payload,hdr1,hdr2,hdr3,hdr4)) != 0 ) + json = cJSON_Parse(data); + } + if ( retstrp != 0 ) + *retstrp = data; + else if ( data != 0 ) + free(data); + return(json); +} + +cJSON *BALANCES(struct exchange_info *exchange,cJSON *argjson) +{ + return(SIGNPOST(&exchange->cHandle,1,0,exchange,"",exchange_nonce(exchange),"accounts","GET")); +} + +char *PARSEBALANCE(struct exchange_info *exchange,double *balancep,char *coinstr,cJSON *argjson) +{ + char field[128],*itemstr = 0; cJSON *obj,*item; + *balancep = 0.; + strcpy(field,coinstr); + tolowercase(field); + if ( argjson != 0 && (obj= jobj(argjson,"return")) != 0 && (item= jobj(obj,"funds")) != 0 ) + { + *balancep = jdouble(item,field); + obj = cJSON_CreateObject(); + touppercase(field); + jaddstr(obj,"base",field); + jaddnum(obj,"balance",*balancep); + itemstr = jprint(obj,1); + } + if ( itemstr == 0 ) + return(clonestr("{\"error\":\"cant find coin balance\"}")); + return(itemstr); +} + +#include "checkbalance.c" + +uint64_t TRADE(int32_t dotrade,char **retstrp,struct exchange_info *exchange,char *base,char *rel,int32_t dir,double price,double volume,cJSON *argjson) +{ + char payload[1024],pairstr[512],method[32],*path,*extra; + cJSON *json; uint64_t nonce,txid = 0; + if ( (extra= *retstrp) != 0 ) + *retstrp = 0; + path = "trade", strcpy(method,"POST"); + if ( (dir= flip_for_exchange(pairstr,"%s_%s","BTC",dir,&price,&volume,base,rel)) == 0 ) + { + printf("cant find baserel (%s/%s)\n",base,rel); + return(0); + } + nonce = exchange_nonce(exchange); + sprintf(payload,"method=Trade&nonce=%llu&pair=%s&type=%s&rate=%.6f&amount=%.6f",(long long)nonce,pairstr,dir>0?"buy":"sell",price,volume); + if ( CHECKBALANCE(retstrp,dotrade,exchange,dir,base,rel,price,volume,argjson) == 0 && (json= SIGNPOST(&exchange->cHandle,dotrade,retstrp,exchange,payload,nonce,path,method)) != 0 ) + { + // parse json and set txid + free_json(json); + } + return(txid); +} + +char *ORDERSTATUS(struct exchange_info *exchange,uint64_t quoteid,cJSON *argjson) +{ + char payload[1024],*retstr = 0; cJSON *json; + // generate payload + if ( (json= SIGNPOST(&exchange->cHandle,1,0,exchange,payload,exchange_nonce(exchange),"accounts","GET")) != 0 ) + { + free_json(json); + } + return(retstr); // return standardized orderstatus +} + +char *CANCELORDER(struct exchange_info *exchange,uint64_t quoteid,cJSON *argjson) +{ + char payload[1024],*retstr = 0; cJSON *json; + // generate payload + if ( (json= SIGNPOST(&exchange->cHandle,1,0,exchange,payload,exchange_nonce(exchange),"accounts","GET")) != 0 ) + { + free_json(json); + } + return(retstr); // return standardized cancelorder +} + +char *OPENORDERS(struct exchange_info *exchange,cJSON *argjson) +{ + char payload[1024],*retstr = 0; cJSON *json; + // generate payload + if ( (json= SIGNPOST(&exchange->cHandle,1,0,exchange,payload,exchange_nonce(exchange),"accounts","GET")) != 0 ) + { + free_json(json); + } + return(retstr); // return standardized open orders +} + +char *TRADEHISTORY(struct exchange_info *exchange,cJSON *argjson) +{ + char payload[1024],*retstr = 0; cJSON *json; + // generate payload + if ( (json= SIGNPOST(&exchange->cHandle,1,0,exchange,payload,exchange_nonce(exchange),"accounts","GET")) != 0 ) + { + free_json(json); + } + return(retstr); // return standardized tradehistory +} + +char *WITHDRAW(struct exchange_info *exchange,char *base,double amount,char *destaddr,cJSON *argjson) +{ + char payload[1024],*retstr = 0; cJSON *json; + // generate payload + if ( (json= SIGNPOST(&exchange->cHandle,1,0,exchange,payload,exchange_nonce(exchange),"accounts","GET")) != 0 ) + { + free_json(json); + } + return(retstr); // return standardized withdraw +} + +struct exchange_funcs coinbase_funcs = EXCHANGE_FUNCS(coinbase,EXCHANGE_NAME); + +#undef UPDATE +#undef SUPPORTS +#undef SIGNPOST +#undef TRADE +#undef ORDERSTATUS +#undef CANCELORDER +#undef OPENORDERS +#undef TRADEHISTORY +#undef BALANCES +#undef PARSEBALANCE +#undef WITHDRAW +#undef EXCHANGE_NAME +#undef EXCHANGE_AUTHURL +#undef CHECKBALANCE diff --git a/iguana/exchanges/huobi.c b/iguana/exchanges/huobi.c new file mode 100755 index 000000000..ef1950f24 --- /dev/null +++ b/iguana/exchanges/huobi.c @@ -0,0 +1,184 @@ +/****************************************************************************** + * Copyright © 2014-2016 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. * + * * + ******************************************************************************/ + +#define EXCHANGE_NAME "huobi" +#define UPDATE huobi ## _price +#define SUPPORTS huobi ## _supports +#define SIGNPOST huobi ## _signpost +#define TRADE huobi ## _trade +#define ORDERSTATUS huobi ## _orderstatus +#define CANCELORDER huobi ## _cancelorder +#define OPENORDERS huobi ## _openorders +#define TRADEHISTORY huobi ## _tradehistory +#define BALANCES huobi ## _balances +#define PARSEBALANCE huobi ## _parsebalance +#define WITHDRAW huobi ## _withdraw +#define CHECKBALANCE huobi ## _checkbalance + +double UPDATE(struct exchange_info *exchange,char *base,char *rel,struct exchange_quote *quotes,int32_t maxdepth,cJSON *argjson) +{ + char url[1024],lbase[16]; + strcpy(lbase,base), tolowercase(lbase); + sprintf(url,"http://api.huobi.com/staticmarket/depth_%s_json.js ",lbase); + return(exchanges777_standardprices(exchange,base,rel,url,quotes,0,0,maxdepth,0)); +} + +int32_t SUPPORTS(struct exchange_info *exchange,char *base,char *rel,cJSON *argjson) +{ + char *baserels[][2] = { {"btc","cny"}, {"ltc","cny"} }; + return(baserel_polarity(baserels,(int32_t)(sizeof(baserels)/sizeof(*baserels)),base,rel)); +} + +cJSON *SIGNPOST(void **cHandlep,int32_t dotrade,char **retstrp,struct exchange_info *exchange,char *payload) +{ + char *data; cJSON *json; + json = 0; + //if ( (data= curl_post(&cHandle,"https://api.huobi.com/apiv3",0,payload,"Content-Type:application/x-www-form-urlencoded",0,0,0)) != 0 ) + if ( dotrade == 0 ) + data = exchange_would_submit(payload,"","","",""); + else if ( (data= curl_post(&exchange->cHandle,"https://api.huobi.com/apiv3",0,payload,"",0,0,0)) != 0 ) + json = cJSON_Parse(data); + if ( retstrp != 0 ) + *retstrp = data; + else if ( data != 0 ) + free(data); + return(json); +} + +cJSON *huobi_issue_auth(void **cHandlep,struct exchange_info *exchange,char *method,char *buf) +{ + char payload[1024],digest[33],tmp[1024]; uint64_t nonce; + nonce = exchange_nonce(exchange); + sprintf(tmp,"access_key=%s&created=%llu&method=%s%s",exchange->apikey,(long long)nonce,method,buf); + sprintf(payload,"%s&secret_key=%s",tmp,exchange->apisecret); + //printf("tmp.(%s) payload.(%s)\n",tmp,payload); + calc_md5(digest,payload,(int32_t)strlen(payload)); + sprintf(payload,"%s&sign=%s",tmp,digest); + //printf("-> (%s)\n",payload); + return(SIGNPOST(&exchange->cHandle,1,0,exchange,payload)); +} + +char *PARSEBALANCE(struct exchange_info *exchange,double *balancep,char *coinstr,cJSON *argjson) +{ + char field[128],*itemstr = 0; cJSON *obj,*item; + *balancep = 0.; + strcpy(field,coinstr); + tolowercase(field); + if ( argjson != 0 && (obj= jobj(argjson,"return")) != 0 && (item= jobj(obj,"funds")) != 0 ) + { + *balancep = jdouble(item,field); + obj = cJSON_CreateObject(); + touppercase(field); + jaddstr(obj,"base",field); + jaddnum(obj,"balance",*balancep); + itemstr = jprint(obj,1); + } + if ( itemstr == 0 ) + return(clonestr("{\"error\":\"cant find coin balance\"}")); + return(itemstr); +} + +cJSON *BALANCES(struct exchange_info *exchange,cJSON *argjson) +{ + return(huobi_issue_auth(&exchange->cHandle,exchange,"get_account_info","")); +} + +#include "checkbalance.c" + +uint64_t TRADE(int32_t dotrade,char **retstrp,struct exchange_info *exchange,char *base,char *rel,int32_t dir,double price,double volume,cJSON *argjson) +{ + char payload[1024],pairstr[64],pricestr[64],*extra,*method; cJSON *json; int32_t type; uint64_t txid = 0; + if ( (extra= *retstrp) != 0 ) + *retstrp = 0; + if ( (dir= flipstr_for_exchange(exchange,pairstr,"%s%s",dir,&price,&volume,base,rel,argjson)) == 0 ) + { + printf("cant find baserel (%s/%s)\n",base,rel); + return(0); + } + if ( extra != 0 && strcmp(extra,"market") == 0 ) + method = (dir > 0) ? "buy_market" : "sell_market"; + else method = (dir > 0) ? "buy" : "sell", sprintf(pricestr,"&price=%.2f",price); + if ( strcmp(pairstr,"btccny") == 0 ) + type = 1; + else if ( strcmp(pairstr,"ltccny") == 0 ) + type = 2; + else + { + printf("cant find baserel (%s/%s)\n",base,rel); + return(0); + } + sprintf(payload,"&amount=%.4f&coin_type=%d%s",volume,type,pricestr); + if ( CHECKBALANCE(retstrp,dotrade,exchange,dir,base,rel,price,volume,argjson) == 0 && (json= huobi_issue_auth(&exchange->cHandle,exchange,method,payload)) != 0 ) + { + txid = j64bits(json,"order_id"); + free_json(json); + } + return(txid); +} + +char *ORDERSTATUS(struct exchange_info *exchange,uint64_t quoteid,cJSON *argjson) +{ + char payload[1024]; + sprintf(payload,"&id=%llu&coin_type=1",(long long)quoteid); + return(jprint(huobi_issue_auth(&exchange->cHandle,exchange,"order_info",payload),1)); +} + +char *CANCELORDER(struct exchange_info *exchange,uint64_t quoteid,cJSON *argjson) +{ + char payload[1024]; + sprintf(payload,"&id=%llu&coin_type=1",(long long)quoteid); + return(jprint(huobi_issue_auth(&exchange->cHandle,exchange,"cancel_order",payload),1)); +} + +char *OPENORDERS(struct exchange_info *exchange,cJSON *argjson) +{ + return(jprint(huobi_issue_auth(&exchange->cHandle,exchange,"get_orders","&coin_type=1"),1)); +} + +char *TRADEHISTORY(struct exchange_info *exchange,cJSON *argjson) +{ + return(clonestr("{\"error\":\"huobi doesnt seem to have trade history api!\"}")); +} + +char *WITHDRAW(struct exchange_info *exchange,char *base,double amount,char *destaddr,cJSON *argjson) +{ + char payload[1024],*method; + if ( base == 0 || base[0] == 0 ) + return(clonestr("{\"error\":\"base not specified\"}")); + if ( destaddr == 0 || destaddr[0] == 0 ) + return(clonestr("{\"error\":\"destaddr not specified\"}")); + if ( amount < SMALLVAL ) + return(clonestr("{\"error\":\"amount not specified\"}")); + method = "withdraw_coin"; + sprintf(payload,"&coin_type=1&withdraw_address=%s&withdraw_amount=%.4f",destaddr,amount); + return(jprint(huobi_issue_auth(&exchange->cHandle,exchange,method,payload),1)); +} + +struct exchange_funcs huobi_funcs = EXCHANGE_FUNCS(huobi,EXCHANGE_NAME); + +#undef UPDATE +#undef SUPPORTS +#undef SIGNPOST +#undef TRADE +#undef ORDERSTATUS +#undef CANCELORDER +#undef OPENORDERS +#undef TRADEHISTORY +#undef BALANCES +#undef PARSEBALANCE +#undef WITHDRAW +#undef EXCHANGE_NAME +#undef CHECKBALANCE + diff --git a/iguana/exchanges/lakebtc.c b/iguana/exchanges/lakebtc.c new file mode 100755 index 000000000..a0329dc7b --- /dev/null +++ b/iguana/exchanges/lakebtc.c @@ -0,0 +1,283 @@ +/****************************************************************************** + * Copyright © 2014-2016 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. * + * * + ******************************************************************************/ + +#define EXCHANGE_NAME "lakebtc" +#define UPDATE lakebtc ## _price +#define SUPPORTS lakebtc ## _supports +#define SIGNPOST lakebtc ## _signpost +#define TRADE lakebtc ## _trade +#define ORDERSTATUS lakebtc ## _orderstatus +#define CANCELORDER lakebtc ## _cancelorder +#define OPENORDERS lakebtc ## _openorders +#define TRADEHISTORY lakebtc ## _tradehistory +#define BALANCES lakebtc ## _balances +#define PARSEBALANCE lakebtc ## _parsebalance +#define WITHDRAW lakebtc ## _withdraw +#define CHECKBALANCE lakebtc ## _checkbalance + +double UPDATE(struct exchange_info *exchange,char *base,char *rel,struct exchange_quote *quotes,int32_t maxdepth,cJSON *argjson) +{ + char url[1024]; + if ( strcmp(rel,"USD") == 0 ) + sprintf(url,"https://www.LakeBTC.com/api_v1/bcorderbook"); + else if ( strcmp(rel,"CNY") == 0 ) + sprintf(url,"https://www.LakeBTC.com/api_v1/bcorderbook_cny"); + else printf("illegal lakebtc pair.(%s/%s)\n",base,rel); + return(exchanges777_standardprices(exchange,base,rel,url,quotes,0,0,maxdepth,0)); +} + +int32_t SUPPORTS(struct exchange_info *exchange,char *base,char *rel,cJSON *argjson) +{ + char *baserels[][2] = { {"btc","usd"}, {"btc","cny"} }; + int32_t polarity; + polarity = baserel_polarity(baserels,(int32_t)(sizeof(baserels)/sizeof(*baserels)),base,rel); + printf("lakebtc.(%s %s) polarity.%d\n",base,rel,polarity); + return(polarity); +} + +cJSON *SIGNPOST(void **cHandlep,int32_t dotrade,char **retstrp,struct exchange_info *exchange,char *payload,char *hdr1,uint64_t tonce) +{ + char hdr2[512],cmdbuf[1024],buf64[1024],hdr3[512],dest[1025],hdr4[512],*sig,*data = 0; cJSON *json; + hdr2[0] = hdr3[0] = hdr4[0] = 0; + json = 0; + if ( (sig= hmac_sha1_str(dest,exchange->apisecret,(int32_t)strlen(exchange->apisecret),hdr1)) != 0 ) + { + sprintf(cmdbuf,"%s:%s",exchange->userid,sig); + nn_base64_encode((void *)cmdbuf,strlen(cmdbuf),buf64,sizeof(buf64)); + sprintf(hdr1,"Authorization:Basic %s",buf64); + sprintf(hdr2,"Json-Rpc-Tonce: %llu",(long long)tonce); + if ( dotrade == 0 ) + data = exchange_would_submit(payload,hdr1,hdr2,hdr3,hdr4); + else if ( (data= curl_post(&exchange->cHandle,"https://www.LakeBTC.com/api_v1",0,payload,hdr1,hdr2,hdr3,hdr4)) != 0 ) + json = cJSON_Parse(data); + } + if ( retstrp != 0 ) + *retstrp = data; + else if ( data != 0 ) + free(data); + return(json); +} + +/* LakeBTC provides trading JSON-RPC API interface. HMAC (Hash-based Message Authentication Code) is employed as our authentication mechanisms. You need at 0.1 BTC in your account to retrieve your private key. + + Besides your private key, the client needs to prepare the following attributes + tonce (timestamp in microseconds, i.e., unixtime × 1000000, make sure your clock is correctly adjusted) + accesskey (your registered email address at LakeBTC) + requestmethod (post) + id (JSON-RPC request id, an integer) + method (JSON-RPC method) + params (JSON-RPC parameters) + Concatenate the above parameters with &, in that order. Parameters can be blank. For example, $signature = + tonce=1389067414466757&accesskey=foo@bar.com&requestmethod=post&id=123&method=ticker¶ms= + Create HMAC signature with your private key by using SHA1. $hash = + hash_hmac('sha1', $signature, $privatetkey) #php + Join your email and the hash signature with colon (:), and sign with Base64. $b64 = + base64_encode("foo@bar.com:") #php YXRjQHF3amlhbi5jb206ZmEzM2UzYzg5MDZjg5MzdiYzFiYw== + Set HTTP Header. Note tonce is the same as that in Step 2. + Json-Rpc-Tonce: 1389067414466757 #HTTP HEADER + Authorization: Basic YXRjQHF3amlhbi5jb206ZmEzM2UzYzg5MDZjg5MzdiYzFiYw== #HTTP HEADER + POST params data in JSON format to this url: + https://www.LakeBTC.com/api_v1 + API Methods + getAccountInfo + method=getAccountInfo + params= (i.e., blank) + +static CURL *cHandle; +char *data,*method,buf64[4096],paramstr[128],jsonbuf[1024],base[64],rel[64],pairstr[64],params[1024],dest[512],url[1024],cmdbuf[8192],*sig,hdr1[4096],hdr2[4096],buf[4096]; cJSON *json; uint64_t tonce,nonce,txid = 0; +*retstrp = 0; +params[0] = 0; +nonce = exchange_nonce(exchange); +tonce = (nonce * 1000000 + ((uint64_t)milliseconds() % 1000) * 1000); +if ( dir == 0 ) +{ + method = "getAccountInfo"; + sprintf(buf,"tonce=%llu&accesskey=%s&requestmethod=post&id=1&method=%s¶ms=",(long long)tonce,exchange->userid,method); + sprintf(jsonbuf,"{\"method\":\"%s\",\"params\":[\"%s\"],\"id\":1}",method,params); +} +else +{ + if ( (dir= flipstr_for_exchange(exchange,pairstr,"%s_%s",dir,&price,&volume,base,rel)) == 0 ) + { + printf("cant find baserel (%s/%s)\n",base,rel); + return(0); + } + method = (dir > 0) ? "buyOrder" : "sellOrder"; + touppercase(rel); + sprintf(paramstr,"%.2f,%.4f,%s",price,volume,rel); + sprintf(buf,"tonce=%llu&accesskey=%s&requestmethod=post&id=1&method=%s¶ms=%s",(long long)tonce,exchange->userid,method,paramstr); + sprintf(jsonbuf,"{\"method\":\"%s\",\"params\":[\"%s\"],\"id\":1}",method,paramstr); +} +if ( (sig= hmac_sha1_str(dest,exchange->apisecret,(int32_t)strlen(exchange->apisecret),buf)) != 0 ) +{ + sprintf(cmdbuf,"%s:%s",exchange->userid,sig); + nn_base64_encode((void *)cmdbuf,strlen(cmdbuf),buf64,sizeof(buf64)); + sprintf(url,"https://www.lakebtc.com/api_v1"); + sprintf(hdr1,"Authorization:Basic %s",buf64); + sprintf(hdr2,"Json-Rpc-Tonce: %llu",(long long)tonce); + if ( (data= curl_post(&cHandle,url,0,jsonbuf,hdr1,hdr2,0,0)) != 0 ) + { + //printf("submit cmd.(%s) [%s]\n",jsonbuf,data); + if ( (json= cJSON_Parse(data)) != 0 ) + { + txid = j64bits(json,"order_id"); + free_json(json); + } + } else fprintf(stderr,"submit err cmd.(%s)\n",cmdbuf); + if ( retstrp != 0 ) + *retstrp = data; + else if ( data != 0 ) + free(data); + } +*/ + +char *PARSEBALANCE(struct exchange_info *exchange,double *balancep,char *coinstr,cJSON *argjson) +{ + //lakebtc.({"balance":{"BTC":0.1},"locked":{"BTC":0.0},"profile":{"email":"jameslee777@yahoo.com","id":"U137561934","btc_deposit_addres":"1RyKrNJjezeFfvYaicnJEozHfhWfYzbuh"}}) + char field[128],*str,*itemstr = 0; cJSON *obj=0,*item=0,*prof=0; double locked = 0; + *balancep = 0.; + strcpy(field,coinstr); + touppercase(field); + if ( argjson != 0 && (obj= jobj(argjson,"balance")) != 0 && (item= jobj(argjson,"locked")) != 0 && (prof= jobj(argjson,"profile")) != 0 ) + { + *balancep = jdouble(obj,field); + locked = jdouble(item,field); + obj = cJSON_CreateObject(); + jaddstr(obj,"base",field); + jaddnum(obj,"balance",*balancep); + jaddnum(obj,"locked",locked); + if ( (str= jstr(prof,"btc_deposit_addres")) != 0 ) + jaddstr(obj,"deposit_address",str); + itemstr = jprint(obj,1); + } + if ( itemstr == 0 ) + return(clonestr("{\"error\":\"cant find coin balance\"}")); + return(itemstr); +} + +cJSON *BALANCES(struct exchange_info *exchange,cJSON *argjson) +{ + char payload[1024],jsonbuf[1024],*method; uint64_t tonce; + method = "getAccountInfo"; + tonce = (exchange_nonce(exchange) * 1000000 + ((uint64_t)OS_milliseconds() % 1000) * 1000); + sprintf(payload,"tonce=%llu&accesskey=%s&requestmethod=post&id=1&method=%s¶ms=",(long long)tonce,exchange->userid,method); + sprintf(jsonbuf,"{\"method\":\"%s\",\"params\":[\"%s\"],\"id\":1}",method,""); + return(SIGNPOST(&exchange->cHandle,1,0,exchange,jsonbuf,payload,tonce)); +} + +#include "checkbalance.c" + +uint64_t TRADE(int32_t dotrade,char **retstrp,struct exchange_info *exchange,char *base,char *rel,int32_t dir,double price,double volume,cJSON *argjson) +{ + char payload[1024],jsonbuf[1024],pairstr[64],paramstr[512],*extra,*method; + cJSON *json; uint64_t tonce,txid = 0; + if ( (extra= *retstrp) != 0 ) + *retstrp = 0; + tonce = (exchange_nonce(exchange) * 1000000 + ((uint64_t)OS_milliseconds() % 1000) * 1000); + if ( (dir= flipstr_for_exchange(exchange,pairstr,"%s_%s",dir,&price,&volume,base,rel,argjson)) == 0 ) + { + printf("cant find baserel (%s/%s)\n",base,rel); + return(0); + } + method = (dir > 0) ? "buyOrder" : "sellOrder"; + touppercase(rel); + sprintf(paramstr,"%.2f,%.4f,%s",price,volume,rel); + sprintf(payload,"tonce=%llu&accesskey=%s&requestmethod=post&id=1&method=%s¶ms=%s",(long long)tonce,exchange->userid,method,paramstr); + sprintf(jsonbuf,"{\"method\":\"%s\",\"params\":[\"%s\"],\"id\":1}",method,paramstr); + if ( CHECKBALANCE(retstrp,dotrade,exchange,dir,base,rel,price,volume,argjson) == 0 && (json= SIGNPOST(&exchange->cHandle,dotrade,retstrp,exchange,jsonbuf,payload,tonce)) != 0 ) + { + txid = j64bits(json,"order_id"); + free_json(json); + } + return(txid); +} + +char *CANCELORDER(struct exchange_info *exchange,uint64_t quoteid,cJSON *argjson) +{ + char payload[1024],jsonbuf[1024],*method,*retstr = 0; cJSON *json; uint64_t tonce; + method = "cancelOrder"; + tonce = (exchange_nonce(exchange) * 1000000 + ((uint64_t)OS_milliseconds() % 1000) * 1000); + sprintf(jsonbuf,"{\"method\":\"%s\",\"params\":[\"%llu\"],\"id\":1}",method,(long long)quoteid); + if ( (json= SIGNPOST(&exchange->cHandle,1,&retstr,exchange,payload,jsonbuf,tonce)) != 0 ) + { + free_json(json); + } + return(retstr); // return standardized cancelorder +} + +char *OPENORDERS(struct exchange_info *exchange,cJSON *argjson) +{ + char payload[1024],jsonbuf[1024],*method,*retstr = 0; cJSON *json; uint64_t tonce; + method = "getOrders"; + tonce = (exchange_nonce(exchange) * 1000000 + ((uint64_t)OS_milliseconds() % 1000) * 1000); + sprintf(jsonbuf,"{\"method\":\"%s\",\"params\":[\"%s\"],\"id\":1}",method,""); + if ( (json= SIGNPOST(&exchange->cHandle,1,&retstr,exchange,payload,jsonbuf,tonce)) != 0 ) + { + free_json(json); + } + return(retstr); // return standardized open orders +} + +char *TRADEHISTORY(struct exchange_info *exchange,cJSON *argjson) +{ + char payload[1024],jsonbuf[1024],timestr[64],*method,*retstr = 0; + cJSON *json; uint64_t tonce; uint32_t starttime; + method = "getTrades"; + if ( (starttime= juint(argjson,"start")) != 0 ) + sprintf(timestr,"%u",starttime); + else timestr[0] = 0; + tonce = (exchange_nonce(exchange) * 1000000 + ((uint64_t)OS_milliseconds() % 1000) * 1000); + sprintf(jsonbuf,"{\"method\":\"%s\",\"params\":[%s],\"id\":1}",method,timestr); + if ( (json= SIGNPOST(&exchange->cHandle,1,&retstr,exchange,payload,jsonbuf,tonce)) != 0 ) + { + free_json(json); + } + return(retstr); // return standardized tradehistory +} + +char *ORDERSTATUS(struct exchange_info *exchange,uint64_t quoteid,cJSON *argjson) +{ + char *status,*retstr; + status = OPENORDERS(exchange,argjson); + if ( (retstr= exchange_extractorderid(0,status,quoteid,"id")) != 0 ) + { + free(status); + return(retstr); + } + free(status); + return(clonestr("{\"error\":\"cant find quoteid\"}")); +} + +char *WITHDRAW(struct exchange_info *exchange,char *base,double amount,char *destaddr,cJSON *argjson) +{ + return(clonestr("{\"error\":\"lakebtc doesnt seem to have withdraw api!\"}")); +} + +struct exchange_funcs lakebtc_funcs = EXCHANGE_FUNCS(lakebtc,EXCHANGE_NAME); + +#undef UPDATE +#undef SUPPORTS +#undef SIGNPOST +#undef TRADE +#undef ORDERSTATUS +#undef CANCELORDER +#undef OPENORDERS +#undef TRADEHISTORY +#undef BALANCES +#undef PARSEBALANCE +#undef WITHDRAW +#undef EXCHANGE_NAME +#undef CHECKBALANCE + diff --git a/iguana/exchanges/okcoin.c b/iguana/exchanges/okcoin.c new file mode 100755 index 000000000..e4f7ae88e --- /dev/null +++ b/iguana/exchanges/okcoin.c @@ -0,0 +1,243 @@ +/****************************************************************************** + * Copyright © 2014-2016 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. * + * * + ******************************************************************************/ + +#define EXCHANGE_NAME "okcoin" +#define UPDATE okcoin ## _price +#define SUPPORTS okcoin ## _supports +#define SIGNPOST okcoin ## _signpost +#define TRADE okcoin ## _trade +#define ORDERSTATUS okcoin ## _orderstatus +#define CANCELORDER okcoin ## _cancelorder +#define OPENORDERS okcoin ## _openorders +#define TRADEHISTORY okcoin ## _tradehistory +#define BALANCES okcoin ## _balances +#define PARSEBALANCE okcoin ## _parsebalance +#define WITHDRAW okcoin ## _withdraw +#define EXCHANGE_AUTHURL "https://www.okcoin.com/api/v1" +#define CHECKBALANCE okcoin ## _checkbalance + +double UPDATE(struct exchange_info *exchange,char *base,char *rel,struct exchange_quote *quotes,int32_t maxdepth,cJSON *argjson) +{ + char url[1024],lrel[16],lbase[16]; + strcpy(lrel,rel), strcpy(lbase,base); + tolowercase(lrel), tolowercase(lbase); + sprintf(url,"https://www.okcoin.com/api/v1/depth.do?symbol=%s_%s",lbase,lrel); + if ( strcmp(rel,"USD") != 0 && strcmp(rel,"BTC") != 0 ) + { + fprintf(stderr,">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> FATAL ERROR OKCOIN.(%s) only supports USD\n",url); + printf(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> FATAL ERROR OKCOIN.(%s) only supports USD\n",url); + exit(-1); + return(0); + } + return(exchanges777_standardprices(exchange,base,rel,url,quotes,0,0,maxdepth,0)); +} + +int32_t SUPPORTS(struct exchange_info *exchange,char *base,char *rel,cJSON *argjson) +{ + char *baserels[][2] = { {"btc","usd"}, {"ltc","usd"} }; + return(baserel_polarity(baserels,(int32_t)(sizeof(baserels)/sizeof(*baserels)),base,rel)); +} + +cJSON *SIGNPOST(void **cHandlep,int32_t dotrade,char **retstrp,struct exchange_info *exchange,char *url,char *payload) +{ + char hdr1[512],hdr2[512],hdr3[512],hdr4[512],*data; cJSON *json; + hdr1[0] = hdr2[0] = hdr3[0] = hdr4[0] = 0; + json = 0; + if ( dotrade == 0 ) + data = exchange_would_submit(payload,hdr1,hdr2,hdr3,hdr4); + else if ( (data= curl_post(&exchange->cHandle,url,0,payload,hdr1,hdr2,hdr3,hdr4)) != 0 ) + json = cJSON_Parse(data); + if ( retstrp != 0 ) + *retstrp = data; + else if ( data != 0 ) + free(data); + return(json); +} +/* +static CURL *cHandle; +char *data,*path,*typestr,*extra,pricestr[64],base[64],rel[64],pairstr[64],url[1024],cmdbuf[8192],buf[512],digest[33]; cJSON *json; uint64_t nonce,txid = 0; +nonce = exchange_nonce(exchange); +if ( (extra= *retstrp) != 0 ) +*retstrp = 0; +if ( dir == 0 ) +{ + path = "userinfo.do"; + sprintf(buf,"api_key=%s&secret_key=%s",exchange->apikey,exchange->apisecret); + calc_md5(digest,buf,(int32_t)strlen(buf)); + touppercase(digest); + sprintf(cmdbuf,"api_key=%s&sign=%s",exchange->apikey,digest); +} +else +{ + path = "trade.do"; + if ( (dir= flipstr_for_exchange(exchange,pairstr,"%s_%s",dir,&price,&volume,base,rel)) == 0 ) + { + printf("cant find baserel (%s/%s)\n",base,rel); + return(0); + } + if ( extra != 0 && strcmp(extra,"market") == 0 ) + typestr = (dir > 0) ? "buy_market" : "sell_market", sprintf(pricestr,"&price=%.2f",price); // docs say market orders put volume in price + else typestr = (dir > 0) ? "buy" : "sell", sprintf(pricestr,"&price=%.2f",price); + sprintf(buf,"amount=%.4f&api_key=%s%ssymbol=%s&type=%s&secret_key=%s",volume,exchange->apikey,pricestr,pairstr,typestr,exchange->apisecret); + calc_md5(digest,buf,(int32_t)strlen(buf)); + touppercase(digest); + sprintf(cmdbuf,"amount=%.4f&api_key=%s%s&symbol=%s&type=%s&sign=%s",volume,exchange->apikey,pricestr,pairstr,typestr,digest); + } +//printf("MD5.(%s)\n",buf); +sprintf(url,"https://www.okcoin.com/api/v1/%s",path); +if ( (data= curl_post(&cHandle,url,0,cmdbuf,0,0,0,0)) != 0 ) // "{\"Content-type\":\"application/x-www-form-urlencoded\"}","{\"User-Agent\":\"OKCoin Javascript API Client\"}" +{ + //printf("submit cmd.(%s) [%s]\n",cmdbuf,data); + if ( (json= cJSON_Parse(data)) != 0 ) + { + txid = j64bits(json,"order_id"); + free_json(json); + } +} else fprintf(stderr,"submit err cmd.(%s)\n",cmdbuf); +*/ + +cJSON *okcoin_issue_auth(void **cHandlep,struct exchange_info *exchange,char *method,char *buf) +{ + char payload[1024],tmp[1024],digest[512],url[512]; + sprintf(tmp,"api_key=%s%s",exchange->apikey,buf); + + sprintf(payload,"%s&secret_key=%s",tmp,exchange->apisecret); + //printf("tmp.(%s) payload.(%s)\n",tmp,payload); + calc_md5(digest,payload,(int32_t)strlen(payload)); + touppercase(digest); + sprintf(payload,"%s&sign=%s",tmp,digest); + sprintf(url,"%s/%s",EXCHANGE_AUTHURL,method); + return(SIGNPOST(&exchange->cHandle,1,0,exchange,url,payload)); +} + +char *PARSEBALANCE(struct exchange_info *exchange,double *balancep,char *coinstr,cJSON *argjson) +{ + //okcoin.({"info":{"funds":{"asset":{"net":"0","total":"0"},"free":{"btc":"0","ltc":"0","usd":"0"},"freezed":{"btc":"0","ltc":"0","usd":"0"}}},"result":true}) + char field[128],*itemstr = 0; cJSON *obj,*item,*avail,*locked; double lockval = 0; + *balancep = 0.; + strcpy(field,coinstr); + tolowercase(field); + if ( argjson != 0 && (obj= jobj(argjson,"info")) != 0 && (item= jobj(obj,"funds")) != 0 ) + { + if ( (avail= jobj(item,"free")) != 0 ) + *balancep = jdouble(avail,field); + if ( (locked= jobj(item,"freezed")) != 0 ) + lockval = jdouble(locked,field); + obj = cJSON_CreateObject(); + touppercase(field); + jaddstr(obj,"base",field); + jaddnum(obj,"balance",*balancep); + jaddnum(obj,"locked",lockval); + itemstr = jprint(obj,1); + } + if ( itemstr == 0 ) + return(clonestr("{\"error\":\"cant find coin balance\"}")); + return(itemstr); +} + +cJSON *BALANCES(struct exchange_info *exchange,cJSON *argjson) +{ + return(okcoin_issue_auth(&exchange->cHandle,exchange,"userinfo.do","")); +} + +#include "checkbalance.c" + +uint64_t TRADE(int32_t dotrade,char **retstrp,struct exchange_info *exchange,char *base,char *rel,int32_t dir,double price,double volume,cJSON *argjson) +{ + char payload[1024],buf[1024],url[1024],digest[512],pairstr[512],pricestr[64],*extra,*typestr; + cJSON *json; uint64_t txid = 0; + if ( (extra= *retstrp) != 0 ) + *retstrp = 0; + if ( (dir= flipstr_for_exchange(exchange,pairstr,"%s_%s",dir,&price,&volume,base,rel,argjson)) == 0 ) + { + printf("cant find baserel (%s/%s)\n",base,rel); + return(0); + } + if ( extra != 0 && strcmp(extra,"market") == 0 ) + typestr = (dir > 0) ? "buy_market" : "sell_market", sprintf(pricestr,"&price=%.2f",price); // docs say market orders put volume in price + else typestr = (dir > 0) ? "buy" : "sell"; + sprintf(pricestr,"&price=%.2f",price); + sprintf(buf,"amount=%.4f&api_key=%s%ssymbol=%s&type=%s&secret_key=%s",volume,exchange->apikey,pricestr,pairstr,typestr,exchange->apisecret); + calc_md5(digest,buf,(int32_t)strlen(buf)); + touppercase(digest); + sprintf(payload,"amount=%.4f&api_key=%s%s&symbol=%s&type=%s&sign=%s",volume,exchange->apikey,pricestr,pairstr,typestr,digest); + sprintf(url,"%s/%s",EXCHANGE_AUTHURL,"trade.do"); + if ( CHECKBALANCE(retstrp,dotrade,exchange,dir,base,rel,price,volume,argjson) == 0 && (json= SIGNPOST(&exchange->cHandle,dotrade,retstrp,exchange,url,payload)) != 0 ) + { + txid = j64bits(json,"order_id"); + free_json(json); + } + return(txid); +} + +char *ORDERSTATUS(struct exchange_info *exchange,uint64_t quoteid,cJSON *argjson) +{ + char buf[64]; + sprintf(buf,"&symbol=btc_usd&order_id=%llu",(long long)quoteid); + return(jprint(okcoin_issue_auth(&exchange->cHandle,exchange,"order_info.do",buf),1)); +} + +char *CANCELORDER(struct exchange_info *exchange,uint64_t quoteid,cJSON *argjson) +{ + char buf[64]; + sprintf(buf,"&symbol=btc_usd&order_id=%llu",(long long)quoteid); + return(jprint(okcoin_issue_auth(&exchange->cHandle,exchange,"cancel_order.do",buf),1)); +} + +char *OPENORDERS(struct exchange_info *exchange,cJSON *argjson) +{ + return(jprint(okcoin_issue_auth(&exchange->cHandle,exchange,"orders_info.do",""),1)); +} + +char *TRADEHISTORY(struct exchange_info *exchange,cJSON *argjson) +{ + return(jprint(okcoin_issue_auth(&exchange->cHandle,exchange,"orders_history.do","&status=1&symbol=btc_usd¤t_page=0&page_length=200"),1)); +} + +char *WITHDRAW(struct exchange_info *exchange,char *base,double amount,char *destaddr,cJSON *argjson) +{ + char payload[1024],*method,*tradepassword; + if ( base == 0 || base[0] == 0 ) + return(clonestr("{\"error\":\"base not specified\"}")); + if ( destaddr == 0 || destaddr[0] == 0 ) + return(clonestr("{\"error\":\"destaddr not specified\"}")); + if ( amount < SMALLVAL ) + return(clonestr("{\"error\":\"amount not specified\"}")); + if ( (tradepassword= jstr(argjson,"tradepassword")) == 0 ) + tradepassword = exchange->tradepassword; + if ( tradepassword == 0 || tradepassword[0] == 0 ) + return(clonestr("{\"error\":\"tradepassword not specified\"}")); + method = "withdraw_coin"; + sprintf(payload,"&symbol=btc_usd&chargefee=0.0001&withdraw_address=%s&withdraw_amount=%.4f&trade_pwd=%s",destaddr,amount,tradepassword); + return(jprint(okcoin_issue_auth(&exchange->cHandle,exchange,method,payload),1)); +} + +struct exchange_funcs okcoin_funcs = EXCHANGE_FUNCS(okcoin,EXCHANGE_NAME); + +#undef UPDATE +#undef SUPPORTS +#undef SIGNPOST +#undef TRADE +#undef ORDERSTATUS +#undef CANCELORDER +#undef OPENORDERS +#undef TRADEHISTORY +#undef BALANCES +#undef PARSEBALANCE +#undef WITHDRAW +#undef EXCHANGE_NAME +#undef EXCHANGE_AUTHURL +#undef CHECKBALANCE + diff --git a/iguana/exchanges/poloniex.c b/iguana/exchanges/poloniex.c new file mode 100755 index 000000000..8d4e77172 --- /dev/null +++ b/iguana/exchanges/poloniex.c @@ -0,0 +1,230 @@ +/****************************************************************************** + * Copyright © 2014-2016 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. * + * * + ******************************************************************************/ + +#define EXCHANGE_NAME "poloniex" +#define UPDATE poloniex ## _price +#define SUPPORTS poloniex ## _supports +#define SIGNPOST poloniex ## _signpost +#define TRADE poloniex ## _trade +#define ORDERSTATUS poloniex ## _orderstatus +#define CANCELORDER poloniex ## _cancelorder +#define OPENORDERS poloniex ## _openorders +#define TRADEHISTORY poloniex ## _tradehistory +#define BALANCES poloniex ## _balances +#define PARSEBALANCE poloniex ## _parsebalance +#define WITHDRAW poloniex ## _withdraw +#define EXCHANGE_AUTHURL "https://poloniex.com/tradingApi" +#define CHECKBALANCE poloniex ## _checkbalance + +double UPDATE(struct exchange_info *exchange,char *base,char *rel,struct exchange_quote *quotes,int32_t maxdepth,cJSON *argjson) +{ + char market[128],url[1024]; + sprintf(market,"%s_%s",rel,base); + sprintf(url,"https://poloniex.com/public?command=returnOrderBook¤cyPair=%s&depth=%d",market,maxdepth); + return(exchanges777_standardprices(exchange,base,rel,url,quotes,0,0,maxdepth,0)); +} + +int32_t SUPPORTS(struct exchange_info *exchange,char *base,char *rel,cJSON *argjson) +{ + //char *baserels[][2] = { {"btc","usd"} }; + //return(baserel_polarity(baserels,(int32_t)(sizeof(baserels)/sizeof(*baserels)),base,rel)); + if ( strlen(base) > 5 || strlen(rel) > 5 || strcmp(rel,"CNY") == 0 || strcmp(base,"CNY") == 0 || strcmp(rel,"USD") == 0 || strcmp(base,"USD") == 0 ) + return(0); + if ( strcmp(rel,"BTC") == 0 ) + return(1); + else if ( strcmp(base,"BTC") == 0 ) + return(-1); + else return(0); +} + +cJSON *SIGNPOST(void **cHandlep,int32_t dotrade,char **retstrp,struct exchange_info *exchange,char *url,char *payload) +{ + char dest[(512>>3)*2+1],hdr1[512],hdr2[512],hdr3[512],hdr4[512],*data,*sig; cJSON *json; + hdr1[0] = hdr2[0] = hdr3[0] = hdr4[0] = 0; + json = 0; + if ( (sig= hmac_sha512_str(dest,exchange->apisecret,(int32_t)strlen(exchange->apisecret),payload)) != 0 ) + sprintf(hdr1,"Sign:%s",sig); + else hdr1[0] = 0; + sprintf(hdr2,"Key:%s",exchange->apikey); + if ( dotrade == 0 ) + data = exchange_would_submit(payload,hdr1,hdr2,hdr3,hdr4); + else if ( (data= curl_post(&exchange->cHandle,url,0,payload,hdr1,hdr2,hdr3,hdr4)) != 0 ) + json = cJSON_Parse(data); + if ( retstrp != 0 ) + *retstrp = data; + else if ( data != 0 ) + free(data); + return(json); +} + +cJSON *BALANCES(struct exchange_info *exchange,cJSON *argjson) +{ + char payload[1024]; + sprintf(payload,"command=returnCompleteBalances&nonce=%llu",(long long)exchange_nonce(exchange)); + return(SIGNPOST(&exchange->cHandle,1,0,exchange,EXCHANGE_AUTHURL,payload)); +} + +char *PARSEBALANCE(struct exchange_info *exchange,double *balancep,char *coinstr,cJSON *argjson) +{ + char *itemstr = 0; cJSON *item,*obj; double onorders,btcvalue; + *balancep = 0.; + if ( argjson != 0 && (item= jobj(argjson,coinstr)) != 0 ) + { + itemstr = jprint(item,0); + *balancep = jdouble(item,"available"); + onorders = jdouble(item,"onOrders"); + btcvalue = jdouble(item,"btcValue"); + if ( (obj= cJSON_Parse(itemstr)) != 0 ) + { + free(itemstr); + jaddstr(obj,"base",coinstr); + jaddnum(obj,"balance",*balancep); + jaddnum(obj,"onOrders",onorders); + jaddnum(obj,"btcvalue",btcvalue); + itemstr = jprint(obj,1); + } + } + if ( itemstr == 0 ) + return(clonestr("{\"error\":\"cant find coin balance\"}")); + return(itemstr); +} + +#include "checkbalance.c" + +uint64_t TRADE(int32_t dotrade,char **retstrp,struct exchange_info *exchange,char *base,char *rel,int32_t dir,double price,double volume,cJSON *argjson) +{ + char payload[1024],pairstr[64],*extra,*typestr; cJSON *json; uint64_t nonce,txid = 0; + nonce = exchange_nonce(exchange); + if ( (extra= *retstrp) != 0 ) + *retstrp = 0; + dir = flip_for_exchange(pairstr,"%s_%s","BTC",dir,&price,&volume,base,rel); + if ( extra != 0 && strcmp(extra,"margin") == 0 ) + typestr = (dir > 0) ? "marginBuy":"marginSell"; + else typestr = (dir > 0) ? "buy":"sell"; + sprintf(payload,"command=%s&nonce=%lld¤cyPair=%s&rate=%.8f&amount=%.8f",typestr,(long long)nonce,pairstr,price,volume); + if ( CHECKBALANCE(retstrp,dotrade,exchange,dir,base,rel,price,volume,argjson) == 0 && (json= SIGNPOST(&exchange->cHandle,dotrade,retstrp,exchange,EXCHANGE_AUTHURL,payload)) != 0 ) + { + txid = (get_API_nxt64bits(cJSON_GetObjectItem(json,"orderNumber")) << 32) | get_API_nxt64bits(cJSON_GetObjectItem(json,"tradeID")); + free_json(json); + } + return(txid); +} + +void poloniex_setpair(char *pair,cJSON *argjson) +{ + char *base,*rel; + base = jstr(argjson,"base"); + rel = jstr(argjson,"rel"); + if ( base == 0 || rel == 0 ) + strcpy(pair,"all"); + else sprintf(pair,"%s_%s",rel,base); +} + +char *CANCELORDER(struct exchange_info *exchange,uint64_t quoteid,cJSON *argjson) +{ + char payload[1024],*retstr = 0; cJSON *json; + sprintf(payload,"command=cancelOrder&nonce=%llu&orderNumber=%llu",(long long)exchange_nonce(exchange),(long long)quoteid); + if ( (json= SIGNPOST(&exchange->cHandle,1,&retstr,exchange,EXCHANGE_AUTHURL,payload)) != 0 ) + { + free_json(json); + } + return(retstr); // return standardized cancelorder +} + +char *OPENORDERS(struct exchange_info *exchange,cJSON *argjson) +{ + char payload[1024],pair[64],*retstr = 0; cJSON *json; + poloniex_setpair(pair,argjson); + sprintf(payload,"command=returnOpenOrders&nonce=%llu¤cyPair=%s",(long long)exchange_nonce(exchange),pair); + if ( (json= SIGNPOST(&exchange->cHandle,1,&retstr,exchange,EXCHANGE_AUTHURL,payload)) != 0 ) + { + free_json(json); + } + return(retstr); // return standardized open orders +} + +char *TRADEHISTORY(struct exchange_info *exchange,cJSON *argjson) +{ + char payload[1024],pair[64],*retstr = 0; cJSON *json; uint32_t timestamp,endstamp; + poloniex_setpair(pair,argjson); + timestamp = juint(argjson,"start"); + endstamp = juint(argjson,"end"); + sprintf(payload,"command=returnTradeHistory&nonce=%llu¤cyPair=%s",(long long)exchange_nonce(exchange),pair); + if ( timestamp != 0 ) + sprintf(payload + strlen(payload),"&start=%u",timestamp); + if ( endstamp != 0 ) + sprintf(payload + strlen(payload),"&end=%u",endstamp); + if ( (json= SIGNPOST(&exchange->cHandle,1,&retstr,exchange,EXCHANGE_AUTHURL,payload)) != 0 ) + { + free_json(json); + } + return(retstr); // return standardized tradehistory +} + +char *ORDERSTATUS(struct exchange_info *exchange,uint64_t quoteid,cJSON *argjson) +{ + char *status,*retstr; uint32_t iter; + for (iter=0; iter<2; iter++) + { + if ( iter == 0 ) + status = OPENORDERS(exchange,argjson); + else status = TRADEHISTORY(exchange,argjson); + if ( (retstr= exchange_extractorderid(iter,status,quoteid,"orderNumber")) != 0 ) + { + free(status); + return(retstr); + } + free(status); + } + return(clonestr("{\"error\":\"cant find quoteid\"}")); +} + +char *WITHDRAW(struct exchange_info *exchange,char *base,double amount,char *destaddr,cJSON *argjson) +{ + char payload[1024],*paymentid,*retstr = 0; cJSON *json; + if ( base == 0 || base[0] == 0 ) + return(clonestr("{\"error\":\"base not specified\"}")); + if ( destaddr == 0 || destaddr[0] == 0 ) + return(clonestr("{\"error\":\"destaddr not specified\"}")); + if ( amount < SMALLVAL ) + return(clonestr("{\"error\":\"amount not specified\"}")); + paymentid = jstr(argjson,"paymentid"); + sprintf(payload,"command=withdraw&nonce=%llu¤cy=%s&amount=%.6f&address=%s",(long long)exchange_nonce(exchange),base,amount,destaddr); + if ( paymentid != 0 ) + sprintf(payload + strlen(payload),"&paymentId=%s",paymentid); + if ( (json= SIGNPOST(&exchange->cHandle,1,&retstr,exchange,EXCHANGE_AUTHURL,payload)) != 0 ) + { + free_json(json); + } + return(retstr); // return standardized withdraw +} + +struct exchange_funcs poloniex_funcs = EXCHANGE_FUNCS(poloniex,EXCHANGE_NAME); + + +#undef UPDATE +#undef SUPPORTS +#undef SIGNPOST +#undef TRADE +#undef ORDERSTATUS +#undef CANCELORDER +#undef OPENORDERS +#undef TRADEHISTORY +#undef BALANCES +#undef PARSEBALANCE +#undef WITHDRAW +#undef EXCHANGE_NAME +#undef EXCHANGE_AUTHURL +#undef CHECKBALANCE diff --git a/iguana/exchanges/quadriga.c b/iguana/exchanges/quadriga.c new file mode 100755 index 000000000..a8bde3910 --- /dev/null +++ b/iguana/exchanges/quadriga.c @@ -0,0 +1,185 @@ +/****************************************************************************** + * Copyright © 2014-2016 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. * + * * + ******************************************************************************/ + +#define EXCHANGE_NAME "quadriga" +#define UPDATE quadriga ## _price +#define SUPPORTS quadriga ## _supports +#define SIGNPOST quadriga ## _signpost +#define TRADE quadriga ## _trade +#define ORDERSTATUS quadriga ## _orderstatus +#define CANCELORDER quadriga ## _cancelorder +#define OPENORDERS quadriga ## _openorders +#define TRADEHISTORY quadriga ## _tradehistory +#define BALANCES quadriga ## _balances +#define PARSEBALANCE quadriga ## _parsebalance +#define WITHDRAW quadriga ## _withdraw +#define CHECKBALANCE quadriga ## _checkbalance + +double UPDATE(struct exchange_info *exchange,char *base,char *rel,struct exchange_quote *quotes,int32_t maxdepth,cJSON *argjson) +{ + char url[1024],lrel[16],lbase[16]; + strcpy(lrel,rel), strcpy(lbase,base); + tolowercase(lrel), tolowercase(lbase); + sprintf(url,"https://api.quadrigacx.com/v2/order_book?book=%s_%s",lbase,lrel); + return(exchanges777_standardprices(exchange,base,rel,url,quotes,0,0,maxdepth,0)); +} + +int32_t SUPPORTS(struct exchange_info *exchange,char *base,char *rel,cJSON *argjson) +{ + char *baserels[][2] = { {"btc","usd"}, {"btc","cad"} }; + return(baserel_polarity(baserels,(int32_t)(sizeof(baserels)/sizeof(*baserels)),base,rel)); +} + +cJSON *SIGNPOST(void **cHandlep,int32_t dotrade,char **retstrp,struct exchange_info *exchange,char *payload,char *path) +{ + char url[1024],req[1024],md5secret[128],tmp[1024],dest[1025],hdr1[512],hdr2[512],hdr3[512],hdr4[512],*sig,*data = 0; + cJSON *json; uint64_t nonce; + hdr1[0] = hdr2[0] = hdr3[0] = hdr4[0] = 0; + json = 0; + nonce = exchange_nonce(exchange) * 1000 + ((uint64_t)OS_milliseconds() % 1000); + sprintf(tmp,"%llu%s%s",(long long)nonce,exchange->userid,exchange->apikey); + calc_md5(md5secret,exchange->apisecret,(int32_t)strlen(exchange->apisecret)); + if ( (sig= hmac_sha256_str(dest,md5secret,(int32_t)strlen(md5secret),tmp)) != 0 ) + { + sprintf(req,"{\"key\":\"%s\",%s\"nonce\":%llu,\"signature\":\"%s\"}",exchange->apikey,payload,(long long)nonce,sig); + sprintf(hdr1,"Content-Type:application/json"); + sprintf(hdr2,"charset=utf-8"); + sprintf(hdr3,"Content-Length:%ld",(long)strlen(req)); + sprintf(url,"https://api.quadrigacx.com/v2/%s",path); + if ( dotrade == 0 ) + data = exchange_would_submit(req,hdr1,hdr2,hdr3,hdr4); + else if ( (data= curl_post(&exchange->cHandle,url,0,req,hdr1,hdr2,hdr3,hdr4)) != 0 ) + json = cJSON_Parse(data); + } + if ( retstrp != 0 ) + *retstrp = data; + else if ( data != 0 ) + free(data); + return(json); +} + +char *PARSEBALANCE(struct exchange_info *exchange,double *balancep,char *coinstr,cJSON *argjson) +{ + //[{"btc_available":"0.00000000","btc_reserved":"0.00000000","btc_balance":"0.00000000","cad_available":"0.00","cad_reserved":"0.00","cad_balance":"0.00","usd_available":"0.00","usd_reserved":"0.00","usd_balance":"0.00","xau_available":"0.000000","xau_reserved":"0.000000","xau_balance":"0.000000","fee":"0.5000"}] + char field[128],*str,*itemstr = 0; cJSON *obj; double reserv,total; + *balancep = 0.; + strcpy(field,coinstr); + tolowercase(field); + strcat(field,"_available"); + if ( argjson != 0 && (str= jstr(argjson,field)) != 0 ) + { + *balancep = jdouble(argjson,field); + strcpy(field,coinstr), tolowercase(field), strcat(field,"_reserved"); + reserv = jdouble(argjson,field); + strcpy(field,coinstr), tolowercase(field), strcat(field,"_balance"); + total = jdouble(argjson,field); + obj = cJSON_CreateObject(); + jaddnum(obj,"balance",*balancep); + jaddnum(obj,"locked_balance",reserv); + jaddnum(obj,"total",total); + itemstr = jprint(obj,1); + } + if ( itemstr == 0 ) + return(clonestr("{\"error\":\"cant find coin balance\"}")); + return(itemstr); +} + +cJSON *BALANCES(struct exchange_info *exchange,cJSON *argjson) +{ + return(SIGNPOST(&exchange->cHandle,1,0,exchange,"","balance")); +} + +#include "checkbalance.c" + +uint64_t TRADE(int32_t dotrade,char **retstrp,struct exchange_info *exchange,char *base,char *rel,int32_t dir,double price,double volume,cJSON *argjson) +{ + char payload[1024],pairstr[64],*extra,*path; cJSON *json; uint64_t txid = 0; + if ( (extra= *retstrp) != 0 ) + *retstrp = 0; + if ( (dir= flipstr_for_exchange(exchange,pairstr,"%s_%s",dir,&price,&volume,base,rel,argjson)) == 0 ) + { + printf("cant find baserel (%s/%s)\n",base,rel); + return(0); + } + path = (dir > 0) ? "buy" : "sell"; + //key - API key + //signature - signature + //nonce - nonce + //amount - amount of major currency + //price - price to buy at + //book - optional, if not specified, will default to btc_cad + sprintf(payload,"\"amount\":%.6f,\"price\":%.3f,\"book\":\"%s_%s\",",volume,price,base,rel); + if ( CHECKBALANCE(retstrp,dotrade,exchange,dir,base,rel,price,volume,argjson) == 0 && (json= SIGNPOST(&exchange->cHandle,dotrade,retstrp,exchange,payload,path)) != 0 ) + { + // parse json and set txid + free_json(json); + } + return(txid); +} + +char *ORDERSTATUS(struct exchange_info *exchange,uint64_t quoteid,cJSON *argjson) +{ + char buf[64]; + sprintf(buf,"\"id\":%llu,",(long long)quoteid); + return(jprint(SIGNPOST(&exchange->cHandle,1,0,exchange,buf,"lookup_order"),1)); +} + +char *CANCELORDER(struct exchange_info *exchange,uint64_t quoteid,cJSON *argjson) +{ + char buf[64]; + sprintf(buf,"\"id\":%llu,",(long long)quoteid); + return(jprint(SIGNPOST(&exchange->cHandle,1,0,exchange,buf,"cancel_order"),1)); +} + +char *OPENORDERS(struct exchange_info *exchange,cJSON *argjson) +{ + return(jprint(SIGNPOST(&exchange->cHandle,1,0,exchange,"","open_orders"),1)); +} + +char *TRADEHISTORY(struct exchange_info *exchange,cJSON *argjson) +{ + return(jprint(SIGNPOST(&exchange->cHandle,1,0,exchange,"","user_transactions"),1)); +} + +char *WITHDRAW(struct exchange_info *exchange,char *base,double amount,char *destaddr,cJSON *argjson) +{ + char buf[1024]; + if ( base == 0 || base[0] == 0 ) + return(clonestr("{\"error\":\"base not specified\"}")); + if ( destaddr == 0 || destaddr[0] == 0 ) + return(clonestr("{\"error\":\"destaddr not specified\"}")); + if ( amount < SMALLVAL ) + return(clonestr("{\"error\":\"amount not specified\"}")); + sprintf(buf,"\"amount\":%.4f,\"address\":\"%s\",",amount,destaddr); + printf("submit.(%s)\n",buf); + return(jprint(SIGNPOST(&exchange->cHandle,1,0,exchange,"","bitcoin_withdrawal"),1)); +} + +struct exchange_funcs quadriga_funcs = EXCHANGE_FUNCS(quadriga,EXCHANGE_NAME); + +#undef UPDATE +#undef SUPPORTS +#undef SIGNPOST +#undef TRADE +#undef ORDERSTATUS +#undef CANCELORDER +#undef OPENORDERS +#undef TRADEHISTORY +#undef BALANCES +#undef PARSEBALANCE +#undef WITHDRAW +#undef EXCHANGE_NAME +#undef CHECKBALANCE + diff --git a/iguana/exchanges777.h b/iguana/exchanges777.h new file mode 100755 index 000000000..26ed88b4f --- /dev/null +++ b/iguana/exchanges777.h @@ -0,0 +1,68 @@ +/****************************************************************************** + * Copyright © 2014-2016 The SuperNET Developers. * + * * + * See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at * + * the top-level directory of this distribution for the individual copyright * + * holder information and the developer policies on copyright and licensing. * + * * + * Unless otherwise agreed in a custom licensing agreement, no part of the * + * SuperNET software, including this file may be copied, modified, propagated * + * or distributed except according to the terms contained in the LICENSE file * + * * + * Removal or modification of this copyright notice is prohibited. * + * * + ******************************************************************************/ + +#ifndef EXCHANGES777_H +#define EXCHANGES777_H +#include "iguana777.h" + +#include +#include + +#define EXCHANGES777_MAXDEPTH 200 +#define EXCHANGES777_DEFAULT_TIMEOUT 30 + +struct exchange_info; +struct exchange_quote { double price,volume; uint64_t orderid,offerNXT; uint32_t timestamp; }; + +struct exchange_request +{ + struct queueitem DL; + cJSON *argjson; char **retstrp; + double price,volume,hbla,lastbid,lastask; + uint64_t orderid; + int32_t dir,depth,func,numbids,numasks; + char base[16],rel[16],destaddr[64],invert,allflag,dotrade; + struct exchange_quote bidasks[]; +}; + +struct exchange_funcs +{ + char name[32]; + double (*price)(struct exchange_info *exchange,char *base,char *rel,struct exchange_quote *quotes,int32_t maxdepth,cJSON *argjson); + int32_t (*supports)(struct exchange_info *exchange,char *base,char *rel,cJSON *argjson); + char *(*parsebalance)(struct exchange_info *exchange,double *balancep,char *coinstr,cJSON *argjson); + cJSON *(*balances)(struct exchange_info *exchange,cJSON *argjson); + uint64_t (*trade)(int32_t dotrade,char **retstrp,struct exchange_info *exchange,char *base,char *rel,int32_t dir,double price,double volume,cJSON *argjson); + char *(*orderstatus)(struct exchange_info *exchange,uint64_t quoteid,cJSON *argjson); + char *(*cancelorder)(struct exchange_info *exchange,uint64_t quoteid,cJSON *argjson); + char *(*openorders)(struct exchange_info *exchange,cJSON *argjson); + char *(*tradehistory)(struct exchange_info *exchange,cJSON *argjson); + char *(*withdraw)(struct exchange_info *exchange,char *base,double amount,char *destaddr,cJSON *argjson); +}; +#define EXCHANGE_FUNCS(xchg,name) { name, xchg ## _price, xchg ## _supports, xchg ## _parsebalance, xchg ## _balances, xchg ## _trade, xchg ## _orderstatus, xchg ## _cancelorder, xchg ## _openorders, xchg ## _tradehistory, xchg ## _withdraw } + +struct exchange_info +{ + struct exchange_funcs issue; + char name[16],apikey[MAX_JSON_FIELD],apisecret[MAX_JSON_FIELD],tradepassword[MAX_JSON_FIELD],userid[MAX_JSON_FIELD]; + uint32_t exchangeid,pollgap,lastpoll; + uint64_t lastnonce; double commission; + CURL *cHandle; queue_t requestQ,pricesQ,pendingQ[2]; +}; + +void *curl_post(void **cHandlep,char *url,char *userpass,char *postfields,char *hdr0,char *hdr1,char *hdr2,char *hdr3); + +void prices777_processprice(struct exchange_info *exchange,char *base,char *rel,struct exchange_quote *bidasks,int32_t maxdepth); +#endif diff --git a/iguana/iguana777.h b/iguana/iguana777.h index b8f5e6f3a..01200b210 100755 --- a/iguana/iguana777.h +++ b/iguana/iguana777.h @@ -721,6 +721,7 @@ cJSON *iguana_voutjson(struct iguana_info *coin,struct iguana_msgvout *vout,int3 cJSON *iguana_vinjson(struct iguana_info *coin,struct iguana_msgvin *vin); char *iguana_rawtxbytes(struct iguana_info *coin,cJSON *json,uint8_t *data,int32_t datalen); int32_t iguana_send_VPNversion(struct iguana_info *coin,struct iguana_peer *addr,uint64_t myservices); +void exchanges777_init(int32_t sleepflag); extern queue_t bundlesQ; diff --git a/iguana/iguana_exchanges.c b/iguana/iguana_exchanges.c new file mode 100755 index 000000000..a74b1cd1f --- /dev/null +++ b/iguana/iguana_exchanges.c @@ -0,0 +1,726 @@ +/****************************************************************************** + * Copyright © 2014-2016 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 "exchanges777.h" + +#define EXCHANGE777_DONE 1 +#define EXCHANGE777_ISPENDING 2 +#define EXCHANGE777_REQUEUE 3 + +char *Exchange_names[] = { "bitfinex", "btc38", "bitstamp", "btce", "poloniex", "bittrex", "huobi", "coinbase", "okcoin", "lakebtc", "quadriga", "truefx", "ecb", "instaforex", "fxcm", "yahoo" }; +struct exchange_info *Exchanges[sizeof(Exchange_names)/sizeof(*Exchange_names)]; + +void prices777_processprice(struct exchange_info *exchange,char *base,char *rel,struct exchange_quote *bidasks,int32_t maxdepth) +{ + +} + +cJSON *exchanges777_quotejson(struct exchange_quote *quote,int32_t allflag) +{ + cJSON *json; char str[65]; + if ( allflag != 0 ) + { + json = cJSON_CreateObject(); + jaddnum(json,"price",quote->price); + jaddnum(json,"volume",quote->volume); + jaddstr(json,"time",utc_str(str,quote->timestamp)); + if ( quote->orderid > 0 ) + jadd64bits(json,"orderid",quote->orderid); + if ( quote->offerNXT > 0 ) + jadd64bits(json,"offerNXT",quote->offerNXT); + return(json); + } else return(cJSON_CreateNumber(quote->price)); +} + +char *exchanges777_orderbook_jsonstr(struct exchange_info *exchange,char *_base,char *_rel,struct exchange_quote *bidasks,int32_t maxdepth,int32_t invert,int32_t allflag) +{ + struct exchange_quote *bid,*ask; cJSON *json,*bids,*asks; double highbid,lowask; uint32_t timestamp; + int32_t slot,numbids,numasks,enda,endb; char baserel[64],base[64],rel[64],str[65]; + if ( invert == 0 ) + { + strcpy(base,_base), strcpy(rel,_rel); + sprintf(baserel,"%s/%s",base,rel); + } + else + { + strcpy(base,_rel), strcpy(rel,_base); + sprintf(baserel,"%s/%s",rel,base); + } + json = cJSON_CreateObject(), bids = cJSON_CreateArray(), asks = cJSON_CreateArray(); + highbid = lowask = 0.; + for (slot=numbids=numasks=enda=endb=0; slotprice > SMALLVAL ) + { + jaddi(bids,exchanges777_quotejson(bid,allflag)); + if ( numbids++ == 0 ) + highbid = bid->price; + } else endb = 1; + if ( enda == 0 && ask->price > SMALLVAL ) + { + jaddi(asks,exchanges777_quotejson(ask,allflag)); + if ( numasks++ == 0 ) + lowask = ask->price; + } else enda = 1; + } + jaddstr(json,"exchange",exchange->name); + jaddnum(json,"inverted",invert); + jaddstr(json,"base",base); + if ( rel[0] != 0 ) + jaddstr(json,"rel",rel); + jadd(json,"bids",bids); + jadd(json,"asks",asks); + if ( invert == 0 ) + { + jaddnum(json,"numbids",numbids); + jaddnum(json,"numasks",numasks); + if ( highbid > SMALLVAL ) + jaddnum(json,"highbid",highbid); + if ( lowask > SMALLVAL ) + jaddnum(json,"lowask",lowask); + } + else + { + jaddnum(json,"numbids",numasks); + jaddnum(json,"numasks",numbids); + if ( lowask > SMALLVAL ) + jaddnum(json,"highbid",1. / lowask); + if ( highbid > SMALLVAL ) + jaddnum(json,"lowask",1. / highbid); + } + timestamp = (uint32_t)time(NULL); + jaddnum(json,"timestamp",timestamp); + jaddstr(json,"time",utc_str(str,timestamp)); + jaddnum(json,"maxdepth",maxdepth); + return(jprint(json,1)); +} + +void exchanges777_json_quotes(struct exchange_info *exchange,char *base,char *rel,double *lastbidp,double *lastaskp,double *hblap,struct exchange_quote *bidasks,cJSON *bids,cJSON *asks,int32_t maxdepth,char *pricefield,char *volfield,uint32_t reftimestamp) +{ + int32_t i,slot,n=0,m=0,dir,bidask,slot_ba,numitems,numbids,numasks; uint64_t orderid,offerNXT; + cJSON *item; struct exchange_quote *quote; uint32_t timestamp; double price,volume,hbla = 0.; + *lastbidp = *lastaskp = 0.; + numbids = numasks = 0; + if ( reftimestamp == 0 ) + reftimestamp = (uint32_t)time(NULL); + if ( bids != 0 ) + { + n = cJSON_GetArraySize(bids); + if ( maxdepth != 0 && n > maxdepth ) + n = maxdepth; + } + if ( asks != 0 ) + { + m = cJSON_GetArraySize(asks); + if ( maxdepth != 0 && m > maxdepth ) + m = maxdepth; + } + for (i=0; i= n ) + continue; + else if ( bidask == 1 && i >= m ) + continue; + //if ( strcmp(prices->exchange,"bter") == 0 && dir < 0 ) + // slot = ((bidask==0?n:m) - 1) - i; + //else + slot = i; + timestamp = 0; + item = jitem(bidask==0?bids:asks,slot); + if ( pricefield != 0 && volfield != 0 ) + price = jdouble(item,pricefield), volume = jdouble(item,volfield); + else if ( is_cJSON_Array(item) != 0 && (numitems= cJSON_GetArraySize(item)) != 0 ) // big assumptions about order within nested array! + { + price = jdouble(jitem(item,0),0), volume = jdouble(jitem(item,1),0); + if ( strcmp(exchange->name,"kraken") == 0 ) + timestamp = juint(jitem(item,2),0); + else orderid = j64bits(jitem(item,2),0); + } + else continue; + if ( price > SMALLVAL && volume > SMALLVAL ) + { + if ( exchange->commission != 0. ) + { + //printf("price %f fee %f -> ",price,prices->commission * price); + if ( bidask == 0 ) + price -= exchange->commission * price; + else price += exchange->commission * price; + //printf("%f\n",price); + } + quote = (bidask == 0) ? &bidasks[numbids<<1] : &bidasks[(numbids<<1) + 1]; + quote->price = price, quote->volume = volume, quote->timestamp = timestamp, quote->orderid = orderid, quote->offerNXT = offerNXT; + if ( bidask == 0 ) + slot_ba = (numbids++ << 1); + else slot_ba = (numasks++ << 1) | 1; + if ( i == 0 ) + { + if ( bidask == 0 ) + *lastbidp = price; + else *lastaskp = price; + if ( hbla == 0. ) + hbla = price; + else hbla = 0.5 * (hbla + price); + } + printf("%d,%d: %-8s %s %5s/%-5s %13.8f vol %13.8f | invert %13.8f vol %13.8f | timestamp.%u\n",numbids,numasks,exchange->name,dir>0?"bid":"ask",base,rel,price,volume,1./price,volume*price,timestamp); + } + } + } + if ( hbla != 0. ) + *hblap = hbla; +} + +double exchanges777_json_orderbook(struct exchange_info *exchange,char *base,char *rel,struct exchange_quote *bidasks,int32_t maxdepth,cJSON *json,char *resultfield,char *bidfield,char *askfield,char *pricefield,char *volfield) +{ + cJSON *obj = 0,*bidobj=0,*askobj=0; double lastbid,lastask,hbla = 0.; int32_t numasks=0,numbids=0; + if ( resultfield == 0 ) + obj = json; + if ( maxdepth == 0 ) + maxdepth = EXCHANGES777_MAXDEPTH; + if ( resultfield == 0 || (obj= jobj(json,resultfield)) != 0 ) + { + bidobj = jarray(&numbids,obj,bidfield); + askobj = jarray(&numasks,obj,askfield); + if ( bidobj != 0 || askobj != 0 ) + { + exchanges777_json_quotes(exchange,base,rel,&lastbid,&lastask,&hbla,bidasks,bidobj,askobj,maxdepth,pricefield,volfield,0); + } + } + return(hbla); +} + +double exchanges777_standardprices(struct exchange_info *exchange,char *base,char *rel,char *url,struct exchange_quote *quotes,char *price,char *volume,int32_t maxdepth,char *field) +{ + char *jsonstr; cJSON *json; double hbla = 0.; + if ( (jsonstr= issue_curl(url)) != 0 ) + { + //if ( strcmp(exchangestr,"btc38") == 0 ) + printf("(%s) -> (%s)\n",url,jsonstr); + if ( (json= cJSON_Parse(jsonstr)) != 0 ) + { + hbla = exchanges777_json_orderbook(exchange,base,rel,quotes,maxdepth,json,field,"bids","asks",price,volume); + free_json(json); + } + free(jsonstr); + } + return(hbla); +} + +char *exchange_would_submit(char *postreq,char *hdr1,char *hdr2,char *hdr3, char *hdr4) +{ + char *data; cJSON *json; + json = cJSON_CreateObject(); + jaddstr(json,"post",postreq); + if ( hdr1[0] != 0 ) + jaddstr(json,"hdr1",hdr1); + if ( hdr2[0] != 0 ) + jaddstr(json,"hdr2",hdr2); + if ( hdr3[0] != 0 ) + jaddstr(json,"hdr3",hdr3); + if ( hdr4[0] != 0 ) + jaddstr(json,"hdr4",hdr4); + data = jprint(json,1); + json = 0; + return(data); +} + +uint64_t exchange_nonce(struct exchange_info *exchange) +{ + uint64_t nonce; + nonce = time(NULL); + if ( nonce < exchange->lastnonce ) + nonce = exchange->lastnonce + 1; + exchange->lastnonce = nonce; + return(nonce); +} + +int32_t flip_for_exchange(char *pairstr,char *fmt,char *refstr,int32_t dir,double *pricep,double *volumep,char *base,char *rel) +{ + if ( strcmp(rel,refstr) == 0 ) + sprintf(pairstr,fmt,rel,base); + else + { + if ( strcmp(base,refstr) == 0 ) + { + sprintf(pairstr,fmt,base,rel); + dir = -dir; + *volumep *= *pricep; + *pricep = (1. / *pricep); + } + else sprintf(pairstr,fmt,rel,base); + } + return(dir); +} + +int32_t flipstr_for_exchange(struct exchange_info *exchange,char *pairstr,char *fmt,int32_t dir,double *pricep,double *volumep,char *_base,char *_rel,cJSON *argjson) +{ + int32_t polarity; char base[64],rel[64]; + strcpy(base,_base), strcpy(rel,_rel); + tolowercase(base), tolowercase(rel); + polarity = (*exchange->issue.supports)(exchange,base,rel,argjson); + if ( dir > 0 ) + sprintf(pairstr,fmt,base,rel); + else if ( dir < 0 ) + { + *volumep *= *pricep; + *pricep = (1. / *pricep); + sprintf(pairstr,fmt,rel,base); + } + return(dir); +} + +int32_t cny_flip(char *market,char *coinname,char *base,char *rel,int32_t dir,double *pricep,double *volumep) +{ + char pairstr[512],lbase[16],lrel[16],*refstr=0; + strcpy(lbase,base), tolowercase(lbase), strcpy(lrel,rel), tolowercase(lrel); + if ( strcmp(lbase,"cny") == 0 || strcmp(lrel,"cny") == 0 ) + { + dir = flip_for_exchange(pairstr,"%s_%s","cny",dir,pricep,volumep,lbase,lrel); + refstr = "cny"; + } + else if ( strcmp(lbase,"btc") == 0 || strcmp(lrel,"btc") == 0 ) + { + dir = flip_for_exchange(pairstr,"%s_%s","btc",dir,pricep,volumep,lbase,lrel); + refstr = "btc"; + } + if ( market != 0 && coinname != 0 && refstr != 0 ) + { + strcpy(market,refstr); + if ( strcmp(lbase,"refstr") != 0 ) + strcpy(coinname,lbase); + else strcpy(coinname,lrel); + touppercase(coinname); + } + return(dir); +} + +char *exchange_extractorderid(int32_t historyflag,char *status,uint64_t quoteid,char *quoteid_field) +{ + cJSON *array,*item,*json; int32_t i,n; uint64_t txid; + if ( status != 0 ) + { + if ( (array= cJSON_Parse(status)) != 0 && is_cJSON_Array(array) != 0 && (n= cJSON_GetArraySize(array)) > 0 ) + { + for (i=0; ifunc ) + { + case 'Q': + memset(req->bidasks,0,req->depth * sizeof(*req->bidasks) * 2); + (*exchange->issue.price)(exchange,req->base,req->rel,req->bidasks,req->depth,req->argjson); + retstr = exchanges777_orderbook_jsonstr(exchange,req->base,req->rel,req->bidasks,req->depth,req->invert,req->allflag); + break; + case 'S': + dir = (*exchange->issue.supports)(exchange,req->base,req->rel,req->argjson); + retjson = cJSON_CreateObject(); + jaddnum(retjson,"result",dir); + retstr = jprint(retjson,1); + break; + case 'T': + orderid = (*exchange->issue.trade)(req->dotrade,&retstr,exchange,req->base,req->rel,req->dir,req->price,req->volume,req->argjson); + if ( retstr == 0 ) + { + retjson = cJSON_CreateObject(); + if ( orderid != 0 ) + jadd64bits(retjson,"result",orderid); + else jaddstr(retjson,"error","no return value from trade call"); + retstr = jprint(retjson,1); + } + break; + case 'B': + if ( (balancejson= (*exchange->issue.balances)(exchange,req->argjson)) != 0 ) + { + retstr = (*exchange->issue.parsebalance)(exchange,&balance,req->base,balancejson); + free_json(balancejson); + } + break; + case 'P': + retstr = (*exchange->issue.orderstatus)(exchange,req->orderid,req->argjson); + break; + case 'C': + retstr = (*exchange->issue.cancelorder)(exchange,req->orderid,req->argjson); + break; + case 'O': + retstr = (*exchange->issue.openorders)(exchange,req->argjson); + break; + case 'H': + retstr = (*exchange->issue.tradehistory)(exchange,req->argjson); + break; + case 'W': + retstr = (*exchange->issue.withdraw)(exchange,req->base,req->volume,req->destaddr,req->argjson); + break; + } + return(retstr); +} + +void exchanges777_loop(void *ptr) +{ + int32_t flag,retval; struct exchange_request *req; char *retstr; struct exchange_info *exchange = ptr; + while ( 1 ) + { + flag = retval = 0; + retstr = 0; + if ( (req= queue_dequeue(&exchange->requestQ,0)) != 0 ) + { + printf("dequeued %s.%c\n",exchange->name,req->func); + retstr = exchanges777_process(exchange,&retval,req); + if ( retval == EXCHANGE777_DONE ) + { + if ( retstr != 0 ) + { + if ( req->retstrp != 0 ) + *req->retstrp = retstr; + else free(retstr); + } + free(req); + flag++; + } + else + { + if ( retstr != 0 ) + free(retstr); + if ( retval == EXCHANGE777_ISPENDING ) + queue_enqueue("Xpending",&exchange->pendingQ[0],&req->DL,0), flag++; + else if ( retval == EXCHANGE777_REQUEUE ) + queue_enqueue("requeue",&exchange->requestQ,&req->DL,0); + else + { + printf("exchanges777_process: illegal retval.%d\n",retval); + free(req); + } + } + } + if ( flag == 0 && time(NULL) > exchange->lastpoll+exchange->pollgap ) + { + printf("check %s pricesQ\n",exchange->name); + if ( (req= queue_dequeue(&exchange->pricesQ,0)) != 0 ) + { + exchange->lastpoll = (uint32_t)time(NULL); + req->hbla = (*exchange->issue.price)(exchange,req->base,req->rel,req->bidasks,req->depth,req->argjson); + prices777_processprice(exchange,req->base,req->rel,req->bidasks,req->depth); + queue_enqueue("pricesQ",&exchange->pricesQ,&req->DL,0); + } + } + if ( flag == 0 ) + sleep(exchange->pollgap/2 + 1); + } +} + +char *exchanges777_submit(struct exchange_info *exchange,char **retstrp,struct exchange_request *req,int32_t func,int32_t maxseconds) +{ + int32_t i; + req->func = func; + if ( maxseconds == 0 ) + maxseconds = EXCHANGES777_DEFAULT_TIMEOUT; + queue_enqueue("exchangeQ",&exchange->requestQ,&req->DL,0); + for (i=0; iargjson = argjson; req->retstrp = &retstr; + safecopy(req->base,base,sizeof(req->base)); + safecopy(req->rel,rel,sizeof(req->rel)); + req->price = price, req->volume = volume; + req->dir = dir, req->dotrade = dotrade; + return(exchanges777_submit(exchange,&retstr,req,'T',maxseconds)); +} + +char *exchanges777_Qprices(struct exchange_info *exchange,char *base,char *rel,int32_t maxseconds,int32_t allfields,int32_t invert,int32_t depth,cJSON *argjson) +{ + struct exchange_request *req; char *retstr = 0; + if ( base[0] == 0 || rel[0] == 0 ) + return(clonestr("{\"error\":\"invalid base or rel\"}")); + req = calloc(1,sizeof(*req) + sizeof(*req->bidasks)*depth*2); + req->argjson = argjson; req->retstrp = &retstr; + safecopy(req->base,base,sizeof(req->base)); + safecopy(req->rel,rel,sizeof(req->rel)); + req->depth = depth, req->allflag = allfields, req->invert = invert; + return(exchanges777_submit(exchange,&retstr,req,'Q',maxseconds)); +} + +char *exchanges777_Qrequest(struct exchange_info *exchange,int32_t func,char *base,char *rel,int32_t maxseconds,uint64_t orderid,char *destaddr,double amount,cJSON *argjson) +{ + struct exchange_request *req; char *retstr = 0; + req = calloc(1,sizeof(*req)); + req->volume = amount; + safecopy(req->destaddr,destaddr,sizeof(req->destaddr)); + safecopy(req->base,base,sizeof(req->base)); + safecopy(req->rel,rel,sizeof(req->rel)); + req->orderid = orderid; + return(exchanges777_submit(exchange,&retstr,req,func,maxseconds)); +} + +int32_t exchanges777_id(char *exchangestr) +{ + int32_t i; + for (i=0; i= 0 ) + return(Exchanges[exchangeid]); + return(0); +} + +struct exchange_info *exchange_create(char *exchangestr,cJSON *argjson) +{ + struct exchange_funcs funcs[] = + { + {"truefx", 0 }, {"ecb", 0 }, {"instaforex", 0 }, {"fxcm", 0 }, {"yahoo", 0 }, + poloniex_funcs, bittrex_funcs, btce_funcs, bitfinex_funcs, btc38_funcs, + huobi_funcs, lakebtc_funcs, quadriga_funcs, okcoin_funcs, coinbase_funcs, bitstamp_funcs + }; + char *key,*secret,*userid,*tradepassword; struct exchange_info *exchange; int32_t i,exchangeid; + if ( (exchangeid= exchanges777_id(exchangestr)) < 0 ) + { + printf("exchange_create: cant find.(%s)\n",exchangestr); + return(0); + } + for (i=0; iissue = funcs[i]; + iguana_initQ(&exchange->pricesQ,"prices"); + iguana_initQ(&exchange->requestQ,"request"); + iguana_initQ(&exchange->pendingQ[0],"pending0"); + iguana_initQ(&exchange->pendingQ[1],"pending1"); + exchange->exchangeid = exchangeid; + safecopy(exchange->name,exchangestr,sizeof(exchange->name)); + exchange->pollgap = juint(argjson,"pollgap"); + if ( (key= jstr(argjson,"apikey")) != 0 || (key= jstr(argjson,"key")) != 0 ) + safecopy(exchange->apikey,key,sizeof(exchange->apikey)); + if ( (secret= jstr(argjson,"apisecret")) != 0 || (secret= jstr(argjson,"secret")) != 0 ) + safecopy(exchange->apisecret,secret,sizeof(exchange->apisecret)); + if ( (userid= jstr(argjson,"userid")) != 0 ) + safecopy(exchange->userid,userid,sizeof(exchange->userid)); + if ( (tradepassword= jstr(argjson,"tradepassword")) != 0 ) + safecopy(exchange->tradepassword,tradepassword,sizeof(exchange->tradepassword)); + if ( (exchange->commission= jdouble(argjson,"commission")) > 0. ) + exchange->commission *= .01; + printf("ADDEXCHANGE.(%s) [%s, %s, %s] commission %.3f%%\n",exchangestr,exchange->apikey,exchange->userid,exchange->apisecret,exchange->commission * 100.); + Exchanges[exchangeid] = exchange; + return(exchange); +} + +struct exchange_info *exchanges777_info(char *exchangestr,int32_t sleepflag,cJSON *json) +{ + struct exchange_info *exchange; + if ( (exchange= exchanges777_find(exchangestr)) == 0 ) + { + if ( (exchange= exchange_create(exchangestr,json)) != 0 ) + { + iguana_launch(iguana_coinadd("BTCD"),"exchangeloop",(void *)exchanges777_loop,exchange,IGUANA_EXCHANGETHREAD); + if ( sleepflag > 0 ) + sleep(sleepflag); + } + } + return(exchange); +} + +void exchanges777_init(int32_t sleepflag) +{ + int32_t i; cJSON *argjson = cJSON_CreateObject(); + for (i=0; iapikey,apikey,sizeof(ptr->apikey)); + safecopy(ptr->apisecret,apisecret,sizeof(ptr->apisecret)); + return(clonestr("{\"result\":\"set apikey and apisecret\"}")); + } else return(clonestr("{\"error\":\"need both userid and password\"}")); + } else return(clonestr("{\"error\":\"cant find or create exchange\"}")); +} + +THREE_STRINGS(InstantDEX,setuserid,exchange,userid,tradepassword) +{ + struct exchange_info *ptr; + if ( (ptr= exchanges777_info(exchange,1,json)) != 0 ) + { + safecopy(ptr->userid,userid,sizeof(ptr->userid)); + safecopy(ptr->tradepassword,tradepassword,sizeof(ptr->tradepassword)); + return(clonestr("{\"result\":\"set userid and/or tradepassword\"}")); + } else return(clonestr("{\"error\":\"cant find or create exchange\"}")); +} + +#include "../includes/iguana_apiundefs.h" diff --git a/iguana/iguana_json.c b/iguana/iguana_json.c index 6e414e662..f2f128e76 100755 --- a/iguana/iguana_json.c +++ b/iguana/iguana_json.c @@ -82,6 +82,10 @@ cJSON *SuperNET_helpjson() #define IGUANA_HELP_S(agent,name,str) array = helpjson(IGUANA_ARGS,#agent,#name,helparray(cJSON_CreateArray(),helpitem(#str,"string"))) #define IGUANA_HELP_SS(agent,name,str,str2) array = helpjson(IGUANA_ARGS,#agent,#name,helparray2(cJSON_CreateArray(),helpitem(#str,"string"),helpitem(#str2,"string"))) #define IGUANA_HELP_SSS(agent,name,str,str2,str3) array = helpjson(IGUANA_ARGS,#agent,#name,helparray3(cJSON_CreateArray(),helpitem(#str,"string"),helpitem(#str2,"string"),helpitem(#str3,"string"))) +#define IGUANA_HELP_SSSD(agent,name,str,str2,str3,amount) array = helpjson(IGUANA_ARGS,#agent,#name,helparray4(cJSON_CreateArray(),helpitem(#str,"string"),helpitem(#str2,"string"),helpitem(#str3,"string"),helpitem(#amount,"float"))) +#define IGUANA_HELP_SSSDDD(agent,name,str,str2,str3,amount,val2,val3) array = helpjson(IGUANA_ARGS,#agent,#name,helparray6(cJSON_CreateArray(),helpitem(#str,"string"),helpitem(#str2,"string"),helpitem(#str3,"string"),helpitem(#amount,"float"),helpitem(#val2,"float"),helpitem(#val3,"float"))) +#define IGUANA_HELP_SSSIII(agent,name,str,str2,str3,val,val2,val3) array = helpjson(IGUANA_ARGS,#agent,#name,helparray6(cJSON_CreateArray(),helpitem(#str,"string"),helpitem(#str2,"string"),helpitem(#str3,"string"),helpitem(#val,"int"),helpitem(#val2,"int"),helpitem(#val3,"int"))) + #define IGUANA_HELP_SSH(agent,name,str,str2,hash) array = helpjson(IGUANA_ARGS,#agent,#name,helparray3(cJSON_CreateArray(),helpitem(#str,"string"),helpitem(#str2,"string"),helpitem(#hash,"hash"))) #define IGUANA_HELP_SSHI(agent,name,str,str2,hash,val) array = helpjson(IGUANA_ARGS,#agent,#name,helparray4(cJSON_CreateArray(),helpitem(#str,"string"),helpitem(#str2,"string"),helpitem(#hash,"hash"),helpitem(#val,"int"))) #define IGUANA_HELP_SSHII(agent,name,str,str2,hash,val,val2) array = helpjson(IGUANA_ARGS,#agent,#name,helparray5(cJSON_CreateArray(),helpitem(#str,"string"),helpitem(#str2,"string"),helpitem(#hash,"hash"),helpitem(#val,"int"),helpitem(#val2,"int"))) @@ -153,7 +157,10 @@ cJSON *SuperNET_helpjson() #define HASH_ARG IGUANA_HELP_H #define TWO_HASHES IGUANA_HELP_HH #define HASH_AND_ARRAY IGUANA_HELP_HA - +#define THREE_STRINGS_AND_THREE_INTS IGUANA_HELP_SSSIII +#define THREE_STRINGS_AND_THREE_DOUBLES IGUANA_HELP_SSSDDD +#define THREE_STRINGS_AND_DOUBLE IGUANA_HELP_SSSD + #include "../includes/iguana_apideclares.h" #include "../includes/iguana_apiundefs.h" @@ -324,7 +331,7 @@ int32_t pretty_forms(char *fname,char *agentstr) fprintf(fp,"%s\n",header); if ( (helpjson= SuperNET_helpjson()) != 0 ) { - printf("JSON.(%s)\n",jprint(helpjson,0)); + //printf("JSON.(%s)\n",jprint(helpjson,0)); if ( (array= jarray(&n,helpjson,"API")) != 0 ) { for (i=0; ipossibleQ,queueitem(ipaddr),1); return((uint32_t)time(NULL)); } diff --git a/iguana/index7778.html b/iguana/index7778.html deleted file mode 100644 index 379ce9bfc..000000000 --- a/iguana/index7778.html +++ /dev/null @@ -1,5177 +0,0 @@ - - - - - - - - SuperNET API> - - - - - - - - - - - - - - - - - - - - - - -
- -
- - - - -
- -
-
- -
-
-
-
- - -
- - -
-
-
-
- -
-
-                                    
-                                
-
-
-
-
- -
- -
-
-
- -
- -
-
- -
-
-
- -
-
-
- -
-
-                                    
-                                
-
-
-
-
- -
- -
-
-
- -
- -
-
- -
-
-
-
- - -
- - -
-
-
-
- -
-
-                                    
-                                
-
-
-
-
- -
- -
-
-
- -
- -
-
- -
-
-
- -
-
-
- -
-
-                                    
-                                
-
-
-
-
- -
- -
-
-
- -
- -
-
- -
-
-
-
- - -
-
-
-
- -
-
-                                    
-                                
-
-
-
-
- -
- -
-
-
- -
- -
-
- -
-
-
-
- - -
- - -
-
-
-
- -
-
-                                    
-                                
-
-
-
-
- -
- -
-
-
- -
- -
-
- -
-
-
-
- - -
- - -
- - -
- - -
- - -
- - -
-
-
-
- -
-
-                                    
-                                
-
-
-
-
- -
- -
-
-
- -
- -
-
- -
-
-
-
- - -
- - -
- - -
-
-
-
- -
-
-                                    
-                                
-
-
-
-
- -
- -
-
-
- -
- -
-
- -
-
-
- -
-
-
- -
-
-                                    
-                                
-
-
-
-
- -
- -
-
-
- -
- -
-
- -
-
-
-
- - -
-
-
-
- -
-
-                                    
-                                
-
-
-
-
- -
- -
-
-
- -
- -
-
- -
-
-
-
- - -
- - -
- - -
-
-
-
- -
-
-                                    
-                                
-
-
-
-
- -
- -
-
-
- -
- -
-
- -
-
-
-
- - -
- - -
- - -
-
-
-
- -
-
-                                    
-                                
-
-
-
-
- -
- -
-
-
- -
- -
-
- -
-
-
-
- - -
-
-
-
- -
-
-                                    
-                                
-
-
-
-
- -
- -
-
-
- -
- -
-
- -
-
-
-
- - -
-
-
-
- -
-
-                                    
-                                
-
-
-
-
- -
- -
-
-
- -
- -
-
- -
-
-
-
- - -
- - -
-
-
-
- -
-
-                                    
-                                
-
-
-
-
- -
- -
-
-
- -
- -
-
- -
-
-
-
- - -
- - -
-
-
-
- -
-
-                                    
-                                
-
-
-
-
- -
- -
-
-
- -
- -
-
- -
-
-
-
- - -
- - -
-
-
-
- -
-
-                                    
-                                
-
-
-
-
- -
- -
-
-
- -
- -
-
- -
-
-
-
- - -
- - -
-
-
-
- -
-
-                                    
-                                
-
-
-
-
- -
- -
-
-
- -
- -
-
- -
-
-
-
- - -
- - -
- - -
-
-
-
- -
-
-                                    
-                                
-
-
-
-
- -
- -
-
-
- -
- -
-
- -
-
-
-
- - -
- - -
- - -
-
-
-
- -
-
-                                    
-                                
-
-
-
-
- -
- -
-
-
- -
- -
-
- -
-
-
-
- - -
- - -
- - -
-
-
-
- -
-
-                                    
-                                
-
-
-
-
- -
- -
-
-
- -
- -
-
- -
-
-
-
- - -
- - -
-
-
-
- -
-
-                                    
-                                
-
-
-
-
- -
- -
-
-
- -
- -
-
- -
-
-
-
- - -
- - -
- - -
-
-
-
- -
-
-                                    
-                                
-
-
-
-
- -
- -
-
-
- -
- -
-
- -
-
-
-
- - -
- - -
- - -
-
-
-
- -
-
-                                    
-                                
-
-
-
-
- -
- -
-
-
- -
- -
-
- -
-
-
-
- - -
- - -
- - -
-
-
-
- -
-
-                                    
-                                
-
-
-
-
- -
- -
-
-
- -
- -
-
- -
-
-
-
- - -
-
-
-
- -
-
-                                    
-                                
-
-
-
-
- -
- -
-
-
- -
- -
-
- -
-
-
-
- - -
-
-
-
- -
-
-                                    
-                                
-
-
-
-
- -
- -
-
-
- -
- -
-
- -
-
-
-
- - -
-
-
-
- -
-
-                                    
-                                
-
-
-
-
- -
- -
-
-
- -
- -
-
- -
-
-
-
- - -
- - -
-
-
-
- -
-
-                                    
-                                
-
-
-
-
- -
- -
-
-
- -
- -
-
- -
-
-
- -
-
-
- -
-
-                                    
-                                
-
-
-
-
- -
- -
-
-
- -
- -
-
- -
-
-
-
- - -
- - -
-
-
-
- -
-
-                                    
-                                
-
-
-
-
- -
- -
-
-
- -
- -
-
- -
-
-
-
- - -
- - -
- - -
-
-
-
- -
-
-                                    
-                                
-
-
-
-
- -
- -
-
-
- -
- -
-
- -
-
-
-
- - -
-
-
-
- -
-
-                                    
-                                
-
-
-
-
- -
- -
-
-
- -
- -
-
- -
-
-
-
- - -
- - -
-
-
-
- -
-
-                                    
-                                
-
-
-
-
- -
- -
-
-
- -
- -
-
- -
-
-
-
- - -
-
-
-
- -
-
-                                    
-                                
-
-
-
-
- -
- -
-
-
- -
- -
-
- -
-
-
-
- - -
-
-
-
- -
-
-                                    
-                                
-
-
-
-
- -
- -
-
-
- -
- -
-
- -
-
-
-
- - -
-
-
-
- -
-
-                                    
-                                
-
-
-
-
- -
- -
-
-
- -
- -
-
- -
-
-
-
- - -
-
-
-
- -
-
-                                    
-                                
-
-
-
-
- -
- -
-
-
- -
- -
-
- -
-
-
-
- - -
- - -
-
-
-
- -
-
-                                    
-                                
-
-
-
-
- -
- -
-
-
- -
- -
-
- -
-
-
-
- - -
- - -
-
-
-
- -
-
-                                    
-                                
-
-
-
-
- -
- -
-
-
- -
- -
-
- -
-
-
-
- - -
- - -
-
-
-
- -
-
-                                    
-                                
-
-
-
-
- -
- -
-
-
- -
- -
-
- -
-
-
-
- - -
- - -
-
-
-
- -
-
-                                    
-                                
-
-
-
-
- -
- -
-
-
- -
- -
-
- -
-
-
- -
-
-
- -
-
-                                    
-                                
-
-
-
-
- -
- -
-
-
- -
- -
-
- -
-
-
- -
-
-
- -
-
-                                    
-                                
-
-
-
-
- -
- -
-
-
- -
- -
-
- -
-
-
- -
-
-
- -
-
-                                    
-                                
-
-
-
-
- -
- -
-
-
- -
- -
-
- -
-
-
- -
-
-
- -
-
-                                    
-                                
-
-
-
-
- -
- -
-
-
- -
- -
-
- -
-
-
- -
-
-
- -
-
-                                    
-                                
-
-
-
-
- -
- -
-
-
- -
- -
-
- -
-
-
- -
-
-
- -
-
-                                    
-                                
-
-
-
-
- -
- -
-
-
- -
- -
-
- -
-
-
- -
-
-
- -
-
-                                    
-                                
-
-
-
-
- -
- -
-
-
- -
- -
-
- -
-
-
- -
-
-
- -
-
-                                    
-                                
-
-
-
-
- -
- -
-
-
- -
- -
-
- -
-
-
- -
-
-
- -
-
-                                    
-                                
-
-
-
-
- -
- -
-
-
- -
- -
-
- -
-
-
- -
-
-
- -
-
-                                    
-                                
-
-
-
-
- -
- -
-
-
- -
- -
-
- -
-
-
- -
-
-
- -
-
-                                    
-                                
-
-
-
-
- -
- -
-
-
- -
- -
-
- -
-
-
-
- - -
- - -
-
-
-
- -
-
-                                    
-                                
-
-
-
-
- -
- -
-
-
- -
- -
-
- -
-
-
-
- - -
- - -
- - -
-
-
-
- -
-
-                                    
-                                
-
-
-
-
- -
- -
-
-
- -
- -
-
- -
-
-
-
- - -
- - -
- - -
-
-
-
- -
-
-                                    
-                                
-
-
-
-
- -
- -
-
-
- -
- -
-
- -
-
-
-
- - -
-
-
-
- -
-
-                                    
-                                
-
-
-
-
- -
- -
-
-
- -
- -
-
- -
-
-
-
- - -
-
-
-
- -
-
-                                    
-                                
-
-
-
-
- -
- -
-
-
- -
- -
-
- -
-
-
-
- - -
-
-
-
- -
-
-                                    
-                                
-
-
-
-
- -
- -
-
-
- -
- -
-
- -
-
-
-
- - -
-
-
-
- -
-
-                                    
-                                
-
-
-
-
- -
- -
-
-
- -
- -
-
- -
-
-
-
- - -
-
-
-
- -
-
-                                    
-                                
-
-
-
-
- -
- -
-
-
- -
- -
-
- -
-
-
-
- - -
-
-
-
- -
-
-                                    
-                                
-
-
-
-
- -
- -
-
-
- -
- -
-
- -
-
-
-
- - -
-
-
-
- -
-
-                                    
-                                
-
-
-
-
- -
- -
-
-
- -
- -
-
- -
-
-
-
- - -
-
-
-
- -
-
-                                    
-                                
-
-
-
-
- -
- -
-
-
- -
- -
-
- -
-
-
-
- - -
-
-
-
- -
-
-                                    
-                                
-
-
-
-
- -
- -
-
-
- -
- -
-
- -
-
-
-
- - -
-
-
-
- -
-
-                                    
-                                
-
-
-
-
- -
- -
-
-
- -
- -
-
- -
-
-
-
- - -
-
-
-
- -
-
-                                    
-                                
-
-
-
-
- -
- -
-
-
- -
- -
-
- -
-
-
-
- - -
-
-
-
- -
-
-                                    
-                                
-
-
-
-
- -
- -
-
-
- -
- -
-
- -
-
-
-
- - -
-
-
-
- -
-
-                                    
-                                
-
-
-
-
- -
- -
-
-
- -
- -
-
- -
-
-
-
- - -
- - -
-
-
-
- -
-
-                                    
-                                
-
-
-
-
- -
- -
-
-
- -
- -
-
- -
-
-
-
- - -
- - -
-
-
-
- -
-
-                                    
-                                
-
-
-
-
- -
- -
-
-
- -
- -
-
- -
-
-
-
- - -
- - -
-
-
-
- -
-
-                                    
-                                
-
-
-
-
- -
- -
-
-
- -
- -
-
- -
-
-
-
- - -
- - -
- - -
-
-
-
- -
-
-                                    
-                                
-
-
-
-
- -
- -
-
-
- -
- -
-
- -
-
-
-
- - -
- - -
- - -
-
-
-
- -
-
-                                    
-                                
-
-
-
-
- -
- -
-
-
- -
- -
-
- -
-
-
-
- - -
- - -
- - -
-
-
-
- -
-
-                                    
-                                
-
-
-
-
- -
- -
-
-
- -
- -
-
- -
-
-
-
- - -
- - -
- - -
-
-
-
- -
-
-                                    
-                                
-
-
-
-
- -
- -
-
-
- -
- -
-
- -
-
-
-
- - -
- - -
-
-
-
- -
-
-                                    
-                                
-
-
-
-
- -
- -
-
-
- -
- -
-
- -
-
-
-
- - -
- - -
-
-
-
- -
-
-                                    
-                                
-
-
-
-
- -
- -
-
-
- -
- -
-
- -
-
-
-
- - -
- - -
-
-
-
- -
-
-                                    
-                                
-
-
-
-
- -
- -
-
-
- -
- -
-
- -
-
-
-
- - -
- - -
-
-
-
- -
-
-                                    
-                                
-
-
-
-
- -
- -
-
-
- -
- -
-
- -
-
-
-
- - -
- - -
- - -
-
-
-
- -
-
-                                    
-                                
-
-
-
-
- -
- -
-
-
- -
- -
-
- -
-
-
-
- - -
- - -
-
-
-
- -
-
-                                    
-                                
-
-
-
-
- -
- -
-
-
- -
- -
-
- -
-
-
-
- - -
- - -
- - -
- - -
-
-
-
- -
-
-                                    
-                                
-
-
-
-
- -
- -
-
-
- -
- -
-
- -
-
-
-
- - -
- - -
- - -
-
-
-
- -
-
-                                    
-                                
-
-
-
-
- -
- -
-
-
- -
- -
-
- -
-
-
-
- - -
-
-
-
- -
-
-                                    
-                                
-
-
-
-
- -
- -
-
-
- -
- -
-
- -
-
-
-
- - -
- - -
-
-
-
- -
-
-                                    
-                                
-
-
-
-
- -
- -
-
-
- -
- -
-
- -
-
-
-
- - -
- - -
- - -
-
-
-
- -
-
-                                    
-                                
-
-
-
-
- -
- -
-
-
- -
- -
-
- -
-
-
-
- - -
- - -
-
-
-
- -
-
-                                    
-                                
-
-
-
-
- -
- -
-
-
- -
- -
-
- -
-
-
-
- - -
- - -
- - -
-
-
-
- -
-
-                                    
-                                
-
-
-
-
- -
- -
-
-
- -
- -
-
- -
-
-
-
- - -
- - -
- - -
- - -
- - -
-
-
-
- -
-
-                                    
-                                
-
-
-
-
- -
- -
-
-
- -
- -
-
- -
-
-
-
- - -
- - -
- - -
- - -
- - -
- - -
-
-
-
- -
-
-                                    
-                                
-
-
-
-
- -
- -
-
-
- -
- -
-
- -
-
-
-
- - -
- - -
- - -
- - -
-
-
-
- -
-
-                                    
-                                
-
-
-
-
- -
- -
-
-
- -
- -
-
- -
-
-
-
- - -
- - -
- - -
- - -
-
-
-
- -
-
-                                    
-                                
-
-
-
-
- -
- -
-
-
- -
- -
-
- -
-
-
-
- - -
-
-
-
- -
-
-                                    
-                                
-
-
-
-
- -
- -
-
-
- -
- -
-
- -
-
-
-
- - -
-
-
-
- -
-
-                                    
-                                
-
-
-
-
- -
- -
-
-
- -
- -
-
- -
-
-
-
- - -
- - -
-
-
-
- -
-
-                                    
-                                
-
-
-
-
- -
- -
-
-
- -
- -
-
- -
-
-
-
- - -
-
-
-
- -
-
-                                    
-                                
-
-
-
-
- -
- -
-
-
- -
- -
-
- -
-
-
-
- - -
-
-
-
- -
-
-                                    
-                                
-
-
-
-
- -
- -
-
-
- -
- -
-
- -
-
-
-
- - -
-
-
-
- -
-
-                                    
-                                
-
-
-
-
- -
- -
-
-
- -
- -
-
- -
-
-
-
- - -
-
-
-
- -
-
-                                    
-                                
-
-
-
-
- -
- -
-
-
- -
- -
-
- -
-
-
-
- - -
-
-
-
- -
-
-                                    
-                                
-
-
-
-
- -
- -
-
-
- -
- -
-
- -
-
-
-
- - -
-
-
-
- -
-
-                                    
-                                
-
-
-
-
- -
- -
-
-
- -
- -
-
- -
-
-
-
- - -
-
-
-
- -
-
-                                    
-                                
-
-
-
-
- -
- -
-
-
- -
- -
-
- -
-
-
-
- - -
-
-
-
- -
-
-                                    
-                                
-
-
-
-
- -
- -
-
-
- -
- -
-
- -
-
-
-
- - -
-
-
-
- -
-
-                                    
-                                
-
-
-
-
- -
- -
-
-
- -
- -
-
- -
-
-
-
- - -
-
-
-
- -
-
-                                    
-                                
-
-
-
-
- -
- -
-
-
- -
- -
-
- -
-
-
-
- - -
-
-
-
- -
-
-                                    
-                                
-
-
-
-
- -
- -
-
-
- -
- -
-
- -
-
-
-
- - -
-
-
-
- -
-
-                                    
-                                
-
-
-
-
- -
- -
-
-
- -
- -
-
- -
-
-
-
- - -
-
-
-
- -
-
-                                    
-                                
-
-
-
-
- -
- -
-
-
- -
- -
-
- -
-
-
-
- - -
-
-
-
- -
-
-                                    
-                                
-
-
-
-
- -
- -
-
-
- -
- -
-
- -
-
-
-
- - -
-
-
-
- -
-
-                                    
-                                
-
-
-
-
- -
- -
-
-
- -
- -
-
- -
-
-
-
- - -
-
-
-
- -
-
-                                    
-                                
-
-
-
-
- -
- -
-
-
- -
- -
-
- -
-
-
-
- - -
-
-
-
- -
-
-                                    
-                                
-
-
-
-
- -
- -
-
-
- -
- -
-
- -
-
-
-
- - -
-
-
-
- -
-
-                                    
-                                
-
-
-
-
- -
- -
-
-
- -
- -
-
- -
-
-
-
- - -
-
-
-
- -
-
-                                    
-                                
-
-
-
-
- -
- -
-
-
- -
- -
-
- -
-
-
-
- - -
-
-
-
- -
-
-                                    
-                                
-
-
-
-
- -
- -
-
-
- -
- -
-
- -
-
-
-
- - -
-
-
-
- -
-
-                                    
-                                
-
-
-
-
- -
- -
-
-
- -
- -
-
- -
-
-
-
- - -
- - -
-
-
-
- -
-
-                                    
-                                
-
-
-
-
- -
- -
-
-
- -
- -
-
- -
-
-
-
- - -
- - -
-
-
-
- -
-
-                                    
-                                
-
-
-
-
- -
- -
-
-
- -
- -
-
- -
-
-
-
- - -
- - -
-
-
-
- -
-
-                                    
-                                
-
-
-
-
- -
- -
-
-
- -
- -
-
- -
-
-
-
- - -
- - -
-
-
-
- -
-
-                                    
-                                
-
-
-
-
- -
- -
-
-
- -
- -
-
- -
-
-
-
- - -
- - -
-
-
-
- -
-
-                                    
-                                
-
-
-
-
- -
- -
-
-
- -
- -
-
- -
-
-
-
- - -
- - -
-
-
-
- -
-
-                                    
-                                
-
-
-
-
- -
- -
-
-
- -
- -
-
- -
-
-
-
- - -
- - -
-
-
-
- -
-
-                                    
-                                
-
-
-
-
- -
- -
-
-
- -
- -
-
- -
-
-
-
- - -
- - -
-
-
-
- -
-
-                                    
-                                
-
-
-
-
- -
- -
-
-
- -
- -
-
- -
-
-
-
- - -
- - -
-
-
-
- -
-
-                                    
-                                
-
-
-
-
- -
- -
-
-
- -
- -
-
- -
-
-
-
- - -
- - -
-
-
-
- -
-
-                                    
-                                
-
-
-
-
- -
- -
-
-
- -
- -
-
- -
-
-
-
- - -
- - -
-
-
-
- -
-
-                                    
-                                
-
-
-
-
- -
- -
-
-
- -
- -
-
- -
-
-
-
- - -
- - -
-
-
-
- -
-
-                                    
-                                
-
-
-
-
- -
- -
-
-
- -
- -
-
- -
-
-
-
- - -
- - -
-
-
-
- -
-
-                                    
-                                
-
-
-
-
- -
- -
-
-
- -
- -
-
- -
-
-
-
- - -
- - -
-
-
-
- -
-
-                                    
-                                
-
-
-
-
- -
- -
-
-
-
- -
- - - - - - - - - - diff --git a/iguana/main.c b/iguana/main.c index db9f13ff3..4420e81d3 100644 --- a/iguana/main.c +++ b/iguana/main.c @@ -288,6 +288,7 @@ void iguana_main(void *arg) iguana_chaingenesis(1,1317972665,0x1e0ffff0,2084524493,bits256_conv("97ddfbbae6be97fd6cdf3e7ca13232a3afff2353e29badfab7f73011edd4ced9")); // LTC mycalloc(0,0,0); + //exchanges777_init(0); iguana_initQ(&helperQ,"helperQ"); OS_ensure_directory("confs"); OS_ensure_directory("DB"); @@ -480,7 +481,7 @@ void iguana_main(void *arg) iguana_launch(iguana_coinadd("BTCD"),"rpcloop",iguana_rpcloop,SuperNET_MYINFO(0),IGUANA_PERMTHREAD); if ( coinargs != 0 ) iguana_launch(iguana_coinadd("BTCD"),"iguana_coins",iguana_coins,coinargs,IGUANA_PERMTHREAD); - else if ( 1 ) + else if ( 0 ) { #ifdef __APPLE__ sleep(1); diff --git a/iguana/orderbooks.h b/iguana/orderbooks.h new file mode 100755 index 000000000..e669f6410 --- /dev/null +++ b/iguana/orderbooks.h @@ -0,0 +1,3456 @@ +/****************************************************************************** + * Copyright © 2014-2016 The SuperNET Developers. * + * * + * See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at * + * the top-level directory of this distribution for the individual copyright * + * holder information and the developer policies on copyright and licensing. * + * * + * Unless otherwise agreed in a custom licensing agreement, no part of the * + * SuperNET software, including this file may be copied, modified, propagated * + * or distributed except according to the terms contained in the LICENSE file * + * * + * Removal or modification of this copyright notice is prohibited. * + * * + ******************************************************************************/ + + +#ifndef xcode_orderbooks_h +#define xcode_orderbooks_h + +char *peggy_contracts[64] = +{ + "BTCD", "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", + "BTCUSD", "NXTBTC", "SuperNET", "ETHBTC", "LTCBTC", "XMRBTC", "BTSBTC", "XCPBTC", // BTC priced + "XAUUSD", "XAGUSD", "XPTUSD", "XPDUSD", "Copper", "NGAS", "UKOil", "USOil", // USD priced + "Bund", "NAS100", "SPX500", "US30", "EUSTX50", "UK100", "JPN225", "GER30", "SUI30", "AUS200", "HKG33", "XAUUSD", "BTCRUB", "BTCCNY", "BTCUSD" // abstract +}; + +char *MGWassets[][3] = +{ + { "12659653638116877017", "BTC", "8" }, + { "17554243582654188572", "BTC", "8" }, // assetid, name, decimals + { "4551058913252105307", "BTC", "8" }, + { "6918149200730574743", "BTCD", "4" }, + { "11060861818140490423", "BTCD", "4" }, + { "13120372057981370228", "BITS", "6" }, + { "16344939950195952527", "DOGE", "4" }, + { "2303962892272487643", "DOGE", "4" }, + { "6775076774325697454", "OPAL", "8" }, + { "7734432159113182240", "VPN", "4" }, + { "9037144112883608562", "VRC", "8" }, + { "1369181773544917037", "BBR", "8" }, + { "17353118525598940144", "DRK", "8" }, + { "2881764795164526882", "LTC", "4" }, + { "7117580438310874759", "BC", "4" }, + { "275548135983837356", "VIA", "4" }, + { "6220108297598959542", "CNMT", "0" }, + { "7474435909229872610", "CNMT", "0" }, +}; + +char *Tradedassets[][4] = +{ + { "6220108297598959542", "CNMT", "0", "poloniex" }, + { "7474435909229872610", "CNMT", "0", "poloniex" }, + { "979292558519844732", "MMNXT", "0", "poloniex" }, + { "12982485703607823902", "XUSD", "0", "poloniex" }, + { "13634675574519917918", "INDEX", "0", "poloniex" }, + { "6932037131189568014", "JLH", "0", "poloniex" }, + { "14273984620270850703", "NXTI", "0", "poloniex" }, + { "12071612744977229797", "UNITY", "4", "poloniex" }, +}; + +char *is_tradedasset(char *exchange,char *assetidstr) +{ + int32_t i; + for (i=0; i<(int32_t)(sizeof(Tradedassets)/sizeof(*Tradedassets)); i++) + if ( strcmp(Tradedassets[i][0],assetidstr) == 0 ) + { + strcpy(exchange,Tradedassets[i][3]); + return(Tradedassets[i][1]); + } + return(0); +} + +uint64_t is_MGWcoin(char *name) +{ + int32_t i; + for (i=0; i<(int32_t)(sizeof(MGWassets)/sizeof(*MGWassets)); i++) + if ( strcmp(MGWassets[i][1],name) == 0 ) + return(calc_nxt64bits(MGWassets[i][0])); + return(0); +} + +char *is_MGWasset(uint64_t assetid) +{ + int32_t i; char assetidstr[64]; + expand_nxt64bits(assetidstr,assetid); + for (i=0; i<(int32_t)(sizeof(MGWassets)/sizeof(*MGWassets)); i++) + if ( strcmp(MGWassets[i][0],assetidstr) == 0 ) + return(MGWassets[i][1]); + return(0); +} + +uint64_t prices777_equiv(uint64_t assetid) +{ + char *str; + if ( (str= is_MGWasset(assetid)) != 0 ) + return(stringbits(str)); + return(assetid); +} + +struct prices777 *prices777_find(int32_t *invertedp,uint64_t baseid,uint64_t relid,char *exchange) +{ + int32_t i; struct prices777 *prices; + *invertedp = 0; + for (i=0; iexchange,exchange) == 0 ) + { + //printf("FOUND.(%s)\n",exchange); + if ( prices777_equiv(prices->baseid) == prices777_equiv(baseid) && prices777_equiv(prices->relid) == prices777_equiv(relid) ) + return(prices); + else if ( prices777_equiv(prices->relid) == prices777_equiv(baseid) && prices777_equiv(prices->baseid) == prices777_equiv(relid) ) + { + *invertedp = 1; + return(prices); + } + //else printf("(%llu/%llu) != (%llu/%llu)\n",(long long)baseid,(long long)relid,(long long)prices->baseid,(long long)prices->relid); + } //else fprintf(stderr,"(%s).%d ",prices->exchange,i); + } + //printf("CANTFIND.(%s) %llu/%llu\n",exchange,(long long)baseid,(long long)relid); + return(0); +} + +struct prices777 *prices777_createbasket(int32_t addbasket,char *name,char *base,char *rel,uint64_t baseid,uint64_t relid,struct prices777_basket *basket,int32_t n,char *typestr) +{ + int32_t i,j,m,iter,max = 0; double firstwt,wtsum; struct prices777 *prices,*feature; + printf("createbasket.%s n.%d (%s/%s)\n",typestr,n,base,rel); + prices = prices777_initpair(1,typestr,base,rel,0.,name,baseid,relid,n); + for (iter=0; iter<2; iter++) + { + for (i=0; idependents = realloc(feature->dependents,sizeof(*feature->dependents) * (feature->numdependents + 1)); + feature->dependents[feature->numdependents++] = &prices->changed; + printf("%p i.%d/%d addlink.%s groupid.%d wt.%f (%s.%llu/%llu -> %s.%llu/%llu).%s\n",feature,i,n,feature->exchange,basket[i].groupid,basket[i].wt,feature->contract,(long long)feature->baseid,(long long)feature->relid,prices->contract,(long long)prices->baseid,(long long)prices->relid,prices->exchange); + } + if ( basket[i].groupid > max ) + max = basket[i].groupid; + if ( fabs(basket[i].wt) < SMALLVAL ) + { + printf("all basket features.%s i.%d must have nonzero wt\n",feature->contract,i); + free(prices); + return(0); + } + if ( strcmp(feature->base,feature->rel) == 0 || feature->baseid == feature->relid ) + { + printf("base rel cant be the same (%s %s) %llu %llu\n",feature->base,feature->rel,(long long)feature->baseid,(long long)feature->relid); + free(prices); + return(0); + } + } + if ( (max+1) > MAX_GROUPS ) + { + printf("baskets limited to %d, %d is too many for %s.(%s/%s)\n",MAX_GROUPS,n,name,base,rel); + return(0); + } + } + prices->numgroups = (max + 1); + for (j=0; jnumgroups; j++) + { + for (firstwt=i=m=0; igroupwts[j] = firstwt = basket[i].wt; + else if ( basket[i].wt != firstwt ) + { + printf("warning features of same group.%d different wt: %d %f != %f\n",j,i,firstwt,basket[i].wt); + // free(prices); + // return(0); + } + m++; + } + } + //printf("m.%d\n",m); + for (i=0; ibasketsize,n,j,i,m); + } + for (j=0; jnumgroups; j++) + for (i=0; ibasket[prices->basketsize++] = basket[i]; + for (i=-1; i<=1; i+=2) + { + for (wtsum=j=m=0; jnumgroups; j++) + { + if ( prices->groupwts[j]*i > 0 ) + wtsum += prices->groupwts[j], m++; + } + if ( 0 && wtsum != 0. ) + { + if ( wtsum < 0. ) + wtsum = -wtsum; + for (j=0; jnumgroups; j++) + prices->groupwts[j] /= wtsum; + } + } + if ( prices->numgroups == 1 ) + prices->groupwts[0] = 1.; + for (j=0; jnumgroups; j++) + printf("%9.6f ",prices->groupwts[j]); + printf("groupwts %s\n",typestr); + return(prices); +} + +double prices777_price_volume(double *volumep,uint64_t baseamount,uint64_t relamount) +{ + *volumep = (((double)baseamount + 0.000000009999999) / SATOSHIDEN); + if ( baseamount > 0. ) + return((double)relamount / (double)baseamount); + else return(0.); +} + +void prices777_best_amounts(uint64_t *baseamountp,uint64_t *relamountp,double price,double volume) +{ + double checkprice,checkvol,distA,distB,metric,bestmetric = (1. / SMALLVAL); + uint64_t baseamount,relamount,bestbaseamount = 0,bestrelamount = 0; + int32_t i,j; + baseamount = volume * SATOSHIDEN; + relamount = ((price * volume) * SATOSHIDEN); + //*baseamountp = baseamount, *relamountp = relamount; + //return; + for (i=-1; i<=1; i++) + for (j=-1; j<=1; j++) + { + checkprice = prices777_price_volume(&checkvol,baseamount+i,relamount+j); + distA = (checkprice - price); + distA *= distA; + distB = (checkvol - volume); + distB *= distB; + metric = sqrt(distA + distB); + if ( metric < bestmetric ) + { + bestmetric = metric; + bestbaseamount = baseamount + i; + bestrelamount = relamount + j; + //printf("i.%d j.%d metric. %f\n",i,j,metric); + } + } + *baseamountp = bestbaseamount; + *relamountp = bestrelamount; +} + +void prices777_additem(cJSON **highbidp,cJSON **lowaskp,cJSON *bids,cJSON *asks,int32_t ind,cJSON *item,int32_t bidask) +{ + if ( bidask == 0 ) + { + cJSON_AddItemToArray(bids,item); + if ( ind == 0 ) + *highbidp = item; + } + else + { + cJSON_AddItemToArray(asks,item); + if ( ind == 0 ) + *lowaskp = item; + } +} + +uint64_t calc_qty(uint64_t mult,uint64_t assetid,uint64_t amount) +{ + if ( assetid != NXT_ASSETID ) + return(amount / mult); + else return(amount); +} + +int32_t verify_NXTtx(cJSON *json,uint64_t refasset,uint64_t qty,uint64_t destNXTbits) +{ + int32_t typeval,subtypeval,n = 0; + uint64_t quantity,price,assetidbits; + cJSON *attachmentobj; + char sender[MAX_JSON_FIELD],recipient[MAX_JSON_FIELD],deadline[MAX_JSON_FIELD],feeNQT[MAX_JSON_FIELD],amountNQT[MAX_JSON_FIELD],type[MAX_JSON_FIELD],subtype[MAX_JSON_FIELD],verify[MAX_JSON_FIELD],referencedTransaction[MAX_JSON_FIELD],quantityQNT[MAX_JSON_FIELD],priceNQT[MAX_JSON_FIELD],assetidstr[MAX_JSON_FIELD],sighash[MAX_JSON_FIELD],fullhash[MAX_JSON_FIELD],timestamp[MAX_JSON_FIELD],transaction[MAX_JSON_FIELD]; + if ( json == 0 ) + { + printf("verify_NXTtx cant parse json\n"); + return(-1); + } + if ( extract_cJSON_str(sender,sizeof(sender),json,"sender") > 0 ) n++; + if ( extract_cJSON_str(recipient,sizeof(recipient),json,"recipient") > 0 ) n++; + if ( extract_cJSON_str(referencedTransaction,sizeof(referencedTransaction),json,"referencedTransactionFullHash") > 0 ) n++; + if ( extract_cJSON_str(amountNQT,sizeof(amountNQT),json,"amountNQT") > 0 ) n++; + if ( extract_cJSON_str(feeNQT,sizeof(feeNQT),json,"feeNQT") > 0 ) n++; + if ( extract_cJSON_str(deadline,sizeof(deadline),json,"deadline") > 0 ) n++; + if ( extract_cJSON_str(type,sizeof(type),json,"type") > 0 ) n++; + if ( extract_cJSON_str(subtype,sizeof(subtype),json,"subtype") > 0 ) n++; + if ( extract_cJSON_str(verify,sizeof(verify),json,"verify") > 0 ) n++; + if ( extract_cJSON_str(sighash,sizeof(sighash),json,"signatureHash") > 0 ) n++; + if ( extract_cJSON_str(fullhash,sizeof(fullhash),json,"fullHash") > 0 ) n++; + if ( extract_cJSON_str(timestamp,sizeof(timestamp),json,"timestamp") > 0 ) n++; + if ( extract_cJSON_str(transaction,sizeof(transaction),json,"transaction") > 0 ) n++; + if ( calc_nxt64bits(recipient) != destNXTbits ) + { + if ( Debuglevel > 2 ) + fprintf(stderr,"recipient.%s != %llu\n",recipient,(long long)destNXTbits); + return(-2); + } + typeval = myatoi(type,256), subtypeval = myatoi(subtype,256); + if ( refasset == NXT_ASSETID ) + { + if ( typeval != 0 || subtypeval != 0 ) + { + fprintf(stderr,"unexpected typeval.%d subtypeval.%d\n",typeval,subtypeval); + return(-3); + } + if ( qty != calc_nxt64bits(amountNQT) ) + { + fprintf(stderr,"unexpected qty.%llu vs.%s\n",(long long)qty,amountNQT); + return(-4); + } + return(0); + } + else + { + if ( typeval != 2 || subtypeval != 1 ) + { + if ( Debuglevel > 2 ) + fprintf(stderr,"refasset.%llu qty %lld\n",(long long)refasset,(long long)qty); + return(-11); + } + price = quantity = assetidbits = 0; + attachmentobj = cJSON_GetObjectItem(json,"attachment"); + if ( attachmentobj != 0 ) + { + if ( extract_cJSON_str(assetidstr,sizeof(assetidstr),attachmentobj,"asset") > 0 ) + assetidbits = calc_nxt64bits(assetidstr); + //else if ( extract_cJSON_str(assetidstr,sizeof(assetidstr),attachmentobj,"currency") > 0 ) + // assetidbits = calc_nxt64bits(assetidstr); + if ( extract_cJSON_str(quantityQNT,sizeof(quantityQNT),attachmentobj,"quantityQNT") > 0 ) + quantity = calc_nxt64bits(quantityQNT); + //else if ( extract_cJSON_str(quantityQNT,sizeof(quantityQNT),attachmentobj,"units") > 0 ) + // quantity = calc_nxt64bits(quantityQNT); + if ( extract_cJSON_str(priceNQT,sizeof(priceNQT),attachmentobj,"priceNQT") > 0 ) + price = calc_nxt64bits(priceNQT); + } + if ( assetidbits != refasset ) + { + fprintf(stderr,"assetidbits %llu != %llu refasset\n",(long long)assetidbits,(long long)refasset); + return(-12); + } + if ( qty != quantity ) + { + fprintf(stderr,"qty.%llu != %llu\n",(long long)qty,(long long)quantity); + return(-13); + } + return(0); + } + return(-1); +} + +int32_t InstantDEX_verify(uint64_t destNXTaddr,uint64_t sendasset,uint64_t sendqty,cJSON *txobj,uint64_t recvasset,uint64_t recvqty) +{ + int32_t err; + // verify recipient, amounts in txobj + if ( (err= verify_NXTtx(txobj,recvasset,recvqty,destNXTaddr)) != 0 ) + { + if ( Debuglevel > 2 ) + printf("InstantDEX_verify dest.(%llu) tx mismatch %d (%llu %lld) -> (%llu %lld)\n",(long long)destNXTaddr,err,(long long)sendasset,(long long)sendqty,(long long)recvasset,(long long)recvqty); + return(-1); + } + return(0); +} + +cJSON *wallet_swapjson(char *recv,uint64_t recvasset,char *send,uint64_t sendasset,uint64_t orderid,uint64_t quoteid) +{ + return(cJSON_Parse(clonestr("{\"error\":\"notyet\"}"))); +#ifdef notyet + int32_t iter; uint64_t assetid; struct coin777 *coin; struct InstantDEX_quote *iQ; + char account[128],walletstr[512],*addr,*str; cJSON *walletitem = 0; + printf("wallet_swapjson is not yet\n"); + if ( (iQ= find_iQ(quoteid)) != 0 && iQ->s.wallet != 0 ) + { + walletitem = cJSON_Parse(iQ->walletstr); + //printf("start with (%s)\n",iQ->walletstr); + } + for (iter=0; iter<2; iter++) + { + addr = 0; + str = (iter == 0) ? recv : send; + assetid = (iter == 0) ? recvasset : sendasset; + if ( (coin= coin777_find(str,1)) != 0 ) + { + if ( is_NXT_native(assetid) == 0 ) + { + if ( (walletitem= set_walletstr(walletitem,walletstr,iQ)) != 0 ) + { + + } + } // else printf("%s is NXT\n",coin->name); + if ( is_NXT_native(assetid) != 0 ) + addr = SUPERNET.NXTADDR; + else + { + addr = (iter == 0) ? coin->atomicrecv : coin->atomicsend; + if ( addr[0] == 0 ) + addr = get_acct_coinaddr(addr,str,coin->serverport,coin->userpass,account); + } + if ( addr != 0 ) + { + } else printf("%s no addr\n",coin->name); + } else printf("cant find coin.(%s)\n",iter == 0 ? recv : send); + } + if ( walletitem == 0 ) + walletitem = cJSON_CreateObject(), jaddstr(walletitem,"error","cant find local coin daemons"); + return(walletitem); +#endif +} + +void _prices777_item(cJSON *item,int32_t group,struct prices777 *prices,int32_t bidask,double price,double volume,uint64_t orderid,uint64_t quoteid) +{ + uint64_t baseqty,relqty; int32_t iswallet = 0; char basec,relc; struct InstantDEX_quote *iQ; + jaddnum(item,"group",group); + jaddstr(item,"exchange",prices->exchange); + jaddstr(item,"base",prices->base), jaddstr(item,"rel",prices->rel); + if ( (iQ= find_iQ(quoteid)) != 0 ) + jadd64bits(item,"offerNXT",iQ->s.offerNXT); + if ( strcmp(prices->exchange,"nxtae") == 0 || strcmp(prices->exchange,"unconf") == 0 || strcmp(prices->exchange,"InstantDEX") == 0 || strcmp(prices->exchange,"wallet") == 0 ) + { + jadd64bits(item,prices->type == 5 ? "currency" : "asset",prices->baseid); + //else if ( quoteid != 0 ) printf("cant find offerNXT.%llu\n",(long long)quoteid); + jadd64bits(item,"baseid",prices->baseid), jadd64bits(item,"relid",prices->relid); + iswallet = (strcmp(prices->exchange,"wallet") == 0); + if ( strcmp(prices->exchange,"InstantDEX") == 0 || iswallet != 0 ) + { + jaddstr(item,"trade","swap"); + baseqty = calc_qty(prices->basemult,prices->baseid,SATOSHIDEN * volume + 0.5/SATOSHIDEN); + //printf("baseid.%llu basemult.%llu -> %llu\n",(long long)prices->baseid,(long long)prices->basemult,(long long)baseqty); + relqty = calc_qty(prices->relmult,prices->relid,SATOSHIDEN * volume * price + 0.5/SATOSHIDEN); + if ( bidask != 0 ) + { + basec = '+', relc = '-'; + jadd64bits(item,"recvbase",baseqty); + jadd64bits(item,"sendrel",relqty); + if ( iswallet != 0 ) + jadd(item,"wallet",wallet_swapjson(prices->base,prices->baseid,prices->rel,prices->relid,orderid,quoteid)); + } + else + { + basec = '-', relc = '+'; + jadd64bits(item,"sendbase",baseqty); + jadd64bits(item,"recvrel",relqty); + if ( iswallet != 0 ) + jadd(item,"wallet",wallet_swapjson(prices->rel,prices->relid,prices->base,prices->baseid,orderid,quoteid)); + } + //printf("(%s %cbaseqty.%llu <-> %s %crelqty.%llu) basemult.%llu baseid.%llu vol %f amount %llu\n",prices->base,basec,(long long)baseqty,prices->rel,relc,(long long)relqty,(long long)prices->basemult,(long long)prices->baseid,volume,(long long)volume*SATOSHIDEN); + } + else + { + //printf("alternate path\n"); + jaddstr(item,"trade",bidask == 0 ? "sell" : "buy"); + } + } + else + { + //printf("alternate path\n"); + jaddstr(item,"trade",bidask == 0 ? "sell" : "buy"); + jaddstr(item,"name",prices->contract); + } + jaddnum(item,"orderprice",price); + jaddnum(item,"ordervolume",volume); + if ( orderid != 0 ) + jadd64bits(item,"orderid",orderid); + if ( quoteid != 0 ) + jadd64bits(item,"quoteid",quoteid); +} + +cJSON *prices777_item(int32_t rootbidask,struct prices777 *prices,int32_t group,int32_t bidask,double origprice,double origvolume,double rootwt,double groupwt,double wt,uint64_t orderid,uint64_t quoteid) +{ + cJSON *item; double price,volume,oppo = 1.; + item = cJSON_CreateObject(); + jaddstr(item,"basket",rootbidask == 0 ? "bid":"ask"); + //jaddnum(item,"rootwt",rootwt); + //jaddnum(item,"groupwt",groupwt); + //jaddnum(item,"wt",wt); + if ( wt*groupwt < 0. ) + oppo = -1.; + if ( wt*groupwt < 0 ) + { + volume = origprice * origvolume; + price = 1./origprice; + } else price = origprice, volume = origvolume; + jaddnum(item,"price",price); + jaddnum(item,"volume",volume); + if ( groupwt*wt < 0 ) + { + volume = origprice * origvolume; + price = 1./origprice; + } else price = origprice, volume = origvolume; + _prices777_item(item,group,prices,bidask,price,volume,orderid,quoteid); + return(item); +} + +cJSON *prices777_tradeitem(int32_t rootbidask,struct prices777 *prices,int32_t group,int32_t bidask,int32_t slot,uint32_t timestamp,double price,double volume,double rootwt,double groupwt,double wt,uint64_t orderid,uint64_t quoteid) +{ + static uint32_t match,error; + if ( prices->O.timestamp == timestamp ) + { + //printf("tradeitem.(%s %f %f)\n",prices->exchange,price,volume); + if ( bidask == 0 && prices->O.book[MAX_GROUPS][slot].bid.s.price == price && prices->O.book[MAX_GROUPS][slot].bid.s.vol == volume ) + match++; + else if ( bidask != 0 && prices->O.book[MAX_GROUPS][slot].ask.s.price == price && prices->O.book[MAX_GROUPS][slot].ask.s.vol == volume ) + match++; + } + else if ( prices->O2.timestamp == timestamp ) + { + //printf("2tradeitem.(%s %f %f)\n",prices->exchange,price,volume); + if ( bidask == 0 && prices->O2.book[MAX_GROUPS][slot].bid.s.price == price && prices->O2.book[MAX_GROUPS][slot].bid.s.vol == volume ) + match++; + else if ( bidask != 0 && prices->O2.book[MAX_GROUPS][slot].ask.s.price == price && prices->O2.book[MAX_GROUPS][slot].ask.s.vol == volume ) + match++; + } else error++, printf("mismatched tradeitem error.%d match.%d\n",error,match); + return(prices777_item(rootbidask,prices,group,bidask,price,volume,rootwt,groupwt,wt,orderid,quoteid)); +} + +cJSON *prices777_tradesequence(struct prices777 *prices,int32_t bidask,struct prices777_order *orders[],double rootwt,double groupwt,double wt,int32_t refgroup) +{ + int32_t i,j,srcslot,srcbidask,err = 0; cJSON *array; struct prices777_order *suborders[MAX_GROUPS]; + struct prices777_order *order; struct prices777 *src; + array = cJSON_CreateArray(); + for (i=0; inumgroups; i++) + { + order = orders[i]; + groupwt = prices->groupwts[i]; + memset(suborders,0,sizeof(suborders)); + srcbidask = (order->slot_ba & 1); srcslot = order->slot_ba >> 1; + if ( (src= order->source) != 0 ) + { + if ( src->basketsize == 0 ) + jaddi(array,prices777_tradeitem(bidask,src,refgroup*10+i,srcbidask,srcslot,order->s.timestamp,order->s.price,order->ratio*order->s.vol,rootwt,groupwt/groupwt,order->wt,order->id,order->s.quoteid)); + else if ( src->O.timestamp == order->s.timestamp ) + { + for (j=0; jnumgroups; j++) + suborders[j] = (srcbidask == 0) ? &src->O.book[j][srcslot].bid : &src->O.book[j][srcslot].ask; + jaddi(array,prices777_tradesequence(src,bidask,suborders,rootwt,groupwt/groupwt,order->wt,refgroup*10 + i)); + } + else if ( src->O2.timestamp == order->s.timestamp ) + { + for (j=0; jnumgroups; j++) + suborders[j] = (srcbidask == 0) ? &src->O2.book[j][srcslot].bid : &src->O2.book[j][srcslot].ask; + jaddi(array,prices777_tradesequence(src,bidask,suborders,rootwt,groupwt/groupwt,order->wt,refgroup*10 + i)); + } + else err = 1; + } + if ( src == 0 || err != 0 ) + { + //jaddi(array,prices777_item(prices,bidask,price,volume,wt,orderid)); + //printf("prices777_tradesequence warning cant match timestamp %u (%s %s/%s)\n",order->timestamp,prices->contract,prices->base,prices->rel); + } + } + return(array); +} + +void prices777_orderbook_item(struct prices777 *prices,int32_t bidask,struct prices777_order *suborders[],cJSON *array,int32_t invert,int32_t allflag,double origprice,double origvolume,uint64_t orderid,uint64_t quoteid) +{ + cJSON *item,*obj,*tarray,*walletitem; double price,volume; struct InstantDEX_quote *iQ; + item = cJSON_CreateObject(); + if ( invert != 0 ) + volume = (origvolume * origprice), price = 1./origprice; + else price = origprice, volume = origvolume; + if ( strcmp(prices->exchange,"jumblr") == 0 || strcmp(prices->exchange,"pangea") == 0 ) + { + jaddstr(item,"plugin",prices->exchange), jaddstr(item,"method","start"); + jaddnum(item,"dotrade",1), jaddnum(item,"volume",volume); + jaddnum(item,"timeout",20000); + jaddstr(item,"base",prices->base); + if ( (iQ= find_iQ(quoteid)) != 0 ) + jadd64bits(item,"offerNXT",iQ->s.offerNXT); + jadd64bits(item,"quoteid",iQ->s.quoteid); + if ( strcmp(prices->exchange,"pangea") == 0 && iQ->s.wallet != 0 && (walletitem= cJSON_Parse(iQ->walletstr)) != 0 ) + jadd(item,"wallet",walletitem); + jaddi(array,item); + return; + } + jaddstr(item,"plugin","InstantDEX"), jaddstr(item,"method","tradesequence"); + jaddnum(item,"dotrade",1), jaddnum(item,"price",price), jaddnum(item,"volume",volume); + //jaddnum(item,"invert",invert), jaddnum(item,"origprice",origprice), jaddnum(item,"origvolume",origvolume); + //jaddstr(item,"base",prices->base), jaddstr(item,"rel",prices->rel); + if ( allflag != 0 ) + { + if ( prices->basketsize == 0 ) + { + tarray = cJSON_CreateArray(); + obj = cJSON_CreateObject(); + _prices777_item(obj,0,prices,bidask,origprice,origvolume,orderid,quoteid); + jaddi(tarray,obj); + } else tarray = prices777_tradesequence(prices,bidask,suborders,invert!=0?-1:1.,1.,1.,0); + jadd(item,"trades",tarray); + } + jaddi(array,item); +} + +char *prices777_orderbook_jsonstr(int32_t invert,uint64_t nxt64bits,struct prices777 *prices,struct prices777_basketinfo *OB,int32_t maxdepth,int32_t allflag) +{ + struct prices777_orderentry *gp; struct prices777_order *suborders[MAX_GROUPS]; cJSON *json,*bids,*asks; + int32_t i,slot; char baserel[64],base[64],rel[64],assetA[64],assetB[64],NXTaddr[64]; + if ( invert == 0 ) + sprintf(baserel,"%s/%s",prices->base,prices->rel); + else sprintf(baserel,"%s/%s",prices->rel,prices->base); + if ( Debuglevel > 2 ) + printf("ORDERBOOK %s/%s iQsize.%ld numbids.%d numasks.%d maxdepth.%d (%llu %llu)\n",prices->base,prices->rel,(long)sizeof(struct InstantDEX_quote),OB->numbids,OB->numasks,maxdepth,(long long)prices->baseid,(long long)prices->relid); + json = cJSON_CreateObject(), bids = cJSON_CreateArray(), asks = cJSON_CreateArray(); + gp = &OB->book[MAX_GROUPS][0]; + memset(suborders,0,sizeof(suborders)); + for (slot=0; (slotnumbids || slotnumasks) && slotnumbids ) + { + for (i=0; inumgroups; i++) + suborders[i] = &OB->book[i][slot].bid; + prices777_orderbook_item(prices,0,suborders,(invert==0) ? bids : asks,invert,allflag,gp->bid.s.price,gp->bid.s.vol,gp->bid.id,gp->bid.s.quoteid); + } + if ( slot < OB->numasks ) + { + for (i=0; inumgroups; i++) + suborders[i] = &OB->book[i][slot].ask; + prices777_orderbook_item(prices,1,suborders,(invert==0) ? asks : bids,invert,allflag,gp->ask.s.price,gp->ask.s.vol,gp->ask.id,gp->ask.s.quoteid); + } + } + expand_nxt64bits(NXTaddr,nxt64bits); + if ( invert != 0 ) + strcpy(base,prices->rel), strcpy(rel,prices->base); + else strcpy(base,prices->base), strcpy(rel,prices->rel); + expand_nxt64bits(assetA,invert==0 ? prices->baseid : prices->relid); + expand_nxt64bits(assetB,invert!=0 ? prices->baseid : prices->relid); + cJSON_AddItemToObject(json,"exchange",cJSON_CreateString(prices->exchange)); + cJSON_AddItemToObject(json,"inverted",cJSON_CreateNumber(invert)); + cJSON_AddItemToObject(json,"contract",cJSON_CreateString(prices->contract)); + cJSON_AddItemToObject(json,"baseid",cJSON_CreateString(assetA)); + if ( assetB[0] != 0 ) + cJSON_AddItemToObject(json,"relid",cJSON_CreateString(assetB)); + cJSON_AddItemToObject(json,"base",cJSON_CreateString(base)); + if ( rel[0] != 0 ) + cJSON_AddItemToObject(json,"rel",cJSON_CreateString(rel)); + cJSON_AddItemToObject(json,"bids",bids); + cJSON_AddItemToObject(json,"asks",asks); + if ( invert == 0 ) + { + cJSON_AddItemToObject(json,"numbids",cJSON_CreateNumber(OB->numbids)); + cJSON_AddItemToObject(json,"numasks",cJSON_CreateNumber(OB->numasks)); + cJSON_AddItemToObject(json,"lastbid",cJSON_CreateNumber(prices->lastbid)); + cJSON_AddItemToObject(json,"lastask",cJSON_CreateNumber(prices->lastask)); + } + else + { + cJSON_AddItemToObject(json,"numbids",cJSON_CreateNumber(OB->numasks)); + cJSON_AddItemToObject(json,"numasks",cJSON_CreateNumber(OB->numbids)); + if ( prices->lastask != 0 ) + cJSON_AddItemToObject(json,"lastbid",cJSON_CreateNumber(1. / prices->lastask)); + if ( prices->lastbid != 0 ) + cJSON_AddItemToObject(json,"lastask",cJSON_CreateNumber(1. / prices->lastbid)); + } + cJSON_AddItemToObject(json,"NXT",cJSON_CreateString(NXTaddr)); + cJSON_AddItemToObject(json,"timestamp",cJSON_CreateNumber(time(NULL))); + cJSON_AddItemToObject(json,"maxdepth",cJSON_CreateNumber(maxdepth)); + return(jprint(json,1)); +} + +void prices777_jsonstrs(struct prices777 *prices,struct prices777_basketinfo *OB) +{ + int32_t allflag; char *strs[4]; + if ( OB->numbids == 0 && OB->numasks == 0 ) + { + printf("warning: updating null orderbook ignored for %s (%s/%s)\n",prices->contract,prices->base,prices->rel); + return; + } + for (allflag=0; allflag<4; allflag++) + { + strs[allflag] = prices777_orderbook_jsonstr(allflag/2,IGUANA_MY64BITS,prices,OB,MAX_DEPTH,allflag%2); + if ( Debuglevel > 2 ) + printf("strs[%d].(%s) prices.%p\n",allflag,strs[allflag],prices); + } + portable_mutex_lock(&prices->mutex); + for (allflag=0; allflag<4; allflag++) + { + if ( prices->orderbook_jsonstrs[allflag/2][allflag%2] != 0 ) + free(prices->orderbook_jsonstrs[allflag/2][allflag%2]); + prices->orderbook_jsonstrs[allflag/2][allflag%2] = strs[allflag]; + } + portable_mutex_unlock(&prices->mutex); +} + +char *orderbook_clonestr(struct prices777 *prices,int32_t invert,int32_t allflag) +{ + char *str,*clone = 0; + portable_mutex_lock(&prices->mutex); + if ( (str= prices->orderbook_jsonstrs[invert][allflag]) != 0 ) + clone = clonestr(str); + portable_mutex_unlock(&prices->mutex); + return(clone); +} + +void prices777_json_quotes(double *hblap,struct prices777 *prices,cJSON *bids,cJSON *asks,int32_t maxdepth,char *pricefield,char *volfield,uint32_t reftimestamp) +{ + cJSON *item; int32_t i,slot,n=0,m=0,dir,bidask,numitems; uint64_t orderid,quoteid; uint32_t timestamp; double price,volume,hbla = 0.; + struct prices777_basketinfo OB; struct prices777_orderentry *gp; struct prices777_order *order; + memset(&OB,0,sizeof(OB)); + if ( reftimestamp == 0 ) + reftimestamp = (uint32_t)time(NULL); + OB.timestamp = reftimestamp; + if ( bids != 0 ) + { + n = cJSON_GetArraySize(bids); + if ( maxdepth != 0 && n > maxdepth ) + n = maxdepth; + } + if ( asks != 0 ) + { + m = cJSON_GetArraySize(asks); + if ( maxdepth != 0 && m > maxdepth ) + m = maxdepth; + } + for (i=0; ibid.source = gp->ask.source = prices; + for (bidask=0; bidask<2; bidask++) + { + price = volume = 0.; + orderid = quoteid = 0; + dir = (bidask == 0) ? 1 : -1; + if ( bidask == 0 && i >= n ) + continue; + else if ( bidask == 1 && i >= m ) + continue; + if ( strcmp(prices->exchange,"bter") == 0 && dir < 0 ) + slot = ((bidask==0?n:m) - 1) - i; + else slot = i; + timestamp = 0; + item = jitem(bidask==0?bids:asks,slot); + if ( pricefield != 0 && volfield != 0 ) + price = jdouble(item,pricefield), volume = jdouble(item,volfield); + else if ( is_cJSON_Array(item) != 0 && (numitems= cJSON_GetArraySize(item)) != 0 ) // big assumptions about order within nested array! + { + price = jdouble(jitem(item,0),0), volume = jdouble(jitem(item,1),0); + if ( strcmp(prices->exchange,"kraken") == 0 ) + timestamp = juint(jitem(item,2),0); + else orderid = j64bits(jitem(item,2),0); + } + else continue; + if ( quoteid == 0 ) + quoteid = orderid; + if ( price > SMALLVAL && volume > SMALLVAL ) + { + if ( prices->commission != 0. ) + { + //printf("price %f fee %f -> ",price,prices->commission * price); + if ( bidask == 0 ) + price -= prices->commission * price; + else price += prices->commission * price; + //printf("%f\n",price); + } + order = (bidask == 0) ? &gp->bid : &gp->ask; + order->s.price = price, order->s.vol = volume, order->source = prices, order->s.timestamp = OB.timestamp, order->wt = 1, order->id = orderid, order->s.quoteid = quoteid; + if ( bidask == 0 ) + order->slot_ba = (OB.numbids++ << 1); + else order->slot_ba = (OB.numasks++ << 1) | 1; + if ( i == 0 ) + { + if ( bidask == 0 ) + prices->lastbid = price; + else prices->lastask = price; + if ( hbla == 0. ) + hbla = price; + else hbla = 0.5 * (hbla + price); + } + if ( Debuglevel > 2 )//|| prices->basketsize > 0 || strcmp("unconf",prices->exchange) == 0 ) + printf("%d,%d: %-8s %s %5s/%-5s %13.8f vol %13.8f | invert %13.8f vol %13.8f | timestamp.%u\n",OB.numbids,OB.numasks,prices->exchange,dir>0?"bid":"ask",prices->base,prices->rel,price,volume,1./price,volume*price,timestamp); + } + } + } + if ( hbla != 0. ) + *hblap = hbla; + prices->O2 = prices->O; + //prices->O = OB; + for (i=0; iO.book[i],prices->O.book[i+1],sizeof(prices->O.book[i])); + memcpy(prices->O.book[MAX_GROUPS],OB.book[MAX_GROUPS],sizeof(OB.book[MAX_GROUPS])); + prices->O.numbids = OB.numbids, prices->O.numasks = OB.numasks, prices->O.timestamp = OB.timestamp; +} + +double prices777_json_orderbook(char *exchangestr,struct prices777 *prices,int32_t maxdepth,cJSON *json,char *resultfield,char *bidfield,char *askfield,char *pricefield,char *volfield) +{ + cJSON *obj = 0,*bidobj=0,*askobj=0; double hbla = 0.; int32_t numasks=0,numbids=0; + if ( resultfield == 0 ) + obj = json; + if ( maxdepth == 0 ) + maxdepth = MAX_DEPTH; + if ( resultfield == 0 || (obj= jobj(json,resultfield)) != 0 ) + { + bidobj = jarray(&numbids,obj,bidfield); + askobj = jarray(&numasks,obj,askfield); + if ( bidobj != 0 || askobj != 0 ) + { + prices777_json_quotes(&hbla,prices,bidobj,askobj,maxdepth,pricefield,volfield,0); + prices777_jsonstrs(prices,&prices->O); + } + } + return(hbla); +} + +void prices777_hbla(uint64_t *bidorderid,uint64_t *askorderid,int32_t *lowaski,int32_t *highbidi,double *highbid,double *bidvol,double *lowask,double *askvol,double groupwt,int32_t i,int32_t bidask,double price,double vol,uint64_t orderid) +{ + if ( groupwt > SMALLVAL && (*lowask == 0. || price < *lowask) ) + *askorderid = orderid, *lowask = price, *askvol = vol, *lowaski = (i << 1) | bidask; + else if ( groupwt < -SMALLVAL && (*highbid == 0. || price > *highbid) ) + *bidorderid = orderid, *highbid = price, *bidvol = vol, *highbidi = (i << 1) | bidask; + //printf("hbla.(%f %f)\n",price,vol); +} + +void prices777_setorder(struct prices777_order *order,struct prices777_basket *group,int32_t coordinate,uint64_t orderid,double refprice,double refvol) +{ + int32_t bidask; struct prices777 *prices; double price=0,vol=0; + bidask = (coordinate & 1), coordinate >>= 1; + prices = group[coordinate].prices; + if ( bidask != 0 && group[coordinate].aski < prices->O.numasks ) + price = prices->O.book[MAX_GROUPS][group[coordinate].aski].ask.s.price, vol = prices->O.book[MAX_GROUPS][group[coordinate].aski].ask.s.vol, order->slot_ba = (group[coordinate].aski++ << 1) | 1; + else if ( group[coordinate].bidi < prices->O.numbids ) + price = prices->O.book[MAX_GROUPS][group[coordinate].bidi].bid.s.price, vol = prices->O.book[MAX_GROUPS][group[coordinate].bidi].bid.s.vol,order->slot_ba = (group[coordinate].bidi++ << 1); + else printf("illegal coordinate.%d bidask.%d when bidi.%d aski.%d numbids.%d numasks.%d\n",coordinate,bidask,group[coordinate].bidi,group[coordinate].aski,prices->O.numbids,prices->O.numasks); + order->source = prices; + order->wt = group[coordinate].wt; + order->s.timestamp = prices->O.timestamp; + order->id = orderid; + if ( order->wt < 0. ) + vol *= price, price = (1. / price); + if ( fabs(price - refprice) > SMALLVAL || fabs(vol - refvol) > SMALLVAL ) + { + printf("[ERROR] "); + printf("%s group.%d (%s/%s) bidask.%d coordinate.%d wt %.8f (%.8f %.8f) vs (%.8f %.8f)\n",prices->exchange,group[coordinate].groupid,prices->base,prices->rel,bidask,coordinate,order->wt,price,vol,refprice,refvol); + } +} + + +int32_t prices777_groupbidasks(struct prices777_orderentry *gp,double groupwt,double minvol,struct prices777_basket *group,int32_t groupsize) +{ + int32_t i,highbidi,lowaski; double highbid,lowask,bidvol,askvol,vol,price,polarity; uint64_t bidorderid,askorderid; + struct prices777 *feature; struct prices777_order *order; + memset(gp,0,sizeof(*gp)); + highbidi = lowaski = -1; + for (bidvol=askvol=highbid=lowask=bidorderid=askorderid=i=0; ibase,group[0].rel) == 0 && strcmp(feature->rel,group[0].base) == 0 ) + // polarity = -1.; + //else polarity = 1.; + //if ( group[i].wt * groupwt < 0 ) fixes supernet/BTC + // polarity *= -1; + polarity = group[i].wt;// * groupwt; + order = &feature->O.book[MAX_GROUPS][group[i].bidi].bid; + if ( group[i].bidi < feature->O.numbids && (vol= order->s.vol) > minvol && (price= order->s.price) > SMALLVAL ) + { + //printf("%d/%d: (%s/%s) %s bidi.%d price.%f polarity.%f groupwt.%f -> ",i,groupsize,feature->base,feature->rel,feature->exchange,group[i].bidi,price,polarity,groupwt); + if ( polarity < 0. ) + vol *= price, price = (1. / price); + prices777_hbla(&bidorderid,&askorderid,&lowaski,&highbidi,&highbid,&bidvol,&lowask,&askvol,-polarity,i,0,price,vol,order->id); + } + order = &feature->O.book[MAX_GROUPS][group[i].aski].ask; + if ( group[i].aski < feature->O.numasks && (vol= order->s.vol) > minvol && (price= order->s.price) > SMALLVAL ) + { + //printf("%d/%d: (%s/%s) %s aski.%d price.%f polarity.%f groupwt.%f -> ",i,groupsize,feature->base,feature->rel,feature->exchange,group[i].aski,price,polarity,groupwt); + if ( polarity < 0. ) + vol *= price, price = (1. / price); + prices777_hbla(&bidorderid,&askorderid,&lowaski,&highbidi,&highbid,&bidvol,&lowask,&askvol,polarity,i,1,price,vol,order->id); + } + } else printf("null feature.%p\n",feature); + } + gp->bid.s.price = highbid, gp->bid.s.vol = bidvol, gp->ask.s.price = lowask, gp->ask.s.vol = askvol; + if ( highbidi >= 0 ) + prices777_setorder(&gp->bid,group,highbidi,bidorderid,highbid,bidvol); + if ( lowaski >= 0 ) + prices777_setorder(&gp->ask,group,lowaski,askorderid,lowask,askvol); + // if ( lowaski >= 0 && highbidi >= 0 ) +//printf("groupwt %f groupsize.%d %s highbidi.%d %f %f %s lowaski.%d wts.(%f %f)\n",groupwt,groupsize,gp->bid.source->exchange,highbidi,gp->bid.s.price,gp->ask.s.price,gp->ask.source->exchange,lowaski,gp->bid.wt,gp->ask.wt); + if ( gp->bid.s.price > SMALLVAL && gp->ask.s.price > SMALLVAL ) + return(0); + return(-1); +} + +double prices777_volcalc(double *basevols,uint64_t *baseids,uint64_t baseid,double basevol) +{ + int32_t i; + //printf("(add %llu %f) ",(long long)baseid,basevol); + for (i=0; i 0. ) + { + //printf("(vol %f vs %f) ",vol,basevols[i]); + if ( vol > basevols[i] ) + return(basevols[i]/vol); + else return(1.); + } + printf("unexpected zero vol basevols.%d\n",i); + return(1.); + break; + } + } + printf("unexpected cant find baseid.%llu\n",(long long)baseid); + return(1.); +} + +double prices777_basket(struct prices777 *prices,int32_t maxdepth) +{ + int32_t i,j,groupsize,slot; uint64_t baseids[MAX_GROUPS*2]; + double basevols[MAX_GROUPS*2],relvols[MAX_GROUPS*2],baseratio,relratio,a,av,b,bv,gap,bid,ask,minvol,bidvol,askvol,hbla = 0.; + struct prices777_basketinfo OB; uint32_t timestamp; struct prices777 *feature; struct prices777_orderentry *gp; + a = av = b = bv = 0; + timestamp = (uint32_t)time(NULL); + memset(&OB,0,sizeof(OB)); + memset(baseids,0,sizeof(baseids)); + OB.timestamp = timestamp; + //printf("prices777_basket.(%s) %s (%s/%s) %llu/%llu basketsize.%d\n",prices->exchange,prices->contract,prices->base,prices->rel,(long long)prices->baseid,(long long)prices->relid,prices->basketsize); + for (i=0; ibasketsize; i++) + { + if ( 0 && strcmp(prices->exchange,"active") == 0 && prices->basket[i].prices != 0 ) + printf("%s.group.%d %10s %10s/%10s wt %3.0f %.8f %.8f\n",prices->exchange,i,prices->basket[i].prices->exchange,prices->basket[i].prices->base,prices->basket[i].rel,prices->basket[i].wt,prices->basket[i].prices->O.book[MAX_GROUPS][0].bid.s.price,prices->basket[i].prices->O.book[MAX_GROUPS][0].ask.s.price); + if ( (feature= prices->basket[i].prices) != 0 ) + { + if ( 0 && (gap= (prices->lastupdate - feature->lastupdate)) < 0 ) + { + if ( prices->lastupdate != 0 ) + printf("you can ignore this harmless warning about unexpected time traveling feature %f vs %f or laggy feature\n",prices->lastupdate,feature->lastupdate); + return(0.); + } + } + else + { + printf("unexpected null basket item %s[%d]\n",prices->contract,i); + return(0.); + } + prices->basket[i].aski = prices->basket[i].bidi = 0; + for (j=0; jbasket[i].prices == 0 || prices->basket[i].prices->baseid == baseids[j] ) + break; + if ( baseids[j] == 0 ) + { + baseids[j] = prices->basket[i].prices->baseid; + break; + } + } + for (j=0; jbasket[i].prices == 0 || prices->basket[i].prices->relid == baseids[j] ) + break; + if ( baseids[j] == 0 ) + { + baseids[j] = prices->basket[i].prices->relid; + break; + } + } + } + //printf("%s basketsize.%d numgroups.%d maxdepth.%d group0size.%d\n",prices->contract,prices->basketsize,prices->numgroups,maxdepth,prices->basket[0].groupsize); + for (slot=0; slotbasket[0].groupsize; + minvol = (1. / SATOSHIDEN); + bid = ask = 1.; bidvol = askvol = 0.; + for (j=i=0; jnumgroups; j++,i+=groupsize) + { + groupsize = prices->basket[i].groupsize; + gp = &OB.book[j][slot]; + if ( prices777_groupbidasks(gp,prices->groupwts[j],minvol,&prices->basket[i],groupsize) != 0 ) + { + //printf("prices777_groupbidasks i.%d j.%d error\n",i,j); + break; + } + //printf("%s j%d slot.%d %s numgroups.%d groupsize.%d\n",prices->exchange,j,slot,prices->contract,prices->numgroups,groupsize); + if ( bid > SMALLVAL && (b= gp->bid.s.price) > SMALLVAL && (bv= gp->bid.s.vol) > SMALLVAL ) + { + //if ( gp->bid.wt*prices->groupwts[j] < 0 ) + // bid /= b; + //else + bid *= b; + prices777_volcalc(basevols,baseids,gp->bid.source->baseid,bv); + prices777_volcalc(basevols,baseids,gp->bid.source->relid,b*bv); + //printf("bid %f b %f bv %f %s %s %f\n",bid,b,bv,gp->bid.source->base,gp->bid.source->rel,bv*b); + } else bid = 0.; + if ( ask > SMALLVAL && (a= gp->ask.s.price) > SMALLVAL && (av= gp->ask.s.vol) > SMALLVAL ) + { + //if ( gp->ask.wt*prices->groupwts[j] < 0 ) + // ask /= a; + //else + ask *= a; + prices777_volcalc(relvols,baseids,gp->ask.source->baseid,av); + prices777_volcalc(relvols,baseids,gp->ask.source->relid,a*av); + //printf("ask %f b %f bv %f %s %s %f\n",ask,a,av,gp->ask.source->base,gp->ask.source->rel,av*a); + } else ask = 0.; + if ( Debuglevel > 2 ) + printf("%10s %10s/%10s %s (%s %s) wt:%f %2.0f/%2.0f j.%d: b %.8f %12.6f a %.8f %12.6f, bid %.8f ask %.8f inv %f %f\n",prices->exchange,gp->bid.source->exchange,gp->ask.source->exchange,prices->contract,gp->bid.source->contract,gp->ask.source->contract,prices->groupwts[j],gp->bid.wt,gp->ask.wt,j,b,bv,a,av,bid,ask,1/bid,1/ask); + } + for (j=0; jnumgroups; j++) + { + gp = &OB.book[j][slot]; + if ( gp->bid.source == 0 || gp->ask.source == 0 ) + { + printf("%s: (%s/%s) null source slot.%d j.%d\n",prices->exchange,prices->base,prices->rel,slot,j); + break; + } + baseratio = prices777_volratio(basevols,baseids,gp->bid.source->baseid,gp->bid.s.vol); + relratio = prices777_volratio(basevols,baseids,gp->bid.source->relid,gp->bid.s.vol * gp->bid.s.price); + gp->bid.ratio = (baseratio < relratio) ? baseratio : relratio; + if ( j == 0 ) + bidvol = (gp->bid.ratio * gp->bid.s.vol); + //printf("(%f %f) (%f %f) bid%d bidratio %f bidvol %f ",gp->bid.s.vol,baseratio,gp->bid.s.vol * gp->bid.s.price,relratio,j,gp->bid.ratio,bidvol); + baseratio = prices777_volratio(relvols,baseids,gp->ask.source->baseid,gp->ask.s.vol); + relratio = prices777_volratio(relvols,baseids,gp->ask.source->relid,gp->ask.s.vol * gp->ask.s.price); + gp->ask.ratio = (baseratio < relratio) ? baseratio : relratio; + if ( j == 0 ) + askvol = (gp->ask.ratio * gp->ask.s.vol); + } + if ( j != prices->numgroups ) + { + //printf("%s: j.%d != numgroups.%d\n",prices->exchange,j,prices->numgroups); + break; + } + for (j=0; j SMALLVAL && bidvol > SMALLVAL ) + { + if ( slot == 0 ) + prices->lastbid = bid; + gp->bid.s.timestamp = OB.timestamp, gp->bid.s.price = bid, gp->bid.s.vol = bidvol, gp->bid.slot_ba = (OB.numbids++ << 1); + gp->bid.source = prices, gp->bid.wt = prices->groupwts[j]; + } + if ( ask > SMALLVAL && askvol > SMALLVAL ) + { + if ( slot == 0 ) + prices->lastask = ask; + gp->ask.s.timestamp = OB.timestamp, gp->ask.s.price = ask, gp->ask.s.vol = askvol, gp->ask.slot_ba = (OB.numasks++ << 1) | 1; + gp->ask.source = prices, gp->ask.wt = prices->groupwts[j]; + } + //printf("%s %s slot.%d (%.8f %.6f %.8f %.6f) (%d %d)\n",prices->exchange,prices->contract,slot,gp->bid.s.price,gp->bid.s.vol,gp->ask.s.price,gp->ask.s.vol,OB.numbids,OB.numasks); + } + //fprintf(stderr,"%s basket.%s slot.%d numbids.%d numasks.%d %f %f\n",prices->exchange,prices->contract,slot,prices->O.numbids,prices->O.numasks,prices->O.book[MAX_GROUPS][0].bid.s.price,prices->O.book[MAX_GROUPS][0].ask.s.price); + if ( slot > 0 ) + { + prices->O2 = prices->O; + prices->O = OB; + if ( prices->lastbid > SMALLVAL && prices->lastask > SMALLVAL ) + hbla = 0.5 * (prices->lastbid + prices->lastask); + } + return(hbla); +} + +struct prices777 *prices777_addbundle(int32_t *validp,int32_t loadprices,struct prices777 *prices,char *exchangestr,uint64_t baseid,uint64_t relid) +{ + int32_t j; struct prices777 *ptr; struct exchange_info *exchange; + *validp = -1; + if ( prices != 0 ) + { + exchangestr = prices->exchange; + baseid = prices->baseid, relid = prices->relid; + } + for (j=0; jbaseid == baseid && ptr->relid == relid) || (ptr->relid == baseid && ptr->baseid == relid)) && strcmp(ptr->exchange,exchangestr) == 0 ) + return(ptr); + } + if ( j == BUNDLE.num ) + { + if ( prices != 0 ) + { + exchange = &Exchanges[prices->exchangeid]; + if ( loadprices != 0 && exchange->issue.update != 0 ) + { + portable_mutex_lock(&exchange->mutex); + (exchange->issue.update)(prices,MAX_DEPTH); + portable_mutex_unlock(&exchange->mutex); + } + printf("total polling.%d added.(%s)\n",BUNDLE.num,prices->contract); + if ( exchange->polling == 0 ) + { + printf("First pair for (%s), start polling]\n",exchange_str(prices->exchangeid)); + exchange->polling = 1; + if ( strcmp(exchange->name,"wallet") != 0 )//&& strcmp(exchange->name,"jumblr") != 0 && strcmp(exchange->name,"pangea") != 0 ) + iguana_launch(iguana_coinadd("BTCD"),"exchangeloop",(void *)prices777_exchangeloop,&Exchanges[prices->exchangeid],IGUANA_EXCHANGETHREAD); + } + BUNDLE.ptrs[BUNDLE.num] = prices; + printf("prices777_addbundle.(%s) (%s/%s).%s %llu %llu\n",prices->contract,prices->base,prices->rel,prices->exchange,(long long)prices->baseid,(long long)prices->relid); + BUNDLE.num++; + } else printf("no prices\n"); + *validp = BUNDLE.num; + return(prices); + } + return(0); +} + +int32_t is_native_crypto(char *name,uint64_t bits) +{ + int32_t i,n; + if ( (n= (int32_t)strlen(name)) > 0 || (n= unstringbits(name,bits)) <= 5 ) + { + for (i=0; i= '0' && name[i] <= '9') || (name[i] >= 'A' && name[i] <= 'Z') )// || (name[i] >= '0' && name[i] <= '9') ) + continue; + printf("(%s) is not native crypto\n",name); + return(0); + } + printf("(%s) is native crypto\n",name); + return(1); + } + return(0); +} + +char *_issue_getAsset(char *assetidstr) +{ + char cmd[4096],*jsonstr; + //sprintf(cmd,"requestType=getAsset&asset=%s",assetidstr); + sprintf(cmd,"requestType=getAsset&asset=%s",assetidstr); + //printf("_cmd.(%s)\n",cmd); + jsonstr = issue_NXTPOST(cmd); + //printf("(%s) -> (%s)\n",cmd,jsonstr); + return(jsonstr); +} + +char *_issue_getCurrency(char *assetidstr) +{ + char cmd[4096]; + //sprintf(cmd,"requestType=getAsset&asset=%s",assetidstr); + sprintf(cmd,"requestType=getCurrency¤cy=%s",assetidstr); + //printf("_cmd.(%s)\n",cmd); + return(issue_NXTPOST(cmd)); +} + +int32_t is_mscoin(char *assetidstr) +{ + char *jsonstr; cJSON *json; int32_t retcode = 0; + if ( (jsonstr= _issue_getCurrency(assetidstr)) != 0 ) + { + if ( (json= cJSON_Parse(jsonstr)) != 0 ) + { + if ( get_cJSON_int(json,"errorCode") == 0 ) + retcode = 1; + free_json(json); + } + free(jsonstr); + } + return(retcode); +} + +int32_t get_assetname(char *name,uint64_t assetid) +{ + char assetidstr[64],*jsonstr; cJSON *json; + name[0] = 0; + if ( is_native_crypto(name,assetid) != 0 ) + return((int32_t)strlen(name)); + expand_nxt64bits(assetidstr,assetid); + name[0] = 0; + if ( (jsonstr= _issue_getAsset(assetidstr)) != 0 ) + { + if ( (json= cJSON_Parse(jsonstr)) != 0 ) + { + extract_cJSON_str(name,15,json,"name"); + free_json(json); + } + free(jsonstr); + } + return((int32_t)strlen(assetidstr)); +} + +uint32_t get_blockutime(uint32_t blocknum) +{ + cJSON *json; + uint32_t timestamp = 0; + char cmd[4096],*jsonstr; + sprintf(cmd,"requestType=getBlock&height=%u",blocknum); + if ( (jsonstr= issue_NXTPOST(cmd)) != 0 ) + { + //printf("(%s) -> (%s)\n",cmd,jsonstr); + if ( (json= cJSON_Parse(jsonstr)) != 0 ) + { + if ( (timestamp= juint(json,"timestamp")) != 0 ) + timestamp += NXT_GENESISTIME; + free_json(json); + } + free(jsonstr); + } + return(timestamp); +} + +uint64_t calc_decimals_mult(int32_t decimals) +{ + int32_t i; uint64_t mult = 1; + for (i=7-decimals; i>=0; i--) + mult *= 10; + return(mult); +} + +int32_t _set_assetname(uint64_t *multp,char *buf,char *jsonstr,uint64_t assetid) +{ + int32_t type = 0,decimals = -1; cJSON *json=0; char assetidstr[64],*str; + *multp = 1; + buf[0] = 0; + if ( assetid != 0 ) + { + //fprintf(stderr,"assetid.%llu\n",(long long)assetid); + if ( (str= is_MGWasset(assetid)) != 0 ) + { + strcpy(buf,str); + return(0); + } + if ( is_native_crypto(buf,assetid) != 0 ) + { + unstringbits(buf,assetid); + return(0); + } + } + if ( jsonstr == 0 ) + { + if ( assetid == 0 ) + printf("_set_assetname null assetid\n"), getchar(); + expand_nxt64bits(assetidstr,assetid); + type = 2; + if ( (jsonstr= _issue_getAsset(assetidstr)) != 0 ) + { + //printf("%llu (%s) -> (%s)\n",(long long)assetid,assetidstr,jsonstr); + if ( (json= cJSON_Parse(jsonstr)) != 0 ) + { + if ( get_cJSON_int(json,"errorCode") != 0 ) + { + free_json(json), free(jsonstr); + if ( (jsonstr= _issue_getCurrency(assetidstr)) != 0 ) + { + //printf("(%s) -> (%s)\n",assetidstr,jsonstr); + if ( (json= cJSON_Parse(jsonstr)) != 0 ) + { + if ( get_cJSON_int(json,"errorCode") != 0 ) + { + printf("(%s) not asset and not currency (%s)\n",assetidstr,jsonstr);//, getchar(); + free_json(json), free(jsonstr); + return(-1); + } + type = 5; + } + } + } + } + free(jsonstr), jsonstr = 0; + } else return(-1); + } + if ( multp != 0 ) + *multp = 0; + if ( json == 0 ) + json = cJSON_Parse(jsonstr); + if ( json != 0 ) + { + if ( get_cJSON_int(json,"errorCode") == 0 ) + { + decimals = (int32_t)get_cJSON_int(json,"decimals"); + if ( multp != 0 && decimals >= 0 && decimals <= 8 ) + *multp = calc_decimals_mult(decimals); + if ( extract_cJSON_str(buf,16,json,"name") <= 0 ) + decimals = -1; + //printf("%s decimals.%d (%s)\n",assetidstr,decimals,buf); + } + free_json(json); + } + return(type); +} + +char *peggy_mapname(char *basebuf,char *relbuf,int32_t i) // sorry it is messy thing +{ + char *base,*rel,buf[16]; + base = rel = 0; + strcpy(buf,peggy_contracts[i]); + base = buf, rel = "BTCD"; + if ( strlen(buf) > 3 && strcmp(buf+strlen(buf)-3,"USD") == 0 ) + { + if ( strcmp(buf,"BTCUSD") == 0 ) + base = "BTC"; + buf[strlen(buf)-3] = 0; + } + else if ( strcmp(buf,"Copper") == 0 || strcmp(buf,"NGAS") == 0 || strcmp(buf,"UKOil") == 0 || strcmp(buf,"USOil") == 0 || strcmp(buf,"US30") == 0 || strcmp(buf,"SPX500") == 0 || strcmp(buf,"NAS100") == 0 ) + rel = "USD"; + else if ( strcmp(buf,"Bund") == 0 ) + rel = "yield"; + else if ( strcmp(buf,"EUSTX50") == 0 ) + rel = "EUR"; + else if ( strcmp(buf,"JPN225") == 0 ) + rel = "JPY"; + else if ( strcmp(buf,"UK100") == 0 ) + rel = "GBP"; + else if ( strcmp(buf,"GER30") == 0 ) + rel = "EUR"; + else if ( strcmp(buf,"SUI30") == 0 ) + rel = "CHF"; + else if ( strcmp(buf,"AUS200") == 0 ) + rel = "AUD"; + else if ( strcmp(buf,"HKG33") == 0 ) + rel = "HKD"; + else if ( strlen(buf) > 3 && strcmp(buf+strlen(buf)-3,"BTC") == 0 ) + base = buf, buf[strlen(buf)-3] = 0; + if ( i == sizeof(peggy_contracts)/sizeof(*peggy_contracts)-1 && strcmp(peggy_contracts[i],"BTCUSD") == 0 ) + base = "BTC", rel = "USD"; + else if ( i == sizeof(peggy_contracts)/sizeof(*peggy_contracts)-2 && strcmp(peggy_contracts[i],"BTCCNY") == 0 ) + base = "BTC", rel = "CNY"; + else if ( i == sizeof(peggy_contracts)/sizeof(*peggy_contracts)-3 && strcmp(peggy_contracts[i],"BTCRUB") == 0 ) + base = "BTC", rel = "RUB"; + else if ( i == sizeof(peggy_contracts)/sizeof(*peggy_contracts)-4 && strcmp(peggy_contracts[i],"XAUUSD") == 0 ) + base = "XAU", rel = "USD"; + else if ( i == 0 ) + base = "BTCD", rel = "maincurrency peggy, price is BTCD/BTC for info only"; + basebuf[0] = relbuf[0] = 0; + if ( rel != 0 ) + strcpy(relbuf,rel);//, printf("rel.(%s) ",rel); + if ( base != 0 ) + strcpy(basebuf,base);//, printf("base.(%s) ",base); + return(basebuf); +} + +uint64_t peggy_basebits(char *name) +{ + int32_t i; char basebuf[64],relbuf[64]; + for (i=0; i<64; i++) + { + if ( strcmp(name,peggy_contracts[i]) == 0 ) + { + peggy_mapname(basebuf,relbuf,i); + return(stringbits(basebuf)); + } + } + return(0); +} + +uint64_t peggy_relbits(char *name) +{ + int32_t i; char basebuf[64],relbuf[64]; + for (i=0; i<64; i++) + { + if ( strcmp(name,peggy_contracts[i]) == 0 ) + { + peggy_mapname(basebuf,relbuf,i); + return(stringbits(relbuf)); + } + } + return(0); +} + +int32_t prices777_key(char *key,char *exchange,char *name,char *base,uint64_t baseid,char *rel,uint64_t relid) +{ + int32_t len,keysize = 0; + memcpy(&key[keysize],&baseid,sizeof(baseid)), keysize += sizeof(baseid); + memcpy(&key[keysize],&relid,sizeof(relid)), keysize += sizeof(relid); + strcpy(&key[keysize],exchange), keysize += strlen(exchange) + 1; + strcpy(&key[keysize],name), keysize += strlen(name) + 1; + memcpy(&key[keysize],base,strlen(base)+1), keysize += strlen(base) + 1; + if ( rel != 0 && (len= (int32_t)strlen(rel)) > 0 ) + memcpy(&key[keysize],rel,len+1), keysize += len+1; + return(keysize); +} + +uint64_t InstantDEX_name(char *key,int32_t *keysizep,char *exchange,char *name,char *base,uint64_t *baseidp,char *rel,uint64_t *relidp) +{ + uint64_t baseid,relid,assetbits = 0; char *s,*str; + baseid = *baseidp, relid = *relidp; + //printf(">>>>>> name.(%s) (%s/%s) %llu/%llu\n",name,base,rel,(long long)baseid,(long long)relid); + if ( strcmp(base,"5527630") == 0 || baseid == 5527630 ) + strcpy(base,"NXT"); + if ( strcmp(rel,"5527630") == 0 || relid == 5527630 ) + strcpy(rel,"NXT"); + if ( relid == 0 && rel[0] != 0 ) + { + if ( is_decimalstr(rel) != 0 ) + relid = calc_nxt64bits(rel); + else relid = is_MGWcoin(rel); + } + else if ( (str= is_MGWasset(relid)) != 0 ) + strcpy(rel,str); + if ( baseid == 0 && base[0] != 0 ) + { + if ( is_decimalstr(base) != 0 ) + baseid = calc_nxt64bits(base); + else baseid = is_MGWcoin(base); + } + else if ( (str= is_MGWasset(baseid)) != 0 ) + strcpy(base,str); + if ( strcmp("InstantDEX",exchange) == 0 || strcmp("nxtae",exchange) == 0 || strcmp("unconf",exchange) == 0 || (baseid != 0 && relid != 0) ) + { + if ( strcmp(rel,"NXT") == 0 ) + s = "+", relid = stringbits("NXT"), strcpy(rel,"NXT"); + else if ( strcmp(base,"NXT") == 0 ) + s = "-", baseid = stringbits("NXT"), strcpy(base,"NXT"); + else s = ""; + if ( base[0] == 0 ) + { + get_assetname(base,baseid); + //printf("mapped %llu -> (%s)\n",(long long)baseid,base); + } + if ( rel[0] == 0 ) + { + get_assetname(rel,relid); + //printf("mapped %llu -> (%s)\n",(long long)relid,rel); + } + if ( name[0] == 0 ) + { + if ( relid == NXT_ASSETID ) + sprintf(name,"%llu",(long long)baseid); + else if ( baseid == NXT_ASSETID ) + sprintf(name,"-%llu",(long long)relid); + else sprintf(name,"%llu/%llu",(long long)baseid,(long long)relid); + } + } + else + { + if ( base[0] != 0 && rel[0] != 0 && baseid == 0 && relid == 0 ) + { + baseid = peggy_basebits(base), relid = peggy_basebits(rel); + if ( name[0] == 0 && baseid != 0 && relid != 0 ) + { + strcpy(name,base); // need to be smarter + strcat(name,"/"); + strcat(name,rel); + } + } + if ( name[0] == 0 || baseid == 0 || relid == 0 || base[0] == 0 || rel[0] == 0 ) + { + if ( baseid == 0 && base[0] != 0 ) + baseid = stringbits(base); + else if ( baseid != 0 && base[0] == 0 ) + sprintf(base,"%llu",(long long)baseid); + if ( relid == 0 && rel[0] != 0 ) + { + relid = stringbits(rel); + printf("set relid.%llu <- (%s)\n",(long long)relid,rel); + } + else if ( relid != 0 && rel[0] == 0 ) + sprintf(rel,"%llu",(long long)relid); + if ( name[0] == 0 ) + strcpy(name,base), strcat(name,"/"), strcat(name,rel); + } + } + *baseidp = baseid, *relidp = relid; + *keysizep = prices777_key(key,exchange,name,base,baseid,rel,relid); + //printf("<<<<<<< name.(%s) (%s/%s) %llu/%llu\n",name,base,rel,(long long)baseid,(long long)relid); + return(assetbits); +} + +int32_t create_basketitem(struct prices777_basket *basketitem,cJSON *item,char *refbase,char *refrel,int32_t basketsize) +{ + struct destbuf exchangestr,name,base,rel; char key[512]; uint64_t tmp,baseid,relid; int32_t groupid,keysize,valid; double wt; struct prices777 *prices; + copy_cJSON(&exchangestr,jobj(item,"exchange")); + if ( strcmp("jumblr",exchangestr.buf) == 0 || strcmp("pangea",exchangestr.buf) == 0 || strcmp("wallet",exchangestr.buf) == 0 || exchange_find(exchangestr.buf) == 0 ) + { + printf("create_basketitem: illegal exchange.%s\n",exchangestr.buf); + return(-1); + } + copy_cJSON(&name,jobj(item,"name")); + copy_cJSON(&base,jobj(item,"base")); + copy_cJSON(&rel,jobj(item,"rel")); + if ( (baseid= j64bits(item,"baseid")) != 0 && base.buf[0] == 0 ) + { + _set_assetname(&tmp,base.buf,0,baseid); + //printf("GOT.(%s) <- %llu\n",base.buf,(long long)baseid); + } + else if ( baseid == 0 ) + baseid = stringbits(base.buf); + if ( (relid= j64bits(item,"relid")) != 0 && rel.buf[0] == 0 ) + { + _set_assetname(&tmp,rel.buf,0,relid); + //printf("GOT.(%s) <- %llu\n",rel.buf,(long long)relid); + } + else if ( relid == 0 ) + relid = stringbits(rel.buf); + groupid = juint(item,"group"); + wt = jdouble(item,"wt"); + if ( wt == 0. ) + wt = 1.; + if ( strcmp(refbase,rel.buf) == 0 || strcmp(refrel,base.buf) == 0 ) + { + if ( wt != -1 ) + { + printf("need to flip wt %f for (%s/%s) ref.(%s/%s)\n",wt,base.buf,rel.buf,refbase,refrel); + wt = -1.; + } + } + else if ( wt != 1. ) + { + printf("need to flip wt %f for (%s/%s) ref.(%s/%s)\n",wt,base.buf,rel.buf,refbase,refrel); + wt = 1.; + } + if ( name.buf[0] == 0 ) + sprintf(name.buf,"%s/%s",base.buf,rel.buf); + if ( base.buf[0] == 0 ) + strcpy(base.buf,refbase); + if ( rel.buf[0] == 0 ) + strcpy(rel.buf,refrel); + InstantDEX_name(key,&keysize,exchangestr.buf,name.buf,base.buf,&baseid,rel.buf,&relid); + printf(">>>>>>>>>> create basketitem.(%s) name.(%s) %s (%s/%s) %llu/%llu wt %f\n",jprint(item,0),name.buf,exchangestr.buf,base.buf,rel.buf,(long long)baseid,(long long)relid,wt); + if ( (prices= prices777_initpair(1,exchangestr.buf,base.buf,rel.buf,0.,name.buf,baseid,relid,basketsize)) != 0 ) + { + prices777_addbundle(&valid,0,prices,0,0,0); + basketitem->prices = prices; + basketitem->wt = wt; + basketitem->groupid = groupid; + strcpy(basketitem->base,base.buf); + strcpy(basketitem->rel,rel.buf); + return(0); + } else printf("couldnt create basketitem\n"); + return(-1); +} + +struct prices777 *prices777_makebasket(char *basketstr,cJSON *_basketjson,int32_t addbasket,char *typestr,struct prices777 *ptrs[],int32_t num) +{ + //{"name":"NXT/BTC","base":"NXT","rel":"BTC","basket":[{"exchange":"poloniex"},{"exchange":"btc38"}]} + int32_t i,j,n,keysize,valid,basketsize,total = 0; struct destbuf refname,refbase,refrel; char key[8192]; uint64_t refbaseid=0,refrelid=0; + struct prices777_basket *basketitem,*basket = 0; cJSON *basketjson,*array,*item; struct prices777 *prices = 0; + if ( (basketjson= _basketjson) == 0 && (basketjson= cJSON_Parse(basketstr)) == 0 ) + { + printf("cant parse basketstr.(%s)\n",basketstr); + return(0); + } + copy_cJSON(&refname,jobj(basketjson,"name")); + copy_cJSON(&refbase,jobj(basketjson,"base")); + copy_cJSON(&refrel,jobj(basketjson,"rel")); + refbaseid = j64bits(basketjson,"baseid"); + refrelid = j64bits(basketjson,"relid"); + if ( (array= jarray(&n,basketjson,"basket")) != 0 ) + { + printf("MAKE/(%s) n.%d num.%d\n",jprint(basketjson,0),n,num); + basketsize = (n + num); + basket = calloc(1,sizeof(*basket) * basketsize); + for (i=0; i>>>>>>>>>>> skipped create_basketitem %d of %d of %d\n",i,n,basketsize); + else + { + printf("MAKE.%d: (%s) %p.%s\n",total,jprint(item,0),basket[total].prices,basket[total].prices->exchange); + total++; + } + } + if ( ptrs != 0 && num > 0 ) + { + for (i=0; i 0 ) + { + for (j=0; jprices = ptrs[i]; + if ( strcmp(refbase.buf,ptrs[i]->rel) == 0 || strcmp(refrel.buf,ptrs[i]->base) == 0 ) + basketitem->wt = -1; + else basketitem->wt = 1; + basketitem->groupid = 0; + strcpy(basketitem->base,ptrs[i]->base); + strcpy(basketitem->rel,ptrs[i]->rel); + total++; + printf("extrai.%d/%d total.%d wt.%f (%s/%s).%s\n",i,num,total,basketitem->wt,ptrs[i]->base,ptrs[i]->rel,ptrs[i]->exchange); + } + } + } + printf(">>>>> addbasket.%d (%s/%s).%s %llu %llu\n",addbasket,refbase.buf,refrel.buf,typestr,(long long)refbaseid,(long long)refrelid); + InstantDEX_name(key,&keysize,typestr,refname.buf,refbase.buf,&refbaseid,refrel.buf,&refrelid); + printf(">>>>> addbasket.%d (%s/%s).%s %llu %llu\n",addbasket,refbase.buf,refrel.buf,typestr,(long long)refbaseid,(long long)refrelid); + if ( addbasket != 0 ) + { + prices777_addbundle(&valid,0,0,typestr,refbaseid,refrelid); + printf("<<<<< created.%s valid.%d refname.(%s) (%s/%s).%s %llu %llu\n",typestr,valid,refname.buf,refbase.buf,refrel.buf,typestr,(long long)refbaseid,(long long)refrelid); + } else valid = 0; + if ( valid >= 0 ) + { + if ( (prices= prices777_createbasket(addbasket,refname.buf,refbase.buf,refrel.buf,refbaseid,refrelid,basket,total,typestr)) != 0 ) + { + if ( addbasket != 0 ) + BUNDLE.ptrs[BUNDLE.num] = prices; + prices->lastprice = prices777_basket(prices,MAX_DEPTH); + //printf("C.bsize.%d total polling.%d added.(%s/%s).%s updating basket lastprice %f changed.%p %d groupsize.%d numgroups.%d %p\n",total,BUNDLE.num,prices->base,prices->rel,prices->exchange,prices->lastprice,&prices->changed,prices->changed,prices->basket[0].groupsize,prices->numgroups,&prices->basket[0].groupsize); + BUNDLE.num++; + } + } else prices = 0; + if ( basketjson != _basketjson ) + free_json(basketjson); + free(basket); + } + return(prices); +} + +cJSON *inner_json(double price,double vol,uint32_t timestamp,uint64_t quoteid,uint64_t nxt64bits,uint64_t qty,uint64_t pqt,uint64_t baseamount,uint64_t relamount) +{ + cJSON *inner = cJSON_CreateArray(); + char numstr[64]; + sprintf(numstr,"%.8f",price), cJSON_AddItemToArray(inner,cJSON_CreateString(numstr)); + sprintf(numstr,"%.8f",vol), cJSON_AddItemToArray(inner,cJSON_CreateString(numstr)); + sprintf(numstr,"%llu",(long long)quoteid), cJSON_AddItemToArray(inner,cJSON_CreateString(numstr)); + cJSON_AddItemToArray(inner,cJSON_CreateNumber(timestamp)); + sprintf(numstr,"%llu",(long long)nxt64bits), cJSON_AddItemToArray(inner,cJSON_CreateString(numstr)); + sprintf(numstr,"%llu",(long long)qty), cJSON_AddItemToArray(inner,cJSON_CreateString(numstr)); + sprintf(numstr,"%llu",(long long)pqt), cJSON_AddItemToArray(inner,cJSON_CreateString(numstr)); + sprintf(numstr,"%llu",(long long)baseamount), cJSON_AddItemToArray(inner,cJSON_CreateString(numstr)); + sprintf(numstr,"%llu",(long long)relamount), cJSON_AddItemToArray(inner,cJSON_CreateString(numstr)); + // printf("(%s) ",jprint(inner,0)); + return(inner); +} + +double prices777_NXT(struct prices777 *prices,int32_t maxdepth) +{ + uint32_t timestamp; int32_t flip,i,n; uint64_t baseamount,relamount,qty,pqt; char url[1024],*str,*cmd,*field; + cJSON *json,*bids,*asks,*srcobj,*item,*array; double price,vol,hbla = 0.; + if ( NXT_ASSETID != stringbits("NXT") || (strcmp(prices->rel,"NXT") != 0 && strcmp(prices->rel,"5527630") != 0) ) + { + printf("NXT_ASSETID.%llu != %llu stringbits rel.%s\n",(long long)NXT_ASSETID,(long long)stringbits("NXT"),prices->rel);//, getchar(); + return(0); + } + bids = cJSON_CreateArray(), asks = cJSON_CreateArray(); + for (flip=0; flip<2; flip++) + { + /*{ + "offer": "16959774565785265980", + "expirationHeight": 1000000, + "accountRS": "NXT-QFAF-GR4F-RBSR-AXW2G", + "limit": "9000000", + "currency": "5775213290661997199", + "supply": "0", + "account": "9728792749189838093", + "height": 348856, + "rateNQT": "650" + }*/ + if ( prices->type != 5 ) + { + if ( flip == 0 ) + cmd = "getBidOrders", field = "bidOrders", array = bids; + else cmd = "getAskOrders", field = "askOrders", array = asks; + sprintf(url,"requestType=%s&asset=%llu&limit=%d",cmd,(long long)prices->baseid,maxdepth); + } + else + { + if ( flip == 0 ) + cmd = "getBuyOffers", field = "offers", array = bids; + else cmd = "getSellOffers", field = "offers", array = asks; + sprintf(url,"requestType=%s¤cy=%llu&limit=%d",cmd,(long long)prices->baseid,maxdepth); + } + if ( (str= issue_NXTPOST(url)) != 0 ) + { + //printf("{%s}\n",str); + if ( (json= cJSON_Parse(str)) != 0 ) + { + if ( (srcobj= jarray(&n,json,field)) != 0 ) + { + for (i=0; itype != 5 ) + qty = j64bits(item,"quantityQNT"), pqt = j64bits(item,"priceNQT"); + else qty = j64bits(item,"limit"), pqt = j64bits(item,"rateNQT"); + baseamount = (qty * prices->ap_mult), relamount = (qty * pqt); + price = prices777_price_volume(&vol,baseamount,relamount); + if ( i == 0 ) + { + hbla = (hbla == 0.) ? price : 0.5 * (price + hbla); + if ( flip == 0 ) + prices->lastbid = price; + else prices->lastask = price; + } + //printf("(%llu %llu) %f %f mult.%llu qty.%llu pqt.%llu baseamount.%lld relamount.%lld\n",(long long)prices->baseid,(long long)prices->relid,price,vol,(long long)prices->ap_mult,(long long)qty,(long long)pqt,(long long)baseamount,(long long)relamount); + timestamp = get_blockutime(juint(item,"height")); + item = inner_json(price,vol,timestamp,j64bits(item,prices->type != 5 ? "order" : "offer"),j64bits(item,"account"),qty,pqt,baseamount,relamount); + cJSON_AddItemToArray(array,item); + } + } + free_json(json); + } + free(str); + } else printf("cant get.(%s)\n",url); + } + json = cJSON_CreateObject(); + cJSON_AddItemToObject(json,"bids",bids); + cJSON_AddItemToObject(json,"asks",asks); + if ( Debuglevel > 2 ) + printf("NXTAE.(%s)\n",jprint(json,0)); + prices777_json_orderbook("nxtae",prices,maxdepth,json,0,"bids","asks",0,0); + free_json(json); + return(hbla); +} + +double prices777_unconfNXT(struct prices777 *prices,int32_t maxdepth) +{ + struct destbuf account,txidstr,comment,recipient; char url[1024],*str; uint32_t timestamp; int32_t type,i,subtype,n; + cJSON *json,*bids,*asks,*array,*txobj,*attachment; + double price,vol; uint64_t assetid,accountid,quoteid,baseamount,relamount,qty,priceNQT,amount; + bids = cJSON_CreateArray(), asks = cJSON_CreateArray(); + prices->lastbid = prices->lastask = 0.; + prices->O.numbids = prices->O.numasks = 0; + sprintf(url,"requestType=getUnconfirmedTransactions"); + if ( IGUANA_disableNXT == 0 && (str= issue_NXTPOST(url)) != 0 ) + { + //printf("{%s}\n",str); + if ( (json= cJSON_Parse(str)) != 0 ) + { + if ( (array= jarray(&n,json,"unconfirmedTransactions")) != 0 ) + { + for (i=0; iap_mult), relamount = (qty * priceNQT); + copy_cJSON(&comment,jobj(attachment,"message")); + if ( comment.buf[0] != 0 ) + { + int32_t match_unconfirmed(char *sender,char *hexstr,cJSON *txobj,char *txidstr,char *account,uint64_t amount,uint64_t qty,uint64_t assetid,char *recipient); + //printf("sender.%s -> recv.(%s)\n",account,recipient); + match_unconfirmed(account.buf,comment.buf,txobj,txidstr.buf,account.buf,amount,qty,assetid,recipient.buf); + } + quoteid = calc_nxt64bits(txidstr.buf); + price = prices777_price_volume(&vol,baseamount,relamount); + if ( prices->baseid == assetid ) + { + if ( Debuglevel > 2 ) + printf("unconf.%d subtype.%d %s %llu (%llu %llu) %f %f mult.%llu qty.%llu pqt.%llu baseamount.%lld relamount.%lld\n",i,subtype,txidstr.buf,(long long)prices->baseid,(long long)assetid,(long long)NXT_ASSETID,price,vol,(long long)prices->ap_mult,(long long)qty,(long long)priceNQT,(long long)baseamount,(long long)relamount); + if ( subtype == 2 ) + { + array = bids; + prices->lastbid = price; + } + else if ( subtype == 3 ) + { + array = asks; + prices->lastask = price; + } + cJSON_AddItemToArray(array,inner_json(price,vol,timestamp,quoteid,accountid,qty,priceNQT,baseamount,relamount)); + } + } + } + free_json(json); + } + free(str); + } else printf("cant get.(%s)\n",url); + } + json = cJSON_CreateObject(); + cJSON_AddItemToObject(json,"bids",bids); + cJSON_AddItemToObject(json,"asks",asks); + prices777_json_orderbook("unconf",prices,maxdepth,json,0,"bids","asks",0,0); + if ( Debuglevel > 2 )//|| prices->O.numbids != 0 || prices->O.numasks != 0 ) + printf("%s %s/%s unconf.(%s) %f %f (%d %d)\n",prices->contract,prices->base,prices->rel,jprint(json,0),prices->lastbid,prices->lastask,prices->O.numbids,prices->O.numasks); + free_json(json); + return(_pairaved(prices->lastbid,prices->lastask)); +} + +double prices777_InstantDEX(struct prices777 *prices,int32_t maxdepth) +{ + cJSON *json; double hbla = 0.; + if ( (json= InstantDEX_orderbook(prices)) != 0 ) // strcmp(prices->exchange,INSTANTDEX_NAME) == 0 && + { + if ( Debuglevel > 2 ) + printf("InstantDEX.(%s)\n",jprint(json,0)); + prices777_json_orderbook("InstantDEX",prices,maxdepth,json,0,"bids","asks",0,0); + free_json(json); + } + return(hbla); +} + +#define BASE_ISNXT 1 +#define BASE_ISASSET 2 +#define BASE_ISNAME 4 +#define BASE_ISMGW 8 +#define BASE_EXCHANGEASSET 16 + +int32_t calc_baseflags(char *exchange,char *base,uint64_t *baseidp) +{ + char assetidstr[64],tmpstr[64],*str; uint64_t tmp; int32_t flags = 0; + exchange[0] = 0; + printf("calc_baseflags.(%s/%llu) ",base,(long long)*baseidp); + if ( strcmp(base,"NXT") == 0 || *baseidp == NXT_ASSETID ) + strcpy(base,"NXT"), *baseidp = NXT_ASSETID, flags |= BASE_ISNXT; + else + { + if ( *baseidp == 0 ) + { + if ( is_decimalstr(base) != 0 ) + { + *baseidp = calc_nxt64bits(base), flags |= BASE_ISASSET; + unstringbits(tmpstr,*baseidp); + if ( (tmp= is_MGWcoin(tmpstr)) != 0 ) + *baseidp = tmp, flags |= (BASE_EXCHANGEASSET | BASE_ISMGW); + else + { + printf("set base.(%s) -> %llu\n",base,(long long)*baseidp); + if ( (str= is_MGWasset(*baseidp)) != 0 ) + strcpy(base,str), flags |= (BASE_EXCHANGEASSET | BASE_ISMGW); + } + } + else + { + *baseidp = stringbits(base), flags |= BASE_ISNAME; + printf("stringbits.(%s) -> %llu\n",base,(long long)*baseidp); + } + } + else + { + if ( (str= is_MGWasset(*baseidp)) != 0 ) + { + printf("is MGWasset.(%s)\n",str); + strcpy(base,str), flags |= (BASE_EXCHANGEASSET | BASE_ISMGW | BASE_ISASSET); + } + else + { + expand_nxt64bits(assetidstr,*baseidp); + if ( (str= is_tradedasset(exchange,assetidstr)) != 0 ) + { + strcpy(base,str), flags |= (BASE_EXCHANGEASSET | BASE_ISASSET); + printf("%s is tradedasset at (%s) %llu\n",assetidstr,str,(long long)*baseidp); + } + else + { + unstringbits(tmpstr,*baseidp); + if ( (tmp= is_MGWcoin(tmpstr)) != 0 ) + strcpy(base,tmpstr), *baseidp = tmp, flags |= (BASE_EXCHANGEASSET | BASE_ISMGW | BASE_ISASSET); + else + { + _set_assetname(&tmp,base,0,*baseidp), flags |= BASE_ISASSET; + printf("_set_assetname.(%s) from %llu\n",base,(long long)*baseidp); + } + } + } + } + if ( (flags & (BASE_ISASSET|BASE_EXCHANGEASSET|BASE_ISMGW)) == 0 ) + *baseidp = stringbits(base); + } + printf("-> flags.%d (%s %llu) %s\n",flags,base,(long long)*baseidp,exchange); + return(flags); +} + +void setitemjson(cJSON *item,char *name,char *base,uint64_t baseid,char *rel,uint64_t relid) +{ + char numstr[64]; + jaddstr(item,"name",name), jaddstr(item,"base",base), jaddstr(item,"rel",rel); + sprintf(numstr,"%llu",(long long)baseid), jaddstr(item,"baseid",numstr); + sprintf(numstr,"%llu",(long long)relid), jaddstr(item,"relid",numstr); +} + +int32_t nxt_basketjson(cJSON *array,int32_t groupid,int32_t polarity,char *base,uint64_t baseid,char *rel,uint64_t relid,char *refbase,char *refrel) +{ + cJSON *item,*item2,*item3; char name[64]; int32_t dir = 0; + item = cJSON_CreateObject(), jaddstr(item,"exchange",INSTANTDEX_NXTAENAME); + item2 = cJSON_CreateObject(), jaddstr(item2,"exchange",INSTANTDEX_NXTAEUNCONF); + item3 = cJSON_CreateObject(), jaddstr(item3,"exchange",INSTANTDEX_NAME); + if ( strcmp(base,"NXT") == 0 ) + { + sprintf(name,"%s/%s",rel,"NXT"); + setitemjson(item,name,rel,relid,"NXT",NXT_ASSETID); + setitemjson(item2,name,rel,relid,"NXT",NXT_ASSETID); + setitemjson(item3,name,rel,relid,"NXT",NXT_ASSETID); + } + else if ( strcmp(rel,"NXT") == 0 ) + { + sprintf(name,"%s/%s",base,"NXT"); + setitemjson(item,name,base,baseid,"NXT",NXT_ASSETID); + setitemjson(item2,name,base,baseid,"NXT",NXT_ASSETID); + setitemjson(item3,name,base,baseid,"NXT",NXT_ASSETID); + } + else + { + free_json(item); + free_json(item2); + free_json(item3); + return(0); + } + if ( strcmp(refbase,rel) == 0 || strcmp(refrel,base) == 0 ) + dir = -1; + else dir = 1; + jaddnum(item,"wt",dir), jaddnum(item2,"wt",dir), jaddnum(item3,"wt",dir); + jaddnum(item,"group",groupid), jaddnum(item2,"group",groupid), jaddnum(item3,"group",groupid); + printf("nxt_basketjson (%s/%s) %llu/%llu ref.(%s/%s) dir.%d polarity.%d\n",base,rel,(long long)baseid,(long long)relid,refbase,refrel,dir,polarity); + jaddi(array,item), jaddi(array,item2), jaddi(array,item3); + return(dir * polarity); +} + +void add_nxtbtc(cJSON *array,int32_t groupid,double wt) +{ + char *btcnxt_xchgs[] = { "poloniex", "bittrex", "btc38" }; + int32_t i; cJSON *item; + if ( wt != 0 ) + { + printf("add NXT/BTC\n"); + for (i=0; i 0 && centralexchange_items(0,1,0,rel,coinstr,tradeable,base,rel) > 0 ) + { + array = cJSON_CreateArray(); + printf("add central jumper.(%s) for (%s/%s)\n",coinstr,base,rel); + centralexchange_items(0,1,array,base,coinstr,tradeable,base,rel); + centralexchange_items(1,-1,array,rel,coinstr,tradeable,base,rel); + } + } + return(array); +} + +int32_t make_subactive(struct prices777 *baskets[],int32_t n,cJSON *array,char *prefix,char *base,char *rel,uint64_t baseid,uint64_t relid,int32_t maxdepth) +{ + char tmpstr[64],typestr[64]; struct prices777 *basket; cJSON *basketjson; + basketjson = cJSON_CreateObject(); + sprintf(tmpstr,"%s/%s",base,rel); + setitemjson(basketjson,tmpstr,base,baseid,rel,relid); + jadd(basketjson,"basket",array); + printf("%s BASKETMAKE.(%s)\n",prefix,jprint(basketjson,0)); + sprintf(typestr,"basket%s",prefix); + if ( (basket= prices777_makebasket(0,basketjson,1,typestr,0,0)) != 0 ) + { + prices777_basket(basket,maxdepth); + prices777_jsonstrs(basket,&basket->O); + printf("add to baskets[%d].%s (%s/%s) (%s)\n",n,basket->exchange,basket->base,basket->rel,basket->contract); + baskets[n++] = basket; + } + free_json(basketjson); + return(n); +} + +char *prices777_activebooks(char *name,char *_base,char *_rel,uint64_t baseid,uint64_t relid,int32_t maxdepth,int32_t allflag,int32_t tradeable) +{ + cJSON *array,*arrayNXT,*arrayBTC,*arrayUSD,*arrayCNY,*basketjson; struct prices777 *active,*basket,*baskets[64]; + int32_t inverted,keysize,baseflags,relflags,n = 0; char tmpstr[64],base[64],rel[64],bexchange[64],rexchange[64],key[512],*retstr = 0; + memset(baskets,0,sizeof(baskets)); + strcpy(base,_base), strcpy(rel,_rel); + baseflags = calc_baseflags(bexchange,base,&baseid); + relflags = calc_baseflags(rexchange,rel,&relid); + InstantDEX_name(key,&keysize,"active",name,base,&baseid,rel,&relid); + printf("activebooks (%s/%s) (%llu/%llu)\n",base,rel,(long long)baseid,(long long)relid); + if ( (active= prices777_find(&inverted,baseid,relid,"active")) == 0 ) + { + if ( ((baseflags & BASE_ISMGW) != 0 || (baseflags & BASE_ISASSET) == 0) && ((relflags & BASE_ISMGW) != 0 || (relflags & BASE_ISASSET) == 0) ) + { + if ( (arrayUSD= external_combo(base,rel,"USD",tradeable)) != 0 ) + n = make_subactive(baskets,n,arrayUSD,"USD",base,rel,baseid,relid,maxdepth); + if ( (arrayCNY= external_combo(base,rel,"CNY",tradeable)) != 0 ) + n = make_subactive(baskets,n,arrayCNY,"CNY",base,rel,baseid,relid,maxdepth); + } + arrayBTC = external_combo(base,rel,"BTC",tradeable); + basketjson = cJSON_CreateObject(), array = cJSON_CreateArray(); + sprintf(tmpstr,"%s/%s",base,rel); + setitemjson(basketjson,tmpstr,base,baseid,rel,relid); + //if ( baseflags != BASE_ISASSET && relflags != BASE_ISASSET ) + centralexchange_items(0,1,array,base,rel,tradeable,base,rel); + if ( (arrayNXT= make_arrayNXT(array,&arrayBTC,base,rel,baseid,relid)) != 0 ) + n = make_subactive(baskets,n,arrayNXT,"NXT",base,rel,baseid,relid,maxdepth); + if ( arrayBTC != 0 ) + n = make_subactive(baskets,n,arrayBTC,"BTC",base,rel,baseid,relid,maxdepth); + if ( (basket= prices777_find(&inverted,baseid,relid,"basket")) != 0 ) + baskets[n++] = basket; + jadd(basketjson,"basket",array); + printf(" ACTIVE MAKE.(%s)\n",jprint(basketjson,0)); + if ( (active= prices777_makebasket(0,basketjson,1,"active",baskets,n)) != 0 ) + { + prices777_basket(active,maxdepth); + prices777_jsonstrs(active,&active->O); + } + free_json(array); + } + if ( active != 0 && retstr == 0 ) + { + prices777_basket(active,maxdepth); + prices777_jsonstrs(active,&active->O); + if ( (retstr= active->orderbook_jsonstrs[inverted][allflag]) != 0 ) + retstr = clonestr(retstr); + } + if ( retstr == 0 ) + retstr = clonestr("{\"error\":\"null active orderbook\"}"); + return(retstr); +} + +cJSON *basketitem_json(struct prices777 *prices) +{ + int32_t i; char numstr[64]; cJSON *json,*array,*item; + json = cJSON_CreateObject(); + if ( prices != 0 ) + { + jaddstr(json,"exchange",prices->exchange); + jaddstr(json,"name",prices->contract); + jaddstr(json,"base",prices->base); + sprintf(numstr,"%llu",(long long)prices->baseid), jaddstr(json,"baseid",numstr); + jaddstr(json,"rel",prices->rel); + sprintf(numstr,"%llu",(long long)prices->relid), jaddstr(json,"relid",numstr); + jaddnum(json,"commission",prices->commission); + if ( prices->basketsize != 0 ) + { + array = cJSON_CreateArray(); + for (i=0; ibasketsize; i++) + { + item = basketitem_json(prices->basket[i].prices); + if ( prices->basket[i].groupsize != 0 ) + jaddnum(item,"groupsize",prices->basket[i].groupsize); + jaddnum(item,"group",prices->basket[i].groupid); + jaddnum(item,"wt",prices->basket[i].wt); + jaddi(array,item); + } + jadd(json,"basket",array); + } + } + return(json); +} + +char *prices777_allorderbooks() +{ + int32_t i; cJSON *json,*array = cJSON_CreateArray(); + for (i=0; iissue = 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; iexchange,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; iissue = 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; inumdependents; 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; idisabled == 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; idisabled == 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; ipollgap = 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; irefcount > 0 || strcmp(exchangeptr->name,"unconf") == 0) )//&& strcmp(exchangeptr->name,"pangea") != 0 && strcmp(exchangeptr->name,"jumblr") != 0 ) + iguana_launch(iguana_coinadd("BTCD"),"exchangeloop",(void *)prices777_exchangeloop,exchangeptr,IGUANA_EXCHANGETHREAD); + } + 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); +} + +void prices777_btcprices(int32_t enddatenum,int32_t numdates) +{ + 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¤cyPair=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 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 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 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 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 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¤cyPair=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¤cyPair=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; ilbase,"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" : "zł"}, + "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¤cyPair=BTC_BTCD&start=1405699200&end=9999999999&period=86400 + + // https://poloniex.com/public?command=returnTradeHistory¤cyPair=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 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 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 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; ctbids[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 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 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 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; itmillistamps,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 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; jexchange,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); +} + + +#endif diff --git a/iguana/pangea_hand.c b/iguana/pangea_hand.c index 36b93371e..af7b40a0e 100755 --- a/iguana/pangea_hand.c +++ b/iguana/pangea_hand.c @@ -279,7 +279,7 @@ int32_t pangea_checkstart(struct supernet_info *myinfo,struct table_info *tp) } if ( matches == tp->G.numactive ) { - if ( time(NULL) > (tp->priv.myind + hand->startdecktime) ) + if ( tp->priv.myind == pangea_slotA(tp) ) { //if ( PANGEA_PAUSE > 0 ) // sleep(PANGEA_PAUSE); diff --git a/includes/iguana_apideclares.h b/includes/iguana_apideclares.h index ae888a886..b041d7f9b 100755 --- a/includes/iguana_apideclares.h +++ b/includes/iguana_apideclares.h @@ -20,6 +20,19 @@ HASH_AND_INT(ramchain,getrawtransaction,txid,verbose); HASH_ARG(ramchain,gettransaction,txid); STRING_ARG(ramchain,decoderawtransaction,rawtx); +THREE_STRINGS_AND_THREE_INTS(InstantDEX,orderbook,exchange,base,rel,depth,allfields,invert); +THREE_STRINGS_AND_THREE_DOUBLES(InstantDEX,buy,exchange,base,rel,price,volume,dotrade); +THREE_STRINGS_AND_THREE_DOUBLES(InstantDEX,sell,exchange,base,rel,price,volume,dotrade); +THREE_STRINGS_AND_DOUBLE(InstantDEX,withdraw,exchange,base,destaddr,amount); +THREE_STRINGS(InstantDEX,apikeypair,exchange,apikey,apisecret); +THREE_STRINGS(InstantDEX,setuserid,exchange,userid,tradepassword); +THREE_STRINGS(InstantDEX,supports,exchange,base,rel); +TWO_STRINGS(InstantDEX,balance,exchange,base); +TWO_STRINGS(InstantDEX,orderstatus,exchange,orderid); +TWO_STRINGS(InstantDEX,cancelorder,exchange,orderid); +STRING_ARG(InstantDEX,openorders,exchange); +STRING_ARG(InstantDEX,tradehistory,exchange); + /*HASH_AND_ARRAY(pangea,userturn,tablehash,params); HASH_AND_ARRAY(pangea,status,tableid,params); HASH_AND_ARRAY(pangea,mode,tableid,params); diff --git a/includes/iguana_apidefs.h b/includes/iguana_apidefs.h index a8aaeace4..b6fc2b4f0 100755 --- a/includes/iguana_apidefs.h +++ b/includes/iguana_apidefs.h @@ -24,6 +24,10 @@ #define IGUANA_CFUNC_SSHII(agent,name,str,str2,hash,val,val2) char *agent ## _ ## name(IGUANA_ARGS,char *str,char *str2,bits256 hash,int32_t val,int32_t val2) #define IGUANA_CFUNC_SSHHII(agent,name,str,str2,hash,hash2,val,val2) char *agent ## _ ## name(IGUANA_ARGS,char *str,char *str2,bits256 hash,bits256 hash2,int32_t val,int32_t val2) #define IGUANA_CFUNC_SSS(agent,name,str,str2,str3) char *agent ## _ ## name(IGUANA_ARGS,char *str,char *str2,char *str3) +#define IGUANA_CFUNC_SSSD(agent,name,str,str2,str3,val) char *agent ## _ ## name(IGUANA_ARGS,char *str,char *str2,char *str3,double val) +#define IGUANA_CFUNC_SSSDDD(agent,name,str,str2,str3,val,val2,val3) char *agent ## _ ## name(IGUANA_ARGS,char *str,char *str2,char *str3,double val,double val2,double val3) +#define IGUANA_CFUNC_SSSIII(agent,name,str,str2,str3,val,val2,val3) char *agent ## _ ## name(IGUANA_ARGS,char *str,char *str2,char *str3,int32_t val,int32_t val2,int32_t val3) + #define IGUANA_CFUNC_SI(agent,name,str,val) char *agent ## _ ## name(IGUANA_ARGS,char *str,int32_t val) #define IGUANA_CFUNC_SII(agent,name,str,val,val2) char *agent ## _ ## name(IGUANA_ARGS,char *str,int32_t val,int32_t val2) #define IGUANA_CFUNC_HI(agent,name,hash,val) char *agent ## _ ## name(IGUANA_ARGS,bits256 hash,int32_t val) @@ -75,3 +79,6 @@ #define HASH_ARG IGUANA_CFUNC_H #define HASH_AND_ARRAY IGUANA_CFUNC_HA #define TWO_HASHES IGUANA_CFUNC_HH +#define THREE_STRINGS_AND_THREE_INTS IGUANA_CFUNC_SSSIII +#define THREE_STRINGS_AND_THREE_DOUBLES IGUANA_CFUNC_SSSDDD +#define THREE_STRINGS_AND_DOUBLE IGUANA_CFUNC_SSSD diff --git a/includes/iguana_apiundefs.h b/includes/iguana_apiundefs.h index 2fd2e0068..f7615746a 100755 --- a/includes/iguana_apiundefs.h +++ b/includes/iguana_apiundefs.h @@ -33,6 +33,10 @@ #undef HASH_ARG #undef TWO_HASHES #undef TWOSTRINGS_AND_TWOHASHES_AND_TWOINTS +#undef THREE_STRINGS_AND_THREE_INTS +#undef THREE_STRINGS_AND_THREE_DOUBLES +#undef THREE_STRINGS_AND_DOUBLE + #undef IGUANA_ARGS #undef IGUANA_CALLARGS