jl777
9 years ago
41 changed files with 17450 additions and 7338 deletions
File diff suppressed because it is too large
@ -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 |
@ -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 |
@ -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 |
@ -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<n; i++) |
|||
{ |
|||
txobj = cJSON_GetArrayItem(array,i); |
|||
copy_cJSON(&receiverstr,cJSON_GetObjectItem(txobj,"recipient")); |
|||
if ( strcmp(receiverstr.buf,INSTANTDEX_ACCT) == 0 ) |
|||
{ |
|||
if ( (senderbits = get_API_nxt64bits(cJSON_GetObjectItem(txobj,"sender"))) != 0 ) |
|||
{ |
|||
expand_nxt64bits(NXTaddr,senderbits); |
|||
amount = get_API_nxt64bits(cJSON_GetObjectItem(txobj,"amountNQT")); |
|||
if ( amount == INSTANTDEX_FEE ) |
|||
totaltickets++; |
|||
else if ( amount >= 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\"}")); |
|||
} |
|||
|
@ -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 <stdint.h> |
|||
#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 |
File diff suppressed because it is too large
File diff suppressed because it is too large
File diff suppressed because it is too large
@ -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)); i<sizeof(*iQ) - sizeof(iQ->hh) - sizeof(iQ->s.quoteid); i++) |
|||
printf("%02x ",((uint8_t *)iQ)[i]); |
|||
printf("iQ\n"); |
|||
for (i=(sizeof(checkiQ->hh) + sizeof(checkiQ->s.quoteid)); i<sizeof(*checkiQ) - sizeof(checkiQ->hh) - sizeof(checkiQ->s.quoteid); i++) |
|||
printf("%02x ",((uint8_t *)checkiQ)[i]); |
|||
printf("checkiQ\n"); |
|||
printf("error finding iQ after adding %llu vs %llu\n",(long long)checkiQ->s.quoteid,(long long)iQ->s.quoteid); |
|||
} |
|||
} |
|||
HASH_ITER(hh,AllQuotes,iQ,tmp) |
|||
{ |
|||
if ( iQ->s.expired != 0 ) |
|||
{ |
|||
printf("quoteid.%llu expired, purging\n",(long long)iQ->s.expired); |
|||
delete_iQ(iQ->s.quoteid); |
|||
} |
|||
} |
|||
return(newiQ); |
|||
} |
|||
|
|||
#ifdef later |
|||
cJSON *pangea_walletitem(cJSON *walletitem,struct coin777 *coin,int32_t rakemillis,int64_t bigblind,int64_t ante,int32_t minbuyin,int32_t maxbuyin) |
|||
{ |
|||
char *addr; struct destbuf pubkey; |
|||
if ( walletitem == 0 ) |
|||
walletitem = cJSON_CreateObject(); |
|||
//printf("call get_acct_coinaddr.%s (%s) (%s)\n",coin->name,coin->serverport,coin->userpass);
|
|||
if ( coin->pangeapubkey[0] == 0 || coin->pangeacoinaddr[0] == 0 ) |
|||
{ |
|||
if ( strcmp("NXT",coin->name) == 0 ) |
|||
{ |
|||
} |
|||
else if ( (addr= get_acct_coinaddr(coin->pangeacoinaddr,coin->name,coin->serverport,coin->userpass,"pangea")) != 0 ) |
|||
{ |
|||
//printf("get_pubkey\n");
|
|||
get_pubkey(&pubkey,coin->name,coin->serverport,coin->userpass,coin->pangeacoinaddr); |
|||
strcpy(coin->pangeapubkey,pubkey.buf); |
|||
} |
|||
} |
|||
jaddstr(walletitem,"pubkey",coin->pangeapubkey); |
|||
jaddstr(walletitem,"coinaddr",coin->pangeacoinaddr); |
|||
jaddnum(walletitem,"rakemillis",rakemillis); |
|||
jaddnum(walletitem,"minbuyin",minbuyin); |
|||
jaddnum(walletitem,"maxbuyin",maxbuyin); |
|||
jadd64bits(walletitem,"bigblind",bigblind); |
|||
jadd64bits(walletitem,"ante",ante); |
|||
return(walletitem); |
|||
} |
|||
|
|||
cJSON *set_walletstr(cJSON *walletitem,char *walletstr,struct InstantDEX_quote *iQ) |
|||
{ |
|||
char pubkeystr[128],pkhash[128],base[64],rel[64],fieldA[64],fieldB[64],fieldpkhash[64],*pubA,*pubB,*pkhashstr,*str,*exchangestr; |
|||
struct coin777 *coin; int32_t flip = 0; |
|||
if ( walletstr != 0 && walletitem == 0 ) |
|||
walletitem = cJSON_Parse(walletstr); |
|||
if ( walletitem == 0 ) |
|||
walletitem = cJSON_CreateObject(); |
|||
unstringbits(base,iQ->s.basebits), unstringbits(rel,iQ->s.relbits); |
|||
flip = (iQ->s.offerNXT != IGUANA_MY64BITS); |
|||
if ( strcmp(base,"NXT") != 0 ) |
|||
coin = coin777_find(base,1); |
|||
else if ( strcmp(rel,"NXT") != 0 ) |
|||
coin = coin777_find(rel,1), flip ^= 1; |
|||
else coin = 0; |
|||
if ( coin != 0 ) |
|||
{ |
|||
if ( (exchangestr= exchange_str(iQ->exchangeid)) != 0 && strcmp(exchangestr,"pangea") == 0 ) |
|||
pangea_walletitem(walletitem,coin,iQ->s.minperc,iQ->s.baseamount,iQ->s.relamount,iQ->s.minbuyin,iQ->s.maxbuyin); |
|||
else |
|||
{ |
|||
//printf("START.(%s)\n",jprint(walletitem,0));
|
|||
if ( (iQ->s.isask ^ flip) == 0 ) |
|||
{ |
|||
sprintf(fieldA,"%spubA",coin->name); |
|||
if ( (pubA= jstr(walletitem,fieldA)) != 0 ) |
|||
cJSON_DeleteItemFromObject(walletitem,fieldA); |
|||
jaddstr(walletitem,fieldA,coin->atomicsendpubkey); |
|||
//printf("replaceA\n");
|
|||
} |
|||
else |
|||
{ |
|||
sprintf(fieldB,"%spubB",coin->name); |
|||
if ( (pubB= jstr(walletitem,fieldB)) != 0 ) |
|||
cJSON_DeleteItemFromObject(walletitem,fieldB); |
|||
jaddstr(walletitem,fieldB,coin->atomicrecvpubkey); |
|||
sprintf(fieldpkhash,"%spkhash",coin->name); |
|||
if ( (pkhashstr= jstr(walletitem,fieldpkhash)) != 0 ) |
|||
cJSON_DeleteItemFromObject(walletitem,fieldpkhash); |
|||
subatomic_pubkeyhash(pubkeystr,pkhash,coin,iQ->s.quoteid); |
|||
jaddstr(walletitem,fieldpkhash,pkhash); |
|||
//printf("replaceB\n");
|
|||
} |
|||
} |
|||
str = jprint(walletitem,0); |
|||
strcpy(walletstr,str); |
|||
free(str); |
|||
return(walletitem); |
|||
} |
|||
return(0); |
|||
} |
|||
#endif |
|||
|
|||
char *InstantDEX_str(char *walletstr,char *buf,int32_t extraflag,struct InstantDEX_quote *iQ) |
|||
{ |
|||
cJSON *json; char _buf[4096],base[64],rel[64],*str; |
|||
unstringbits(base,iQ->s.basebits), unstringbits(rel,iQ->s.relbits); |
|||
if ( buf == 0 ) |
|||
buf = _buf; |
|||
sprintf(buf,"{\"quoteid\":\"%llu\",\"base\":\"%s\",\"baseid\":\"%llu\",\"baseamount\":\"%llu\",\"rel\":\"%s\",\"relid\":\"%llu\",\"relamount\":\"%llu\",\"price\":%.8f,\"volume\":%.8f,\"offerNXT\":\"%llu\",\"timestamp\":\"%u\",\"isask\":\"%u\",\"exchange\":\"%s\",\"gui\":\"%s\"}",(long long)iQ->s.quoteid,base,(long long)iQ->s.baseid,(long long)iQ->s.baseamount,rel,(long long)iQ->s.relid,(long long)iQ->s.relamount,iQ->s.price,iQ->s.vol,(long long)iQ->s.offerNXT,iQ->s.timestamp,iQ->s.isask,exchange_str(iQ->exchangeid),iQ->gui); |
|||
if ( extraflag != 0 ) |
|||
{ |
|||
sprintf(buf + strlen(buf) - 1,",\"plugin\":\"relay\",\"destplugin\":\"InstantDEX\",\"method\":\"busdata\",\"submethod\":\"%s\"}",(iQ->s.isask != 0) ? "ask" : "bid"); |
|||
} |
|||
//printf("InstantDEX_str.(%s)\n",buf);
|
|||
if ( (json= cJSON_Parse(buf)) != 0 ) |
|||
{ |
|||
#ifdef later |
|||
char _buf[4096],_walletstr[256],base[64],rel[64],*exchange,*str; cJSON *walletitem,*json; struct coin777 *coin; |
|||
if ( walletstr == 0 ) |
|||
{ |
|||
walletstr = _walletstr; |
|||
walletstr[0] = 0; |
|||
} |
|||
if ( (exchange= exchange_str(iQ->exchangeid)) != 0 ) |
|||
{ |
|||
coin = coin777_find(base,0); |
|||
if ( strcmp(exchange,"wallet") == 0 ) |
|||
walletitem = set_walletstr(0,walletstr,iQ); |
|||
else if ( strcmp(exchange,"pangea") == 0 && walletstr[0] == 0 && coin != 0 ) |
|||
walletitem = pangea_walletitem(0,coin,iQ->s.minperc,iQ->s.baseamount,iQ->s.relamount,iQ->s.minbuyin,iQ->s.maxbuyin); |
|||
else walletitem = 0; |
|||
if ( walletitem != 0 ) |
|||
{ |
|||
jadd(json,"wallet",walletitem); |
|||
strcpy(walletstr,jprint(walletitem,0)); |
|||
} |
|||
//printf("exchange.(%s) iswallet.%d (%s) base.(%s) coin.%p (%s)\n",exchange,iQ->s.wallet,walletstr,base,coin,jprint(json,0));
|
|||
} else printf("InstantDEX_str cant find exchangeid.%d\n",iQ->exchangeid); |
|||
#endif |
|||
str = jprint(json,1); |
|||
strcpy(buf,str); |
|||
//printf("str.(%s) %p\n",buf,buf);
|
|||
free(str); |
|||
} else printf("InstantDEX_str cant parse.(%s)\n",buf); |
|||
if ( buf == _buf ) |
|||
return(clonestr(buf)); |
|||
else return(buf); |
|||
} |
|||
|
|||
uint64_t _get_AEquote(char *str,uint64_t orderid) |
|||
{ |
|||
cJSON *json; |
|||
uint64_t nxt64bits = 0; |
|||
char cmd[256],*jsonstr; |
|||
sprintf(cmd,"requestType=get%sOrder&order=%llu",str,(long long)orderid); |
|||
if ( (jsonstr= issue_NXTPOST(cmd)) != 0 ) |
|||
{ |
|||
//printf("(%s) -> (%s)\n",cmd,jsonstr);
|
|||
if ( (json= cJSON_Parse(jsonstr)) != 0 ) |
|||
{ |
|||
nxt64bits = get_API_nxt64bits(cJSON_GetObjectItem(json,"account")); |
|||
free_json(json); |
|||
} |
|||
free(jsonstr); |
|||
} |
|||
return(nxt64bits); |
|||
} |
|||
|
|||
char *cancel_NXTorderid(char *NXTaddr,char *nxtsecret,uint64_t orderid) |
|||
{ |
|||
uint64_t nxt64bits; char cmd[1025],secret[8192],*str = "Bid",*retstr = 0; |
|||
if ( (nxt64bits= _get_AEquote(str,orderid)) == 0 ) |
|||
str = "Ask", nxt64bits = _get_AEquote(str,orderid); |
|||
if ( nxt64bits == calc_nxt64bits(NXTaddr) ) |
|||
{ |
|||
escape_code(secret,nxtsecret); |
|||
sprintf(cmd,"requestType=cancel%sOrder&secretPhrase=%s&feeNQT=%lld&deadline=%d&order=%llu",str,secret,(long long)MIN_NQTFEE,DEFAULT_NXT_DEADLINE,(long long)orderid); |
|||
retstr = issue_NXTPOST(cmd); |
|||
//printf("(%s) -> (%s)\n",cmd,retstr);
|
|||
} |
|||
return(retstr); |
|||
} |
|||
|
|||
char *InstantDEX_cancelorder(cJSON *argjson,char *activenxt,char *secret,uint64_t orderid,uint64_t quoteid) |
|||
{ |
|||
struct InstantDEX_quote *iQ; cJSON *json,*array,*item; char numstr[64],*retstr,*exchangestr; |
|||
uint64_t quoteids[256]; int32_t i,exchangeid,n=0; struct exchange_info *exchange; |
|||
if ( (exchangestr= jstr(argjson,"exchange")) != 0 && (exchange= find_exchange(&exchangeid,exchangestr)) != 0 ) |
|||
{ |
|||
if ( exchange->issue.cancelorder != 0 ) |
|||
{ |
|||
if ( (retstr= (*exchange->issue.cancelorder)(&exchange->cHandle,exchange,argjson,quoteid)) == 0 ) |
|||
retstr = clonestr("{\"result\":\"nothing returned from exchange\"}"); |
|||
return(retstr); |
|||
} |
|||
else return(clonestr("{\"error\":\"no cancelorder function\"}")); |
|||
} |
|||
memset(quoteids,0,sizeof(quoteids)); |
|||
json = cJSON_CreateObject(), array = cJSON_CreateArray(); |
|||
if ( quoteid != 0 ) |
|||
quoteids[n++] = quoteid; |
|||
//n += InstantDEX_quoteids(quoteids+n,orderid);
|
|||
for (i=0; i<n; i++) |
|||
{ |
|||
quoteid = quoteids[i]; |
|||
if ( (retstr= cancel_NXTorderid(activenxt,secret,quoteid)) != 0 ) |
|||
{ |
|||
if ( (iQ= findquoteid(quoteid,0)) != 0 && iQ->s.offerNXT == calc_nxt64bits(activenxt) ) |
|||
cancel_InstantDEX_quote(iQ); |
|||
if ( (item= cJSON_Parse(retstr)) != 0 ) |
|||
jaddi(array,item); |
|||
free(retstr); |
|||
} |
|||
cancelquote(activenxt,quoteid); |
|||
} |
|||
if ( orderid != 0 ) |
|||
{ |
|||
if ( cancelquote(activenxt,orderid) != 0 ) |
|||
sprintf(numstr,"%llu",(long long)orderid), jaddstr(json,"ordercanceled",numstr); |
|||
} |
|||
return(jprint(json,1)); |
|||
} |
|||
|
|||
char *InstantDEX_orderstatus(cJSON *argjson,uint64_t orderid,uint64_t quoteid) |
|||
{ |
|||
struct InstantDEX_quote *iQ = 0; char *exchangestr,*str; struct exchange_info *exchange; int32_t exchangeid; |
|||
if ( (exchangestr= jstr(argjson,"exchange")) != 0 && (exchange= find_exchange(&exchangeid,exchangestr)) != 0 ) |
|||
{ |
|||
if ( exchange->issue.orderstatus != 0 ) |
|||
{ |
|||
if ( (str= (*exchange->issue.orderstatus)(&exchange->cHandle,exchange,argjson,quoteid)) == 0 ) |
|||
str = clonestr("{\"result\":\"nothing returned from exchange\"}"); |
|||
return(str); |
|||
} |
|||
else return(clonestr("{\"error\":\"no orderstatus function\"}")); |
|||
} |
|||
if ( (iQ= find_iQ(orderid)) != 0 || (iQ= find_iQ(quoteid)) != 0 ) |
|||
return(InstantDEX_str(0,0,0,iQ)); |
|||
return(clonestr("{\"error\":\"couldnt find orderid\"}")); |
|||
} |
|||
|
|||
char *InstantDEX_openorders(cJSON *argjson,char *NXTaddr,int32_t allorders) |
|||
{ |
|||
struct InstantDEX_quote *iQ,*tmp; char buf[4096],*exchangestr,*jsonstr,*str; uint32_t now,duration; |
|||
cJSON *json,*array,*item; uint64_t nxt64bits; struct exchange_info *exchange; int32_t exchangeid; |
|||
if ( (exchangestr= jstr(argjson,"exchange")) != 0 && (exchange= find_exchange(&exchangeid,exchangestr)) != 0 ) |
|||
{ |
|||
if ( exchange->issue.openorders != 0 ) |
|||
{ |
|||
if ( (str= (*exchange->issue.openorders)(&exchange->cHandle,exchange,argjson)) == 0 ) |
|||
str = clonestr("{\"result\":\"nothing returned from exchange\"}"); |
|||
return(str); |
|||
} |
|||
else return(clonestr("{\"error\":\"no orderstatus function\"}")); |
|||
} |
|||
nxt64bits = calc_nxt64bits(NXTaddr); |
|||
now = (uint32_t)time(NULL); |
|||
json = cJSON_CreateObject(), array = cJSON_CreateArray(); |
|||
HASH_ITER(hh,AllQuotes,iQ,tmp) |
|||
{ |
|||
if ( (duration= iQ->s.duration) == 0 ) |
|||
duration = ORDERBOOK_EXPIRATION; |
|||
if ( iQ->s.timestamp > (now + duration) ) |
|||
iQ->s.expired = iQ->s.closed = 1; |
|||
if ( iQ->s.offerNXT == nxt64bits && (allorders != 0 || iQ->s.closed == 0) ) |
|||
{ |
|||
if ( (jsonstr= InstantDEX_str(0,buf,0,iQ)) != 0 && (item= cJSON_Parse(jsonstr)) != 0 ) |
|||
jaddi(array,item); |
|||
} |
|||
} |
|||
jadd(json,"openorders",array); |
|||
return(jprint(json,1)); |
|||
} |
|||
|
|||
cJSON *InstantDEX_specialorders(uint64_t *quoteidp,uint64_t nxt64bits,char *base,char *special,uint64_t baseamount,int32_t addrtype) |
|||
{ |
|||
struct InstantDEX_quote *iQ,*tmp; int32_t exchangeid; uint32_t i,n,now,duration,ismine = 0; |
|||
uint64_t basebits; cJSON *item=0,*array = 0; char *coinaddr=0,*pubkey,checkaddr[128]; |
|||
now = (uint32_t)time(NULL); |
|||
basebits = stringbits(base); |
|||
if ( special == 0 || find_exchange(&exchangeid,special) == 0 ) |
|||
exchangeid = 0; |
|||
n = 0; |
|||
*quoteidp = 0; |
|||
HASH_ITER(hh,AllQuotes,iQ,tmp) |
|||
{ |
|||
//printf("iter Q.%llu b.%llu\n",(long long)iQ->s.quoteid,(long long)iQ->s.basebits);
|
|||
if ( (duration= iQ->s.duration) == 0 ) |
|||
duration = ORDERBOOK_EXPIRATION; |
|||
if ( iQ->s.timestamp > (now + duration) ) |
|||
{ |
|||
iQ->s.expired = iQ->s.closed = 1; |
|||
printf("expire order %llu\n",(long long)iQ->s.quoteid); |
|||
continue; |
|||
} |
|||
if ( iQ->s.basebits == basebits && (exchangeid == 0 || iQ->exchangeid == exchangeid) ) |
|||
{ |
|||
//printf("matched basebits\n");
|
|||
if ( strcmp(special,"pangea") == 0 ) |
|||
{ |
|||
checkaddr[0] = 0; |
|||
if ( iQ->s.wallet != 0 && (item= cJSON_Parse(iQ->walletstr)) != 0 && (coinaddr= jstr(item,"coinaddr")) != 0 && coinaddr[0] != 0 && (pubkey= jstr(item,"pubkey")) != 0 && pubkey[0] != 0 ) |
|||
btc_coinaddr(coinaddr,addrtype,pubkey); |
|||
if ( item != 0 ) |
|||
free_json(item); |
|||
if ( coinaddr == 0 || strcmp(coinaddr,checkaddr) != 0 ) |
|||
{ |
|||
printf("mismatched pangea coinaddr (%s) vs (%s) or baseamount %.8f vs %.8f\n",coinaddr,checkaddr,dstr(baseamount),dstr(iQ->s.baseamount)); |
|||
continue; |
|||
} |
|||
} |
|||
if ( n > 0 ) |
|||
{ |
|||
for (i=0; i<n; i++) |
|||
{ |
|||
if ( iQ->s.offerNXT == j64bits(jitem(array,i),0) ) |
|||
break; |
|||
} |
|||
//printf("found duplicate\n");
|
|||
} else i = 0; |
|||
if ( i == n ) |
|||
{ |
|||
if ( iQ->s.offerNXT == nxt64bits ) |
|||
{ |
|||
ismine = 1; |
|||
if ( *quoteidp == 0 ) |
|||
*quoteidp = iQ->s.quoteid; |
|||
} |
|||
if ( array == 0 ) |
|||
array = cJSON_CreateArray(); |
|||
jaddi64bits(array,iQ->s.offerNXT); |
|||
//printf("add %llu\n",(long long)iQ->s.offerNXT);
|
|||
} |
|||
} //else printf("quote.%llu basebits.%llu\n",(long long)iQ->s.quoteid,(long long)iQ->s.basebits);
|
|||
} |
|||
if ( ismine == 0 ) |
|||
free_json(array), array = 0; |
|||
//printf("ismine.%d n.%d array.%d\n",ismine,n,array==0?0:cJSON_GetArraySize(array));
|
|||
return(array); |
|||
} |
|||
|
|||
int _decreasing_quotes(const void *a,const void *b) |
|||
{ |
|||
#define order_a ((struct InstantDEX_quote *)a) |
|||
#define order_b ((struct InstantDEX_quote *)b) |
|||
if ( order_b->s.price > order_a->s.price ) |
|||
return(1); |
|||
else if ( order_b->s.price < order_a->s.price ) |
|||
return(-1); |
|||
return(0); |
|||
#undef order_a |
|||
#undef order_b |
|||
} |
|||
|
|||
int _increasing_quotes(const void *a,const void *b) |
|||
{ |
|||
#define order_a ((struct InstantDEX_quote *)a) |
|||
#define order_b ((struct InstantDEX_quote *)b) |
|||
if ( order_b->s.price > order_a->s.price ) |
|||
return(-1); |
|||
else if ( order_b->s.price < order_a->s.price ) |
|||
return(1); |
|||
return(0); |
|||
#undef order_a |
|||
#undef order_b |
|||
} |
|||
|
|||
cJSON *prices777_orderjson(struct InstantDEX_quote *iQ) |
|||
{ |
|||
cJSON *item = cJSON_CreateArray(); |
|||
jaddinum(item,iQ->s.price); |
|||
jaddinum(item,iQ->s.vol); |
|||
jaddi64bits(item,iQ->s.quoteid); |
|||
return(item); |
|||
} |
|||
|
|||
cJSON *InstantDEX_orderbook(struct prices777 *prices) |
|||
{ |
|||
struct InstantDEX_quote *ptr,iQ,*tmp,*askvals=0,*bidvals=0; cJSON *json,*bids,*asks; uint32_t now,duration; |
|||
int32_t i,isask,iter,n,m,numbids,numasks,invert; |
|||
json = cJSON_CreateObject(), bids = cJSON_CreateArray(), asks = cJSON_CreateArray(); |
|||
now = (uint32_t)time(NULL); |
|||
for (iter=numbids=numasks=n=m=0; iter<2; iter++) |
|||
{ |
|||
HASH_ITER(hh,AllQuotes,ptr,tmp) |
|||
{ |
|||
iQ = *ptr; |
|||
if ( (duration= iQ.s.duration) == 0 ) |
|||
duration = ORDERBOOK_EXPIRATION; |
|||
if ( iQ.s.timestamp > (now + duration) ) |
|||
{ |
|||
iQ.s.expired = iQ.s.closed = 1; |
|||
continue; |
|||
} |
|||
if ( Debuglevel > 2 ) |
|||
printf("iterate quote.%llu\n",(long long)iQ.s.quoteid); |
|||
if ( prices777_equiv(ptr->s.baseid) == prices777_equiv(prices->baseid) && prices777_equiv(ptr->s.relid) == prices777_equiv(prices->relid) ) |
|||
invert = 0; |
|||
else if ( prices777_equiv(ptr->s.relid) == prices777_equiv(prices->baseid) && prices777_equiv(ptr->s.baseid) == prices777_equiv(prices->relid) ) |
|||
invert = 1; |
|||
else continue; |
|||
if ( ptr->s.pending != 0 ) |
|||
continue; |
|||
isask = iQ.s.isask; |
|||
if ( invert != 0 ) |
|||
isask ^= 1; |
|||
if ( invert != 0 ) |
|||
{ |
|||
if ( iQ.s.price > SMALLVAL ) |
|||
iQ.s.vol *= iQ.s.price, iQ.s.price = 1. / iQ.s.price; |
|||
else iQ.s.price = prices777_price_volume(&iQ.s.vol,iQ.s.relamount,iQ.s.baseamount); |
|||
} |
|||
else if ( iQ.s.price <= SMALLVAL ) |
|||
iQ.s.price = prices777_price_volume(&iQ.s.vol,iQ.s.baseamount,iQ.s.relamount); |
|||
if ( iter == 0 ) |
|||
{ |
|||
if ( isask != 0 ) |
|||
numasks++; |
|||
else numbids++; |
|||
} |
|||
else |
|||
{ |
|||
if ( isask == 0 && n < numbids ) |
|||
bidvals[n++] = iQ; |
|||
else if ( isask != 0 && m < numasks ) |
|||
askvals[m++] = iQ; |
|||
} |
|||
} |
|||
if ( iter == 0 ) |
|||
{ |
|||
if ( numbids > 0 ) |
|||
bidvals = calloc(numbids,sizeof(*bidvals)); |
|||
if ( numasks > 0 ) |
|||
askvals = calloc(numasks,sizeof(*askvals)); |
|||
} |
|||
} |
|||
if ( numbids > 0 ) |
|||
{ |
|||
if ( n > 0 ) |
|||
{ |
|||
qsort(bidvals,n,sizeof(*bidvals),_decreasing_quotes); |
|||
for (i=0; i<n; i++) |
|||
jaddi(bids,prices777_orderjson(&bidvals[i])); |
|||
} |
|||
free(bidvals); |
|||
} |
|||
if ( numasks > 0 ) |
|||
{ |
|||
if ( m > 0 ) |
|||
{ |
|||
qsort(askvals,m,sizeof(*askvals),_increasing_quotes); |
|||
for (i=0; i<m; i++) |
|||
jaddi(asks,prices777_orderjson(&askvals[i])); |
|||
} |
|||
free(askvals); |
|||
} |
|||
jadd(json,"bids",bids), jadd(json,"asks",asks); |
|||
return(json); |
|||
} |
|||
|
|||
double ordermetric(double price,double vol,int32_t dir,double refprice,double refvol) |
|||
{ |
|||
double metric = 0.; |
|||
if ( vol > (refvol * INSTANTDEX_MINVOLPERC) )//&& refvol > (vol * iQ->s.minperc * .01) )
|
|||
{ |
|||
if ( vol < refvol ) |
|||
metric = (vol / refvol); |
|||
else metric = 1.; |
|||
if ( dir > 0 && price < (refprice * (1. + INSTANTDEX_PRICESLIPPAGE) + SMALLVAL) ) |
|||
metric *= (1. + (refprice - price)/refprice); |
|||
else if ( dir < 0 && price > (refprice * (1. - INSTANTDEX_PRICESLIPPAGE) - SMALLVAL) ) |
|||
metric *= (1. + (price - refprice)/refprice); |
|||
else metric = 0.; |
|||
if ( metric != 0. ) |
|||
{ |
|||
printf("price %.8f vol %.8f | %.8f > %.8f? %.8f > %.8f?\n",price,vol,vol,(refvol * INSTANTDEX_MINVOLPERC),refvol,(vol * INSTANTDEX_MINVOLPERC)); |
|||
printf("price %f against %f or %f\n",price,(refprice * (1. + INSTANTDEX_PRICESLIPPAGE) + SMALLVAL),(refprice * (1. - INSTANTDEX_PRICESLIPPAGE) - SMALLVAL)); |
|||
printf("metric %f\n",metric); |
|||
} |
|||
} |
|||
return(metric); |
|||
} |
|||
|
|||
char *autofill(char *remoteaddr,struct InstantDEX_quote *refiQ,char *NXTaddr,char *NXTACCTSECRET) |
|||
{ |
|||
double price,volume,revprice,revvol,metric,bestmetric = 0.; int32_t dir,inverted; uint64_t nxt64bits; char *retstr=0; |
|||
struct InstantDEX_quote *iQ,*tmp,*bestiQ; struct prices777 *prices; uint32_t duration,now = (uint32_t)time(NULL); |
|||
return(0); |
|||
nxt64bits = calc_nxt64bits(NXTaddr); |
|||
memset(&bestiQ,0,sizeof(bestiQ)); |
|||
dir = (refiQ->s.isask != 0) ? -1 : 1; |
|||
HASH_ITER(hh,AllQuotes,iQ,tmp) |
|||
{ |
|||
if ( (duration= refiQ->s.duration) == 0 ) |
|||
duration = ORDERBOOK_EXPIRATION; |
|||
if ( iQ->s.timestamp > (now + duration) ) |
|||
iQ->s.expired = iQ->s.closed = 1; |
|||
if ( iQ->s.offerNXT == nxt64bits && iQ->s.closed == 0 && iQ->s.pending == 0 ) |
|||
{ |
|||
if ( iQ->s.baseid == refiQ->s.baseid && iQ->s.relid == refiQ->s.relid && iQ->s.isask != refiQ->s.isask && (metric= ordermetric(iQ->s.price,iQ->s.vol,dir,refiQ->s.price,refiQ->s.vol)) > bestmetric ) |
|||
{ |
|||
bestmetric = metric; |
|||
bestiQ = iQ; |
|||
} |
|||
else if ( iQ->s.baseid == refiQ->s.relid && iQ->s.relid == refiQ->s.baseid && iQ->s.isask == refiQ->s.isask && iQ->s.price > SMALLVAL ) |
|||
{ |
|||
revvol = (iQ->s.price * iQ->s.vol), revprice = (1. / iQ->s.price); |
|||
if ( (metric= ordermetric(revprice,revvol,dir,refiQ->s.price,refiQ->s.vol)) > bestmetric ) |
|||
{ |
|||
bestmetric = metric; |
|||
bestiQ = iQ; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
if ( bestmetric > 0. ) |
|||
{ |
|||
if ( (prices= prices777_find(&inverted,bestiQ->s.baseid,bestiQ->s.relid,exchange_str(bestiQ->exchangeid))) != 0 ) |
|||
{ |
|||
printf("isask.%d %f %f -> bestmetric %f inverted.%d autofill dir.%d price %f vol %f\n",bestiQ->s.isask,bestiQ->s.price,bestiQ->s.vol,bestmetric,inverted,dir,refiQ->s.price,refiQ->s.vol); |
|||
if ( bestiQ->s.isask != 0 ) |
|||
dir = -1; |
|||
else dir = 1; |
|||
if ( inverted != 0 ) |
|||
{ |
|||
dir *= -1; |
|||
volume = (bestiQ->s.price * bestiQ->s.vol); |
|||
price = 1. / bestiQ->s.price; |
|||
printf("price inverted (%f %f) -> (%f %f)\n",bestiQ->s.price,bestiQ->s.vol,price,volume); |
|||
} else price = bestiQ->s.price, volume = bestiQ->s.vol; |
|||
retstr = prices777_trade(0,0,0,0,1,0,NXTaddr,NXTACCTSECRET,prices,dir,price,volume,bestiQ,0,bestiQ->s.quoteid,0); |
|||
} |
|||
} |
|||
return(retstr); |
|||
} |
|||
|
|||
char *automatch(struct prices777 *prices,int32_t dir,double refprice,double refvol,char *NXTaddr,char *NXTACCTSECRET) |
|||
{ |
|||
int32_t i,n=0; struct prices777_order order,bestorder; char *retstr = 0; double metric,bestmetric = 0.; |
|||
return(0); |
|||
memset(&bestorder,0,sizeof(bestorder)); |
|||
if ( dir > 0 ) |
|||
n = prices->O.numasks; |
|||
else if ( dir < 0 ) |
|||
n = prices->O.numbids; |
|||
if ( n > 0 ) |
|||
{ |
|||
for (i=0; i<n; i++) |
|||
{ |
|||
order = (dir > 0) ? prices->O.book[MAX_GROUPS][i].ask : prices->O.book[MAX_GROUPS][i].bid; |
|||
if ( (metric= ordermetric(order.s.price,order.s.vol,dir,refprice,refvol)) > bestmetric ) |
|||
{ |
|||
bestmetric = metric; |
|||
bestorder = order; |
|||
} |
|||
} |
|||
} |
|||
//printf("n.%d\n",n);
|
|||
if ( bestorder.source != 0 ) |
|||
retstr = prices777_trade(0,0,0,0,1,0,NXTaddr,NXTACCTSECRET,bestorder.source,bestorder.s.isask!=0?-1:1,bestorder.s.price,bestorder.s.vol,0,&bestorder,bestorder.s.quoteid,0); |
|||
return(retstr); |
|||
} |
|||
|
|||
int offer_checkitem(struct pending_trade *pend,cJSON *item) |
|||
{ |
|||
uint64_t quoteid; struct InstantDEX_quote *iQ; |
|||
if ( (quoteid= j64bits(item,"quoteid")) != 0 && (iQ= find_iQ(quoteid)) != 0 && iQ->s.closed != 0 ) |
|||
return(0); |
|||
return(-1); |
|||
} |
|||
|
|||
void trades_update() |
|||
{ |
|||
#ifdef later |
|||
int32_t iter; struct pending_trade *pend; |
|||
for (iter=0; iter<2; iter++) |
|||
{ |
|||
while ( (pend= queue_dequeue(&Pending_offersQ.pingpong[iter],0)) != 0 ) |
|||
{ |
|||
if ( time(NULL) > pend->expiration ) |
|||
{ |
|||
printf("now.%ld vs timestamp.%u vs expiration %u | ",(long)time(NULL),pend->timestamp,pend->expiration); |
|||
printf("offer_statemachine %llu/%llu %d %f %f\n",(long long)pend->orderid,(long long)pend->quoteid,pend->dir,pend->price,pend->volume); |
|||
//InstantDEX_history(1,pend,retstr);
|
|||
if ( pend->bot == 0 ) |
|||
free_pending(pend); |
|||
else pend->finishtime = (uint32_t)time(NULL); |
|||
} |
|||
else |
|||
{ |
|||
printf("InstantDEX_update requeue %llu/%llu %d %f %f\n",(long long)pend->orderid,(long long)pend->quoteid,pend->dir,pend->price,pend->volume); |
|||
queue_enqueue("requeue",&Pending_offersQ.pingpong[iter ^ 1],&pend->DL,0); |
|||
} |
|||
} |
|||
} |
|||
#endif |
|||
} |
|||
|
|||
void InstantDEX_update(char *NXTaddr,char *NXTACCTSECRET) |
|||
{ |
|||
int32_t dir; double price,volume; uint32_t now; char *retstr = 0; |
|||
int32_t inverted; struct InstantDEX_quote *iQ,*tmp; struct prices777 *prices; uint64_t nxt64bits = calc_nxt64bits(NXTaddr); |
|||
now = (uint32_t)time(NULL); |
|||
HASH_ITER(hh,AllQuotes,iQ,tmp) |
|||
{ |
|||
if ( iQ->s.timestamp > (now + ORDERBOOK_EXPIRATION) ) |
|||
iQ->s.expired = iQ->s.closed = 1; |
|||
if ( iQ->s.offerNXT == nxt64bits && iQ->s.closed == 0 && iQ->s.pending == 0 ) |
|||
{ |
|||
if ( (prices= prices777_find(&inverted,iQ->s.baseid,iQ->s.relid,exchange_str(iQ->exchangeid))) != 0 ) |
|||
{ |
|||
if ( iQ->s.isask != 0 ) |
|||
dir = -1; |
|||
else dir = 1; |
|||
if ( inverted != 0 ) |
|||
{ |
|||
dir *= -1; |
|||
volume = (iQ->s.price * iQ->s.vol); |
|||
price = 1. / iQ->s.price; |
|||
printf("price inverted (%f %f) -> (%f %f)\n",iQ->s.price,iQ->s.vol,price,volume); |
|||
} else price = iQ->s.price, volume = iQ->s.vol; |
|||
if ( (retstr= automatch(prices,dir,price,volume,NXTaddr,NXTACCTSECRET)) != 0 ) |
|||
{ |
|||
printf("automatched %s isask.%d %f %f (%s)\n",prices->contract,iQ->s.isask,iQ->s.price,iQ->s.vol,retstr); |
|||
free(retstr); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
trades_update(); |
|||
} |
|||
|
|||
int32_t is_specialexchange(char *exchangestr) |
|||
{ |
|||
if ( strcmp(exchangestr,"InstantDEX") == 0 || strcmp(exchangestr,"jumblr") == 0 || strcmp(exchangestr,"pangea") == 0 || strcmp(exchangestr,"peggy") == 0 || strcmp(exchangestr,"wallet") == 0 || strcmp(exchangestr,"active") == 0 || strncmp(exchangestr,"basket",strlen("basket")) == 0 ) |
|||
return(1); |
|||
return(0); |
|||
} |
|||
|
|||
char *InstantDEX_placebidask(char *remoteaddr,uint64_t orderid,char *exchangestr,char *name,char *base,char *rel,struct InstantDEX_quote *iQ,char *extra,char *secret,char *activenxt,cJSON *origjson) |
|||
{ |
|||
struct exchange_info *exchange; cJSON *obj; |
|||
char walletstr[256],*str,*retstr = 0; int32_t inverted,dir; struct prices777 *prices; double price,volume; |
|||
if ( secret == 0 || activenxt == 0 ) |
|||
{ |
|||
secret = IGUANA_NXTACCTSECRET; |
|||
activenxt = IGUANA_NXTADDR; |
|||
} |
|||
//printf("placebidask.(%s)\n",jprint(origjson,0));
|
|||
if ( (obj= jobj(origjson,"wallet")) != 0 ) |
|||
{ |
|||
str = jprint(obj,1); |
|||
safecopy(walletstr,str,sizeof(walletstr)); |
|||
free(str), str = 0; |
|||
} |
|||
else walletstr[0] = 0; |
|||
if ( exchangestr != 0 && (exchange= exchange_find(exchangestr)) != 0 ) |
|||
iQ->exchangeid = exchange->exchangeid; |
|||
if ( iQ->exchangeid < 0 || (exchangestr= exchange_str(iQ->exchangeid)) == 0 ) |
|||
{ |
|||
printf("exchangestr.%s id.%d\n",exchangestr,iQ->exchangeid); |
|||
return(clonestr("{\"error\":\"exchange not active, check SuperNET.conf exchanges array\"}\n")); |
|||
} |
|||
//printf("walletstr.(%s)\n",walletstr);
|
|||
if ( (prices= prices777_find(&inverted,iQ->s.baseid,iQ->s.relid,exchangestr)) == 0 ) |
|||
prices = prices777_poll(exchangestr,name,base,iQ->s.baseid,rel,iQ->s.relid); |
|||
if ( prices != 0 ) |
|||
{ |
|||
price = iQ->s.price, volume = iQ->s.vol; |
|||
if ( price < SMALLVAL || volume < SMALLVAL ) |
|||
{ |
|||
printf("price %f volume %f error\n",price,volume); |
|||
return(clonestr("{\"error\":\"prices777_trade invalid price or volume\"}\n")); |
|||
} |
|||
if ( iQ->s.isask != 0 ) |
|||
dir = -1; |
|||
else dir = 1; |
|||
if ( inverted != 0 ) |
|||
{ |
|||
dir *= -1; |
|||
volume *= price; |
|||
price = 1. / price; |
|||
printf("price inverted (%f %f) -> (%f %f)\n",iQ->s.price,iQ->s.vol,price,volume); |
|||
} |
|||
//printf("dir.%d price %f vol %f isask.%d remoteaddr.%p\n",dir,price,volume,iQ->s.isask,remoteaddr);
|
|||
if ( remoteaddr == 0 ) |
|||
{ |
|||
if ( is_specialexchange(exchangestr) == 0 ) |
|||
return(prices777_trade(0,0,0,0,1,0,activenxt,secret,prices,dir,price,volume,iQ,0,iQ->s.quoteid,extra)); |
|||
//printf("check automatch\n");
|
|||
//if ( strcmp(exchangestr,"wallet") != 0 && strcmp(exchangestr,"jumblr") != 0 && strcmp(exchangestr,"pangea") != 0 && iQ->s.automatch != 0 && (SUPERNET.automatch & 1) != 0 && (retstr= automatch(prices,dir,volume,price,activenxt,secret)) != 0 )
|
|||
// return(retstr);
|
|||
if ( strcmp(IGUANA_NXTACCTSECRET,secret) != 0 ) |
|||
return(clonestr("{\"error\":\"cant do queued requests with non-default accounts\"}")); |
|||
retstr = InstantDEX_str(walletstr,0,1,iQ); |
|||
//printf("create_iQ.(%llu) quoteid.%llu walletstr.(%s) %p\n",(long long)iQ->s.offerNXT,(long long)iQ->s.quoteid,walletstr,walletstr);
|
|||
iQ = create_iQ(iQ,walletstr); |
|||
printf("local got create_iQ.(%llu) quoteid.%llu wallet.(%s) baseamount %llu iswallet.%d\n",(long long)iQ->s.offerNXT,(long long)iQ->s.quoteid,walletstr,(long long)iQ->s.baseamount,iQ->s.wallet); |
|||
prices777_InstantDEX(prices,MAX_DEPTH); |
|||
queue_enqueue("InstantDEX",&InstantDEXQ,queueitem(retstr),0); |
|||
} |
|||
else |
|||
{ |
|||
iQ = create_iQ(iQ,walletstr); |
|||
if ( (retstr= autofill(remoteaddr,iQ,activenxt,secret)) == 0 ) |
|||
{ |
|||
//printf("create_iQ.(%llu) quoteid.%llu\n",(long long)iQ->s.offerNXT,(long long)iQ->s.quoteid);
|
|||
if ( strcmp(IGUANA_NXTACCTSECRET,secret) != 0 ) |
|||
return(clonestr("{\"error\":\"cant do queued requests with non-default accounts\"}")); |
|||
prices777_InstantDEX(prices,MAX_DEPTH); |
|||
printf("remote got create_iQ.(%llu) quoteid.%llu wallet.(%s) baseamount %llu\n",(long long)iQ->s.offerNXT,(long long)iQ->s.quoteid,walletstr,(long long)iQ->s.baseamount); |
|||
} |
|||
return(retstr); |
|||
} |
|||
} else printf("cant find prices\n"); |
|||
if ( retstr == 0 ) |
|||
retstr = clonestr("{\"error\":\"cant get prices ptr\"}"); |
|||
return(retstr); |
|||
} |
|||
|
|||
|
|||
#endif |
|||
#endif |
File diff suppressed because it is too large
File diff suppressed because it is too large
@ -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; i<bot->numlinks; 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; i<n; i++) |
|||
{ |
|||
trade = jitem(trades,i); |
|||
sprintf(bot->buf+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; i<n; i++) |
|||
{ |
|||
item = jitem(array,i); |
|||
if ( jstr(item,"error") == 0 && (resultval= jstr(item,"success")) != 0 ) |
|||
{ |
|||
balance = jdouble(item,"balance"); |
|||
required = jdouble(item,"required"); |
|||
printf("[%s %f R%f] ",resultval,balance,required); |
|||
valid++; |
|||
} |
|||
} |
|||
//printf("valid.%d of %d\n",valid,n);
|
|||
if ( valid == n ) |
|||
return(0); |
|||
} |
|||
return(-1); |
|||
} |
|||
|
|||
int32_t tradebot_tradedone(struct tradebot_info *bot,struct prices777_order *order) |
|||
{ |
|||
struct pending_trade *pend; |
|||
if ( (pend= order->pend) != 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; i<bot->numtrades; 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; i<bot->numtrades; 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 |
File diff suppressed because it is too large
@ -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<n; i++) |
|||
{ |
|||
if ( (item= jitem(argjson,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); |
|||
} |
|||
|
|||
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 |
@ -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 |
@ -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; i<n; i++) |
|||
{ |
|||
if ( (item= jitem(array,i)) != 0 ) |
|||
{ |
|||
if ( (str= jstr(item,"Currency")) != 0 && strcmp(coinstr,str) == 0 ) |
|||
{ |
|||
itemstr = jprint(item,0); |
|||
*balancep = jdouble(item,"Available"); |
|||
total = jdouble(item,"Balance"); |
|||
pending = jdouble(item,"Pending"); |
|||
if ( (obj= cJSON_Parse(itemstr)) != 0 ) |
|||
{ |
|||
jaddnum(obj,"balance",*balancep); |
|||
jaddnum(obj,"total",total); |
|||
jaddnum(obj,"pending",pending); |
|||
if ( (str= jstr(obj,"CryptoAddress")) != 0 ) |
|||
jaddstr(obj,"deposit_address",str); |
|||
free(itemstr); |
|||
itemstr = jprint(obj,1); |
|||
} |
|||
break; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
if ( itemstr == 0 ) |
|||
return(clonestr("{\"error\":\"cant find coin balance, are you sure it isnt empty account?\"}")); |
|||
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; int32_t i,j,n; |
|||
struct destbuf uuidstr; uint8_t databuf[512]; |
|||
if ( (extra= *retstrp) != 0 ) |
|||
*retstrp = 0; |
|||
if ( (dir= flip_for_exchange(pairstr,"%s-%s","BTC",dir,&price,&volume,base,rel)) == 0 ) |
|||
{ |
|||
return(0); |
|||
} |
|||
sprintf(payload,"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)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 |
@ -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; i<sizeof(btcpairs)/sizeof(*btcpairs); i++) |
|||
if ( strcmp(btcpairs[i],rel) == 0 ) |
|||
return(-1); |
|||
} |
|||
else if ( strcmp(rel,"BTC") == 0 ) |
|||
{ |
|||
for (i=0; i<sizeof(btcpairs)/sizeof(*btcpairs); i++) |
|||
if ( strcmp(btcpairs[i],base) == 0 ) |
|||
return(1); |
|||
} |
|||
else if ( strcmp(base,"CNY") == 0 ) |
|||
{ |
|||
for (i=0; i<sizeof(cnypairs)/sizeof(*cnypairs); i++) |
|||
if ( strcmp(cnypairs[i],rel) == 0 ) |
|||
return(-1); |
|||
} |
|||
else if ( strcmp(rel,"CNY") == 0 ) |
|||
{ |
|||
for (i=0; i<sizeof(cnypairs)/sizeof(*cnypairs); i++) |
|||
if ( strcmp(cnypairs[i],base) == 0 ) |
|||
return(1); |
|||
} |
|||
printf("BTC38 doesnt support (%s/%s)\n",base,rel); |
|||
return(0); |
|||
} |
|||
|
|||
cJSON *SIGNPOST(void **cHandlep,int32_t dotrade,char **retstrp,struct exchange_info *exchange,char *payload,char *path) |
|||
{ |
|||
char cmdbuf[2048],url[1024],buf[1024],hdr1[512],hdr2[512],hdr3[512],hdr4[512],digest[33],*data; |
|||
cJSON *json; uint64_t nonce; |
|||
hdr1[0] = hdr2[0] = hdr3[0] = hdr4[0] = 0; |
|||
json = 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)); |
|||
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 |
|||
|
@ -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 |
@ -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); |
|||
} |
@ -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 |
@ -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 |
|||
|
@ -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:<hash>") #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 |
|||
|
@ -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 |
|||
|
@ -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 |
@ -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 |
|||
|
@ -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 <curl/curl.h> |
|||
#include <curl/easy.h> |
|||
|
|||
#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 |
@ -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; slot<maxdepth; slot++) |
|||
{ |
|||
bid = &bidasks[slot << 1], ask = &bidasks[(slot << 1) + 1]; |
|||
if ( endb == 0 && bid->price > 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||i<m; i++) |
|||
{ |
|||
for (bidask=0; bidask<2; bidask++) |
|||
{ |
|||
offerNXT = orderid = 0; |
|||
price = volume = 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(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; i<n; i++) |
|||
{ |
|||
item = jitem(array,i); |
|||
if ( (txid= juint(item,quoteid_field)) == quoteid ) |
|||
{ |
|||
json = cJSON_CreateObject(); |
|||
jaddstr(json,"result",historyflag == 0 ? "order still pending" : "order completed"); |
|||
jadd(json,"order",cJSON_Duplicate(item,1)); |
|||
free_json(array); |
|||
return(jprint(json,1)); |
|||
} |
|||
} |
|||
} |
|||
if ( array != 0 ) |
|||
free_json(array); |
|||
} |
|||
return(0); |
|||
} |
|||
|
|||
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<n; i++) |
|||
{ |
|||
if ( strcmp(pairs[i][0],base) == 0 && strcmp(pairs[i][1],rel) == 0 ) |
|||
return(1); |
|||
else if ( strcmp(pairs[i][0],rel) == 0 && strcmp(pairs[i][1],base) == 0 ) |
|||
return(-1); |
|||
} |
|||
printf("cant find.(%s/%s) [%s/%s].%d\n",base,rel,pairs[0][0],pairs[0][1],n); |
|||
return(0); |
|||
} |
|||
|
|||
// following includes C code directly
|
|||
#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" |
|||
|
|||
char *exchanges777_process(struct exchange_info *exchange,int32_t *retvalp,struct exchange_request *req) |
|||
{ |
|||
char *retstr = 0; int32_t dir; uint64_t orderid; double balance; cJSON *balancejson,*retjson; |
|||
*retvalp = EXCHANGE777_DONE; |
|||
switch ( req->func ) |
|||
{ |
|||
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; i<maxseconds; i++) |
|||
if ( *retstrp != 0 ) |
|||
return(*retstrp); |
|||
return(clonestr("{\"error\":\"request timed out\"}")); |
|||
} |
|||
|
|||
char *exchanges777_Qtrade(struct exchange_info *exchange,char *base,char *rel,int32_t maxseconds,int32_t dotrade,int32_t dir,double price,double volume,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)); |
|||
req->argjson = 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<sizeof(Exchange_names)/sizeof(*Exchange_names); i++) |
|||
{ |
|||
if ( strcmp(exchangestr,Exchange_names[i]) == 0 ) |
|||
return(i); |
|||
} |
|||
return(-1); |
|||
} |
|||
|
|||
struct exchange_info *exchanges777_find(char *exchangestr) |
|||
{ |
|||
int32_t exchangeid; |
|||
if ( (exchangeid= exchanges777_id(exchangestr)) >= 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; i<sizeof(funcs)/sizeof(*funcs); i++) |
|||
{ |
|||
if ( strcmp(exchangestr,funcs[i].name) == 0 ) |
|||
{ |
|||
break; |
|||
} |
|||
} |
|||
if ( i == sizeof(funcs)/sizeof(*funcs) ) |
|||
{ |
|||
printf("cant find exchange.(%s)\n",exchangestr); |
|||
return(0); |
|||
} |
|||
exchange = calloc(1,sizeof(*exchange)); |
|||
exchange->issue = 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; i<sizeof(Exchange_names)/sizeof(*Exchange_names); i++) |
|||
exchanges777_info(Exchange_names[i],sleepflag,argjson); |
|||
} |
|||
|
|||
#include "../includes/iguana_apidefs.h" |
|||
|
|||
THREE_STRINGS_AND_THREE_INTS(InstantDEX,orderbook,exchange,base,rel,depth,allfields,invert) |
|||
{ |
|||
struct exchange_info *ptr; |
|||
if ( (ptr= exchanges777_info(exchange,1,json)) != 0 ) |
|||
return(exchanges777_Qprices(ptr,base,rel,juint(json,"maxseconds"),allfields,invert,depth,json)); |
|||
else return(clonestr("{\"error\":\"cant find or create exchange\"}")); |
|||
} |
|||
|
|||
THREE_STRINGS_AND_THREE_DOUBLES(InstantDEX,buy,exchange,base,rel,price,volume,dotrade) |
|||
{ |
|||
struct exchange_info *ptr; |
|||
if ( (ptr= exchanges777_info(exchange,1,json)) != 0 ) |
|||
return(exchanges777_Qtrade(ptr,base,rel,juint(json,"maxseconds"),dotrade,1,price,volume,json)); |
|||
else return(clonestr("{\"error\":\"cant find or create exchange\"}")); |
|||
} |
|||
|
|||
THREE_STRINGS_AND_THREE_DOUBLES(InstantDEX,sell,exchange,base,rel,price,volume,dotrade) |
|||
{ |
|||
struct exchange_info *ptr; |
|||
if ( (ptr= exchanges777_info(exchange,1,json)) != 0 ) |
|||
return(exchanges777_Qtrade(ptr,base,rel,juint(json,"maxseconds"),dotrade,-1,price,volume,json)); |
|||
else return(clonestr("{\"error\":\"cant find or create exchange\"}")); |
|||
} |
|||
|
|||
THREE_STRINGS_AND_DOUBLE(InstantDEX,withdraw,exchange,base,destaddr,amount) |
|||
{ |
|||
struct exchange_info *ptr; |
|||
if ( (ptr= exchanges777_info(exchange,1,json)) != 0 ) |
|||
return(exchanges777_Qrequest(ptr,'W',base,0,juint(json,"maxseconds"),0,destaddr,amount,json)); |
|||
else return(clonestr("{\"error\":\"cant find or create exchange\"}")); |
|||
} |
|||
|
|||
THREE_STRINGS(InstantDEX,supports,exchange,base,rel) |
|||
{ |
|||
struct exchange_info *ptr; |
|||
if ( (ptr= exchanges777_info(exchange,1,json)) != 0 ) |
|||
return(exchanges777_Qrequest(ptr,'S',base,rel,juint(json,"maxseconds"),0,0,0,json)); |
|||
else return(clonestr("{\"error\":\"cant find or create exchange\"}")); |
|||
} |
|||
|
|||
TWO_STRINGS(InstantDEX,balance,exchange,base) |
|||
{ |
|||
struct exchange_info *ptr; |
|||
if ( (ptr= exchanges777_info(exchange,1,json)) != 0 ) |
|||
return(exchanges777_Qrequest(ptr,'B',base,0,juint(json,"maxseconds"),0,0,0,json)); |
|||
else return(clonestr("{\"error\":\"cant find or create exchange\"}")); |
|||
} |
|||
|
|||
TWO_STRINGS(InstantDEX,orderstatus,exchange,orderid) |
|||
{ |
|||
struct exchange_info *ptr; |
|||
if ( (ptr= exchanges777_info(exchange,1,json)) != 0 ) |
|||
return(exchanges777_Qrequest(ptr,'P',0,0,juint(json,"maxseconds"),calc_nxt64bits(orderid),0,0,json)); |
|||
else return(clonestr("{\"error\":\"cant find or create exchange\"}")); |
|||
} |
|||
|
|||
TWO_STRINGS(InstantDEX,cancelorder,exchange,orderid) |
|||
{ |
|||
struct exchange_info *ptr; |
|||
if ( (ptr= exchanges777_info(exchange,1,json)) != 0 ) |
|||
return(exchanges777_Qrequest(ptr,'C',0,0,juint(json,"maxseconds"),calc_nxt64bits(orderid),0,0,json)); |
|||
else return(clonestr("{\"error\":\"cant find or create exchange\"}")); |
|||
} |
|||
|
|||
STRING_ARG(InstantDEX,openorders,exchange) |
|||
{ |
|||
struct exchange_info *ptr; |
|||
if ( (ptr= exchanges777_info(exchange,1,json)) != 0 ) |
|||
return(exchanges777_Qrequest(ptr,'O',0,0,juint(json,"maxseconds"),0,0,0,json)); |
|||
else return(clonestr("{\"error\":\"cant find or create exchange\"}")); |
|||
} |
|||
|
|||
STRING_ARG(InstantDEX,tradehistory,exchange) |
|||
{ |
|||
struct exchange_info *ptr; |
|||
if ( (ptr= exchanges777_info(exchange,1,json)) != 0 ) |
|||
return(exchanges777_Qrequest(ptr,'H',0,0,juint(json,"maxseconds"),0,0,0,json)); |
|||
else return(clonestr("{\"error\":\"cant find or create exchange\"}")); |
|||
} |
|||
|
|||
THREE_STRINGS(InstantDEX,apikeypair,exchange,apikey,apisecret) |
|||
{ |
|||
struct exchange_info *ptr; |
|||
if ( (ptr= exchanges777_info(exchange,1,json)) != 0 ) |
|||
{ |
|||
if ( apikey != 0 && apikey[0] != 0 && apisecret != 0 && apisecret[0] != 0 ) |
|||
{ |
|||
safecopy(ptr->apikey,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" |
File diff suppressed because it is too large
File diff suppressed because it is too large
Loading…
Reference in new issue