mpex 0.4.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 2454a26f57e35fe68ee81fa629266788b3eb9059
4
+ data.tar.gz: 665b68f17bb164db43c929ac19f521e625e1fdd0
5
+ SHA512:
6
+ metadata.gz: 2f91599220b2d73afc0e3e17fdc3a3282cf5b752de040ffb72a1dbbc23bc507cf4e7084d6d9416471a99c5633f839d05a9d5cc338645b371945f3372edea2370
7
+ data.tar.gz: 7ad5a9da36bd1995f0b3be3aac944e9f9d0fe1bb706b0e2be4540ff4870ab89c3aecf4a4f719fd3d4c23307e782b72ef6c77dc66ead45706717661ca1df3c3b5
data/FAQ.html ADDED
@@ -0,0 +1,240 @@
1
+ <h1>MPEx FAQ</h1>
2
+
3
+ Original can be found at <a href="http://mpex.co/faq.html">http://mpex.co/faq.html</a> by Mircea Popescu.
4
+
5
+ <div style="float: right; padding:6px;">Last revision : February the 6th, 2013.</div>
6
+ <h3><a href="#1" name="1">1.</a> <i>Dear Lord, what is this ?</i></h3><ul>
7
+
8
+ Yes, this is dog.
9
+
10
+ </ul><h3><a href="#2" name="2">2.</a> <i>What is an MPSIC ?</i></h3><ul>
11
+
12
+ Short for Mircea Popescu Standard Identification Code. It's true that it's not very standard, but on the other hand it's very code-y, so it all evens out in the end.
13
+
14
+ </ul><h3><a href="#3" name="3">3.</a> <i>So how do I use this thing ?</i></h3><ul>
15
+
16
+ First, you need to get registered. Export your public key (gpg --armor --output pubkey.txt --export 'Your Name') and <a href=http://polimedia.us/trilema/wp-content/uploads/office.jpg>email</a> it. Make sure you include the exact phrase "I understand that I will be required to pay 30 BTC as fees for registering this account, and I agree and promise to do so" or your email will be discarded unread. This is unfortunately necessary <a href=http://polimedia.us/trilema/2013/because-most-people-are-idiots-in-spite-of-never-manning-up-and-admitting-to-it/>because idiots</a>.
17
+ <br /><br />
18
+ You will be thus added to the list of people who can deal on MPEx, and as soon as you are you'll be ready to issue new orders.
19
+ <br /><br />
20
+ If you wish you may encrypt your key first, use Mircea Popescu's key (gpg --encrypt --armor -r 2FB7B452 also gpg --search-keys "2FB7B452" if gpg complains about not having the key). This will ensure higher anonymity if it justifies the effort for you.
21
+ <br /><br />
22
+ If none of this makes any sense you might want to check out the <a href=http://www.gnupg.org/>gpg documentation</a>.
23
+
24
+ </ul><h3><a href="#4" name="4">4.</a> <i>What orders are available ?</i></h3><ul>
25
+
26
+ STAT, STATJSON, BUY, SELL, CANCEL, WITHDRAW, DEPOSIT, DIVIDEND, PUSH, SPLIT, MKOPT, MKFUT and EXERCISE so far.
27
+
28
+ </ul><h3><a href="#5" name="5">5.</a> <i>Syntax ?</i></h3>
29
+
30
+ <ul><li>STAT requests a human-readable account statement. The trade and dividend history returned start with the first transaction after a point in time one hour previous to the last STAT issued to that user. For active daytrading accounts it is advisable to run some form of STAT programatically once a day for bookkeeping purposes. Brokerage houses with lots of clients and lots of activity may consider doing it even more often. Low trade frequency investors are still advised to run STAT once a month. In all cases please keep your STAT receipts, they are issued to protect you.
31
+ <br /><br />
32
+ Due to the cuantic nature of the Universe and other causes, STAT results are not infinitely up to date. If a transaction is in the process of being executed or cleared your involved bid/ask may or may not appear in the STAT, your holdings may or may not reflect the new acquisition/sale and your history may or may not include the executing or clearing transaction. In general these transient states resolve in sub-second time.</li>
33
+ <br /><li>STATJSON requests the same data in JSON format. </li>
34
+ <br /><li>BUY|{MPSIC}|{quantity}|{price}|{expiry} or SELL|{MPSIC}|{quantity}|{price}|{expiry}. Replace curly braces with the actual intended values. MPSIC must be stated and be a valid MPSIC. Quantity must be stated and be a positive integer. Price may be absent in which case your order will be executed at market. If price is given it must be a positive integer (expressed in satoshi, there's 100000000 satoshi in 1 bitcoin - that's eight zeroes). Expiry may be absent in which case your order never expires, but if stated must be given in unixtime format (seconds since epoch) and be after current server time (you can verify this with a STAT).</li>
35
+ <br /><li>CANCEL|{order id} (you get the order ids from a stat) will knock out the order from the book, returning you the shares/money in reserve there. Notice that CANCEL can not undo an already executed trade.</li>
36
+ <br /><li>WITHDRAW|{1YoUrBiTcOiNaDdReSs987654321098765}|{sum}, where the sum is an integer, written in satoshi (note that there's a minimum of 50000 to withdraw, equivalent to 0.0005 BTC). Bear in mind that if you zero out your account it will become inactive and you won't be able to sell any symbols. You can use this feature to lock your account for whatever reason (vacation, changing of pgp key etc). If you don't mean to lock the account make sure you leave a few miliBTC in.</li>
37
+ <br /><li>DEPOSIT|{sum}, where the sum is an integer, written in BTC (note that you can not deposit less than 10 BTC). You will be quoted an exact sum, which you must send to the exchange address (1Fx3N5iFPDQxUKhhmDJqCMmi3U8Y7gSncx). Don't round anything, the decimals are there to identify you as the beneficiary. You will be credited the full amount. <strong><font color=red>Incoming Bitcoin that doesn't exactly match a quoted sum will be simply kept, reported as profits and distributed to MPEx shareholders.</font></strong></li>
38
+ <br /><li>DIVIDEND|{MPSIC}|{total dividend to pay}|{notional float}, where the total dividend to pay is equal to... the total dividend you pay (in satoshi) and the notional float is the total amount of shares in circulation (as established in your IPO contract). MPEx will handle the distribution. It is safe to send small sums (ie, a 1 BTC total dividend on a 5.2 million notional float will yield the correct 0.00019230 BTC dividend to the holder of a 1k share block).</li>
39
+ <br /><li>PUSH|{MPSIC}|{40 char key fingerprint}|{qty}, which allows you to push an asset (including BTC) to another account on MPEx. This is free of charge but <b>it does not check if the keyid exists</b> so please, for the love of all that is holy, make sure you don't send your stocks to limbo.</li>
40
+ <br /><li>SPLIT|{MPSIC}|{btc}, which allows you to split a number of whole BTCs into CALL-PUT pairs for a given strike. Say you want to sell short CALLS and PUTS all struck at 5.0 expiring this month. Provided you have 100 BTC in your account you go SPLIT|O.BTCUSDC050T|100 (or SPLIT|O.BTCUSDP050T|100, same thing) and voila, you now have 50 CALLS @5.0 (and a number of PUTS @5.0 based on the strike/current BTC/USD ratio) in your account, which you can sell. At the month's end you will receive the 100 BTC back, minus any costs resulting from exercises.</li>
41
+ <br /><li>MKOPT|{MPSIC}|{qty}, which allows you to create a number of the quoted contracts, provided you have the BTC to put up as collateral. Each CALL requires 1 BTC of collateral irrespective of strike. Each PUT requires an amount of collateral equal to strike / spot BTC . Bear in mind that whenever someone exercises options of your symbol you will be allocated a portion of the executions corresponding to your total share of created contracts for that symbol. Thus if you create 100 O.BTCUSD.C50T and someone else creates 150, in case there's an execution of 50 contracts you will be assigned 20 of those.</li>
42
+ <br /><li>MKFUT|{MPSIC}|{qty}, which allows you to create a number of the quoted contracts, provided you have the BTC to put up as collateral. Each contract requires 1.8x its last settlement value. Once the contracts settle you will be credited deposited collateral minus the settlement value of the contracts.</li>
43
+ <br /><li>EXERCISE|{MPSIC}|{qty}, which allows you to exercise a number of option contracts.</li>
44
+ </ul>
45
+ <h3><a href="#6" name="6">6.</a> <i>But how do I actually send an order ?</i></h3><ul>
46
+
47
+ Sending an order works like this : you clearsign your order (gpg --clearsign), then you encrypt the result with the exchange's public key (gpg --encrypt --armor -r F1B69921). If you don't have that key try gpg --search-keys 'F1B69921'. The exchange answers with a signed message encrypted with your own public key, which you can decrypt at will. You don't have to use the web interface at all, you can POST directly to the script (via for instance curl).
48
+ <br /><br />
49
+ If that didn't make any sense to you :
50
+ <ol>
51
+ <br /><li>Open up a terminal. On Ubuntu you press Ctrl+Alt+T. On Os/X (Macs) you navigate to /Applications/Utilities and double-click on Terminal. In Windows you click Start > Run > cmd.exe.</li>
52
+ <br /><li>Type gpg --clearsign, hit Enter. If it complains that it can't find gpg, you have to navigate to the directory where you have it installed. If you have ever identified with gribble you certainly have it installed. If you never did, aren't part of the <a href=http://bitcoin-otc.com/viewratings.php>WOT</a> etc you should go get it right now. Trying to be part of a <em>crypto</em>currency without knowing how to use gpg is like trying to be part of the 60s without knowing how to use a bong. If you're on Windows <a href=http://www.gpg4win.org/about.html>this</a> is a good place to start. Also make sure you read the documentation, for instance <a href=http://www.madboa.com/geek/gpg-quickstart/>here</a>.</li>
53
+ <br /><li>Type your passphrases if prompted for it, hit Enter. Don't panic if nothing seems to happen and you just get a blinky cursor, this is RMS-style user interface.</li>
54
+ <br /><li>Type your command for MPEx, such as STAT, then hit Ctrl-d and Ctrl-d again. (On some systems such as Windows this might be Ctrl-z instead. Whatever EOF is on your system, that's what you need.)</li>
55
+ <br /><li>Type gpg --encrypt --armor -r F1B69921, hit Enter.</li>
56
+ <br /><li>If prompted for confirmation on whether to trust the key press y, hit Enter. This means you haven't signed the key, please do so (type gpg --sign-key F1B69921 hit Enter then gpg --send-key F1B69921 hit Enter.).</li>
57
+ <br /><li>Paste the clearsigned message from before. Get the whole thing, don't just copy the signature block. It starts with "-----BEGIN PGP SIGNED MESSAGE-----". Hit Ctrl-d and Ctrl-d again.</li>
58
+ <br /><li>Paste the gnarly result into the MPEx box, "Output as html" checked (it's checked by default).</li>
59
+ <br /><li>Copy the resulting message.</li>
60
+ <br /><li>Go back to terminal, type gpg, hit Enter.</li>
61
+ <br /><li>Paste message, Ctrl-d and Ctrl-d again.</li>
62
+ <br /><li>If prompted for passphrase type it in, hit Enter. It'll pop up your sig info, hit Ctrl-d.</li>
63
+ <br /><li>At this point you are looking at the exchange's response. If it complains that you pasted mangled output you probably didn't correctly copy/paste things. If it doesn't complain then congratulations! You've made it.</li>
64
+ </ol>
65
+
66
+ </ul><h3><a href="#7" name="7">7.</a> <i>You mean I have to do all that by hand all the time ?</i></h3><ul>
67
+
68
+ Not really. Give a look to <a href=https://github.com/Azelphur/pyMPEx>pyMPEx</a>, the python script contributed by Azelphur. If you don't have or don't like python there's also <a href=https://github.com/modsix/bitotter_perl>a perl equivalent</a>, contributed by mod6. Also there are some projects in the works by people in the community to develop broker sites on top of the MPEx infrastructure. If you're part of the evil Windows empire aegis was nice enough to make a <a href=http://github.com/ageis/MPEx-bin>stand-alone 32bit exe</a> compile. Also a Mac version. Same place.
69
+
70
+ </ul><h3><a href="#8" name="8">8.</a> <i>Apparently gpg can't find F1B69921 ?</i></h3><ul>
71
+
72
+ You need port 11371 open for gpg to be able to find keys. If all else fails, gpg --import and paste the below :<br /><br />
73
+ -----BEGIN PGP PUBLIC KEY BLOCK-----<br />
74
+ Version: GnuPG v1.4.9 (GNU/Linux)<br />
75
+ <br />
76
+ mQGiBE9cKo4RBACdRJfDLOsztjn22MN36kj2F0DDU17Bcq40kYpfW8DKVIDUJngP<br />
77
+ AYgHhrt0WIRP7X+njs7/c9a0S0z2ysC1W9knf/iC4RWO2ofiCaMpdpzIJ433O+nR<br />
78
+ S64gu9ameP/RZXcpy7rRI9jD6y+aeVKtbxEuGqChYw0clPg1Gh7m+YdGiwCgpn5n<br />
79
+ Pq0pp6eXDoh4yssVcEWReXsD/jvhjFl6PRlt+L5ZS6cLQCuBH7/uCt0AXdeydbSU<br />
80
+ 6OE9DeRo1XRd3Cn6Y5hcTzTSEph/JBse374WSwbzOXGiKVEaX5hgKo/BXw+Ne7ae<br />
81
+ XJGx1EUhGdGTn4V5Xu04KkpOn/O6Vu6BOEnML2xKtkQnCbkvG+Y2YDSLU6ZYHaPd<br />
82
+ YGStA/4jS03b128dR+ETbBrUqZtlNOlBW9f38R1mO192LHmc8v4Jtq4bbhGt0/rV<br />
83
+ qRaCqCcS8vaQQrNYR9xyqVeX0wjZya3dXdKve6+ZGTwFaJP6vxTkAH/J4g5uP7T6<br />
84
+ Kb2rmAjuVEimEl6oBmyUjyyynghJWq9AAZcZfkUT8iQBEOqyQ7RMTVAgU3RvY2sg<br />
85
+ RXhjaGFuZ2UgKFZpc2l0IGh0dHA6Ly9wb2xpbWVkaWEudXMvYml0Y29pbi8pIDxv<br />
86
+ ZmZpY2VAcG9saW1lZGlhLnVzPohmBBMRAgAmBQJPXCqOAhsDBQkB4TOABgsJCAcD<br />
87
+ AgQVAggDBBYCAwECHgECF4AACgkQkhT8a/G2mSHobwCfamcRWvl7kvOUP7koIKc0<br />
88
+ OOtcxdUAniPmSrdPNOhiTO0i82EqXw8ngccsuQINBE9cKpIQCADQCMqkdQg91uJP<br />
89
+ qMCzFMGUx2GShG6gTleNibkcSgRJ2mOGoZ1lYMvyX+wZfrDWgFRMkj7DQ2wN4M1S<br />
90
+ DMgaO3nSKPzYSVWfGu2+NapApr4pctFSJAHDX9SAN/iI03BSU66oH7xaNoOcDvcL<br />
91
+ Wq2sv2InSsv29Dwt8fBtnd7/GFATxx+hsXzUVOfhuukw3FjMJsfANDvk6pq+4mj9<br />
92
+ VVUaFjdnjyv8mXEd3LAslh4WpgavnGiowRzsjYall62+hB0BwOmze8Me+XpaVdlQ<br />
93
+ h/7Vg5/2FPBeq0AKafxgDzpmzjv8mTMdozT7WNCaJx/jnJsMzlEDTkKmxWcen3KH<br />
94
+ jef3GEB3AAMFCAC0I9PjZcJodK8srx7Dlr3dlRpLEcbb4FIo4GQL9839LYtmHg9f<br />
95
+ y8eVh0nGWOXhtMeM5BdT609R5Amidq+u9ek9UP2zWevWXe4FzwYR87HdMS8eeho/<br />
96
+ sS46CzRcXAp2rIusJIa8xFC8ORbGeyfq7f4OIgE4fVNkGYOB2vJ7urkSVf2HpUhd<br />
97
+ 1LXZ7i3mVUlanGmw1wpGSTs92UnnuDMK1LyjSqlV7XpTADSc1Hu6IX0aD/ZYoFCo<br />
98
+ i1QBegdnTmsqOVam6rlfXadGv4al1bKaSoWMEDHuHc9uxgXBfu9eZBiSx5Jh94K6<br />
99
+ xPKFbsv6C7JuR38/yOd66KogzAKml+u2x821iE8EGBECAA8FAk9cKpICGwwFCQHh<br />
100
+ M4AACgkQkhT8a/G2mSGYBgCfUZo6sAQTqBP1Yj/uimYchwXJu5oAn23wZiriVCHq<br />
101
+ 1zyvnUmYeiH+q9xR<br />
102
+ =oQGJ<br />
103
+ -----END PGP PUBLIC KEY BLOCK-----
104
+
105
+ </ul><h3><a href="#9" name="9">9.</a> <i>Why doesn't PUSH check if the destination account exists ? That's no way to run an exchange!</i></h3><ul>
106
+
107
+ If it did check then a snoop could find out whether a given account exists or not.
108
+
109
+ </ul><h3><a href="#10" name="10">10.</a> <i>You know those charts without any indication of scale ? That's not how charts work.</i></h3><ul>
110
+
111
+ Yes, well, trying to do the best in a limited space. The charts flow left to right (oldest data left, newest data right). Each column/dot represents a day, for 30 days total rolling window (so, past 24 hours = today ; 24 to 48 hours ago = yesterday etc). Vertically the scale for volume can be gleaned from the last day's volume, which is given as a numerical value whereas the scale for prices can be gleaned from the month's min/max prices, which are also given as numerical values.
112
+ <br /><br />
113
+ Also, you might wish to check out <a href=http://live.coinbr.com/?mpsic=S.MPOE>live.coinbr.com</a>.
114
+
115
+ </ul><h3><a href="#11" name="11">11.</a> <i>What about data feeds ?</i></h3><ul>
116
+
117
+ For the perennially curious there's a transactions <a href=http://mpex.co/mpex-rss.php>RSS feed</a> as well as a <a href=http://bitcoin-assets.com/mpex-socket/>socket connection</a> (with SierraCharts plugin) and a <a href="https://twitter.com/#!/mpex1" rel="nofollow">twitter feed</a>. For the bot builder in all of us there's a 1d/7d/30d rolling window <a href=http://mpex.co/mpex-vwap.php>volume-weighted average price json</a> as well as a full <a href=http://mpex.co/mpex-mktdepth.php>market depth json</a>.
118
+
119
+ </ul><h3><a href="#12" name="12">12.</a> <i>Are there any fees ?</i></h3><ul>
120
+
121
+ There is a 30BTC fixed fee for adding your public key to the MPEx. This is a one-time fee. All sellers are assesed a 0.2% fee at the moment the sale completes (so if you sell 500 stocks for 100 satoshi each you get 49`900 satoshi or 0.000499 BTC). All MKOPT and MKFUT orders are assesed a 2% fee (SPLIT orders are free).
122
+
123
+ </ul><h3><a href="#13" name="13">13.</a> <i>Is there some way I could be an affiliate ?</i></h3><ul>
124
+
125
+ Sure. If you already have an account and someone mentions your keyid when they sign up for a new account each of you will be credited 5 BTC. Simple as pie.
126
+
127
+ </ul><h3><a href="#14" name="14">14.</a> <i>So why would I use MPEx ?</i></h3><ul>
128
+
129
+ Lowest transaction fees, significantly more market depth, better security, higher uptime and faster response than anywhere else. Among other things. O, and margin.
130
+
131
+ </ul><h3><a href="#15" name="15">15.</a> <i>Margin ?!</i></h3><ul>
132
+
133
+ Yes, MPEx allows you to trade on margin. To qualify you must have a solid <a href=http://bitcoin-otc.com/viewratings.php>WOT rating</a> and considerable trade volume on MPEx. Amounts and rates negotiable, you will have to talk to mircea_popescu (usually in #bitcoin-assets, or alternatively <a href=http://polimedia.us/trilema/wp-content/uploads/office.jpg>email</a>) to get yours.
134
+ <br /><br />
135
+ Note that margin doesn't work in the "traditional" way, moreover you get the lump sum added to your account. Note that you will be required to gpg-sign a commitment to repay with specific terms. All withdrawals made while margined will go towards reducing the margin first.
136
+
137
+ </ul><h3><a href="#16" name="16">16.</a> <i>Do you pay interest on balances ?</i></h3><ul>
138
+
139
+ MPEx has in the past paid 80% of the MPBOR (MPOE Bonds Offered Rate, the interest rate as fixed by the monthly bond auction detailed <a href=http://polimedia.us/trilema/2012/sa-ne-jucam-de-a-investitiile-n-bitcoini/#comment-78745>here</a>). This is currently suspended (since July 2012). The feature may be reintroduced.
140
+
141
+ </ul><h3><a href="#17" name="17">17.</a> <i>Yes but 30 BTC for registering ? That's extortion!</i></h3><ul>
142
+
143
+ That fee was waived for about a month during the beta, so at the very least it'd have to be a combination of extortion with laziness. Then it was 20 BTC. Now it's 30 BTC. The fee is projected to keep going up for the undetermined future.
144
+
145
+ </ul><h3><a href="#18" name="18">18.</a> <i>How do I go about taking advantage of this vaunted "100% security" ?</i></h3><ul>
146
+
147
+ <b>Step 1.</b> Create a new GPG key <i>on a machine that never connects to the Internet</i>. Do not advertise this key anywhere, do not register it with gribble, do not use it anywhere at all.
148
+ <br /><b>Step 2.</b> Email the public key encrypted as described above.
149
+ <br /><b>Step 3.</b> Make your first deposit (make sure it covers for the account registration fee). Note that due to the encoding <em>it does not matter where the payment comes from</em>. You can withdraw the money from a pool or MtGox or pretty much any public service which allows bitcoin withdrawals to a specified address.
150
+ <br /><b>Step 4.</b> Your account is now set up, you can use it in full confidence. Yes, this includes the inconvenient step of transferring GPG-encoded strings from a cold machine to a hot machine. Security always comes at a cost of convenience.
151
+ <br /><br />
152
+ Some important points to keep in mind : <ul><br />
153
+ <li>The machine handling encryption and decryption on the MPEx side never connects to the Internet. There is no cable. As such, it does not even do updates of keys. Should your key become expired or revoked <strong><font color=red>you will have to create a new account</font></strong>. We will not transfer your assets for you if it cannot be established beyond the shadow of a doubt that they are in fact yours. Please handle key expiration and revocation responsibly.
154
+ </li><br /><li>Internet-facing machines do hold copies of the database. They are reasonably secured, which probably means they are more secure than most any other bitcoin-based application at this time. However, their absolute security is not considered a strategic priority and no extraordinary measures are undertaken to ensure it. Provided that an attacker manages to breach one or all such machines it would be possible for that attacker to acquire a copy of the list of all accounts (not emails, but keyids), their transaction history, assets and so forth. If you follow Step 1 above even in this scenario the attacker gains no benefit : he now knows that "someone" owns so-and-so assets, which is information he could have compiled anyway watching the tickers on irc/twitter etc. If you do not follow Step 1 above it is possible for your assets holdings to be identified in this (unlikely) scenario. If you value your anonimity do follow Step 1 above.
155
+ </li><br /><li>While it is true that an attacker could, in extraordinary circumstances, acquire a snapshot of the database, it is not true that an attacker could commit alterations to it, even in the event that he controls without being detected all the machines used for running MPEx. We have numerous data integrity procedures in place, many of which <em>are not automated</em>.
156
+ </li><br /><li>Due to the fact that all information is gpg-encrypted you can safely use any proxies or tor networks; you can even send all your orders from the local public library. If your anonymity is important to you you are well advised to do exactly that.
157
+ </li><br /><li>Due to the way the system is designed, even in the case of catastrophic breach of the gpg protocol (if overnight someone finds a way to reliably and cheaply crack keys) <em>your account is not immediately at risk</em>, provided you have followed Step 1 above. Only a combination of this scenario with the previously discussed scenario is actually dangerous. Should in fact such a catastrophic breach of the gpg protocol occur we will immediately take supplementary security measures utterly paranoid in their extension to ensure the machines will not be compromised for the interim in which a solution is found.
158
+ </ul>
159
+ <br /><br />
160
+ In short : secret gpg keyid + anonymous IPs = perfect security. Not so secret gpg key, not so anonymous IPs = imperfect security. The exact level of security that best fits your needs is yours to determine. Please consider these points carefully and draw up your own strategy and policies.
161
+
162
+ </ul><h3><a href="#19" name="19">19.</a> <i>Do you use Google Analytics ?</i></h3><ul>
163
+
164
+ No. Making a BTC financials website and then slapping GA on it is really akin to going to a cancer survivor's survival party and bringing them chemo drugs as a gift. Yes, it's that insulting/thoughtless. Really. Yes, it does show that level of outright contempt for the user. Really.
165
+ <br /><br />
166
+ Also GA does break Tor in many cases.
167
+
168
+ </ul><h3><a href="#20" name="20">20.</a> <i>Was MPEx security ever independently audited ?</i></h3><ul>
169
+
170
+ <a href="http://www.reddit.com/r/Bitcoin/comments/ycgm8/freeforall_pentesting_on_mpex/" rel="nofollow">Sort of</a>.
171
+
172
+ </ul><h3><a href="#21" name="21">21.</a> <i>What happens if your domain(s) or server(s) are confiscated ?</i></h3><ul>
173
+
174
+ In case the domain is confiscated or otherwise lost MPEx will move to a different domain, in a different jurisdiction. Should the same happen again, MPEx would move to what will at the time be a solid alternative for a free Internet, be it the TOR network, namecoin or some equivalent DNS or any comparable solution. No government will ever be able to stop the Internet, in general. We're prepared to show this in the particular.
175
+ <br /><br />
176
+ Should the systems be confiscated or otherwise lost the service will failover to different systems, possibly on bulletproof hosting if need be. If sufficient pressure is put on this side MPEx will be recoded as a p2p system.
177
+
178
+ </ul><h3><a href="#22" name="22">22.</a> <i>Even so, how would the investors be affected in the event MPEx can no longer be continued ?</i></h3><ul>
179
+
180
+ In the unlikely case that the continuation of MPEx becomes impossible, all issuers will be provided with lists of their shareholders. A successor system would have to be constructed (either centralized or maintained independently by the respective issuers), but no information is lost : since people can still sign with their keys, it is trivial for anyone who is in fact a shareholder to identify himself as shareholder. Just to be on the safe side, a dump of all users' final STATs, encrypted with their keys and clearsigned by the exchange will be released before closing, in whatever manner will be deemed at that time efficient, as for instance on a p2p file sharing system.
181
+ <br /><br />
182
+ Also worth mentioning, you can create <a href=http://mpex.co/db_dump.php>your very own copy of the MPEx database</a>, containing sufficient information to reconstruct ownership of coins and shares even if all our back-ups are compromised.
183
+ </ul><h3><a href="#23" name="23">23.</a> <i>What will you do about stolen coins ? How will you help the rightful owner ?</i></h3><ul>
184
+
185
+ By definition the rightful owner of any coins is "he who can send them". If you take issue with that, please stick to fiat. You are not ready for Bitcoin yet.
186
+
187
+ </ul><h3><a href="#24" name="24">24.</a> <i>What will you do in case I can't sign with my key anymore ?</i></h3><ul>
188
+
189
+ Most likely nothing. If either your account is very large and / or I know you I might try to verify you. Maybe. Don't count on it, but instead proceed with the clear state of mind that if you lose your keys you lose your assets. It's healthier.
190
+
191
+ </ul><h3><a href="#25" name="25">25.</a> <i>What is the reference BTC/USD ratio you use for options exercises ?</i></h3><ul>
192
+
193
+ The 24 hour volume-weighted cross-exchange ratio is used, as <a href=http://bitcoincharts.com/markets/currencies/>published by bitcoincharts</a>. The same figure is available in any IRC channel where gribble is present. The command is ;;bc,24hprc
194
+
195
+ </ul><h3><a href="#26" name="26">26.</a> <i>What if that becomes unavailable ?</i></h3><ul>
196
+
197
+ If the service is temporarily unavailable the MPOE market maker bot for options on MPEx will stop quoting. Exercises will occur at the last available price. This has happened a few times in the past, but the interruption never exceeded a couple of hours.
198
+ <br /><br />
199
+ Should the service be unavailable for a longer interval I will devise some other way to obtain the data and calculate the average. In principle I would prefer for a third party to be doing this, but absent such it will be done by MPEx itself.
200
+ <br /><br />
201
+ If for whatever reason there no longer exists a reliable way to calculate average prices (such as for instance MtGox being suddenly and permanently closed or other such catastrophic event) options will be refunded at prices originally paid.
202
+ </ul><h3><a href="#27" name="27">27.</a> <i>Do you hedge your options positions ?</i></h3><ul>
203
+
204
+ No.
205
+
206
+ </ul><h3><a href="#28" name="28">28.</a> <i>Why not ?</i></h3><ul>
207
+
208
+ You can't pull yourself up by your breeches and for the very same reason you can't have everybody in the market hedge. Someone needs to provide the support everyone else relies on to hedge. I'm that someone.
209
+
210
+ </ul><h3><a href="#29" name="29">29.</a> <i>You could at least buy / sell BTC according to your book...</i></h3><ul>
211
+
212
+ No, I could not. For one, the spot is not at all trustworthy yet. For the other, the volume is so low that if I did that I'd cause chaos. Think "microphone next to speaker" sort of situation.
213
+
214
+ </ul><h3><a href="#30" name="30">30.</a> <i>I have a question not answered here, can I get live support ?</i></h3><ul>
215
+
216
+ Yes. #bitcoin-assets or #trilema on <a href=http://webchat.freenode.net/>freenode</a>, look for mircea_popescu.
217
+
218
+ </ul><h3><a href="#31" name="31">31.</a> <i>So did you do it all by yourself ?</i></h3><ul>
219
+
220
+ Not really. While <a href=http://bitcoin-otc.com/viewratingdetail.php?nick=mircea_popescu&sign=ANY&type=RECV&sortby=rating&sortorder=DESC>Mircea Popescu</a> has been managing the project and putting up the capital since the very beginning, most of the code was written and tested by a six man team (of which as it usually turns out two or three individuals did most of the heavy lifting). The economics side is the result of many a late night discussion in a small but loose group of financial professionals (informally known as "the Board") based at least in part on research conducted by a dedicated Market Analysis Desk, which is currently (April 2012) three people. There are a couple of people working secretarial, PR, media buying and other support tasks. In short, MPOE/MPEx is about the size of a small Mormon family.
221
+ <br /><br />
222
+ There has been significant support generously donated by many members of the community, in many shapes and forms - from bug reporting and factual error checking to financial model evaluation etc. These are, listed in alphabetical order and with our sincere thanks : ageis, azelphur, brendio, ezl, cory, jurov, kakobrekla, nanotube, onefixt, mod6, random_cat, rdponticelli, reeses, smickles, sgornick, the00dustin, znort alongside many others. Bitcoin is in fact first and foremost a wonderful community of highly skilled, intelligent and open minded people which tearfully reminds one of the old days of the pre-September Internet.
223
+
224
+ </ul><h3><a href="#32" name="32">32.</a> <i>What happened to the cute little unicorn!</i></h3><ul>
225
+
226
+ *Poof*. Initially I thought adding a few vignettes might be a nice way to showcase community talent and funnel some coins from the rich fat cat to the starving artist, but alas there wasn't much in the way of talent to showcase. Maybe in time.
227
+
228
+ </ul><h3><a href="#33" name="33">33.</a> <i>How do I know you're respectable ? Have you received any awards ?</i></h3><ul>
229
+
230
+ Yes, in point of fact we have. We are the proud recipients of both the respected Slightly Smoky Dragon trophy as well as the coveted Double Cherry Truck insignia. Proof below :
231
+ <br /><br />
232
+ <img src="cherries2.png"> <img src="dragon-1.png">
233
+
234
+ </ul>
235
+
236
+ </ul><h3><a href="#34" name="34">34.</a> <i>Ahh, but did you expect the Spanish Inquisition ?</i></h3><ul>
237
+
238
+ Nobody expects the Spanish Inquisition.
239
+
240
+ </ul>
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in mpex.gemspec
4
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,39 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ mpex (0.4.1)
5
+ cri (~> 2.2)
6
+ gpgme
7
+ highline
8
+ json
9
+ net-yail
10
+
11
+ GEM
12
+ remote: http://rubygems.org/
13
+ specs:
14
+ builder (3.1.4)
15
+ colored (1.2)
16
+ cri (2.3.0)
17
+ colored (>= 1.2)
18
+ cucumber (1.2.1)
19
+ builder (>= 2.1.2)
20
+ diff-lcs (>= 1.1.3)
21
+ gherkin (~> 2.11.0)
22
+ json (>= 1.4.6)
23
+ diff-lcs (1.1.3)
24
+ gherkin (2.11.6)
25
+ json (>= 1.7.6)
26
+ gpgme (2.0.2)
27
+ highline (1.6.15)
28
+ json (1.7.6)
29
+ net-yail (1.6.1)
30
+ rspec-expectations (2.12.1)
31
+ diff-lcs (~> 1.1.3)
32
+
33
+ PLATFORMS
34
+ ruby
35
+
36
+ DEPENDENCIES
37
+ cucumber
38
+ mpex!
39
+ rspec-expectations
data/README.md ADDED
@@ -0,0 +1,28 @@
1
+ # Commandline Client for MPEx
2
+
3
+ ## About
4
+
5
+ Commandline client for [MPEx](http://mpex.co), a Bitcoin security exchange. Make sure to carefully read its [FAQ](http://mpex.co/faq.html) before using it.
6
+
7
+ ## Install
8
+
9
+ * make sure Ruby > 1.9.x or 2.0 and GnuPG are installed
10
+ * gem install mpex
11
+
12
+ ## Usage
13
+
14
+ $ mpex help
15
+
16
+ If you want to use MPEx via IRC, use the interactive mode:
17
+
18
+ $ mpex -i
19
+
20
+ ## License
21
+
22
+ Copyright (c) 2013 Fa Wuxi
23
+
24
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
25
+
26
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
27
+
28
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
data/bin/mpex ADDED
@@ -0,0 +1,19 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # Try loading bundler if it's possible
4
+ begin
5
+ require 'rubygems'
6
+ require 'bundler/setup'
7
+ rescue LoadError
8
+ # no problem
9
+ end
10
+
11
+ # Add lib to load path
12
+ $LOAD_PATH.unshift(File.expand_path(File.dirname(__FILE__) + '/../lib'))
13
+
14
+ require 'mpex'
15
+ require 'mpex/cli'
16
+ require 'mpex/interactive'
17
+ require 'mpex/irc'
18
+
19
+ Mpex::CLI.run(ARGV)
data/lib/mpex/cli.rb ADDED
@@ -0,0 +1,197 @@
1
+ require 'cri'
2
+ require 'json'
3
+
4
+ module Mpex::CLI
5
+
6
+ @cmd = Cri::Command.define do
7
+ name 'mpex'
8
+ usage 'mpex [options] [command] [options]'
9
+ summary 'commandline interface for MPEX trading'
10
+ description <<-DESC
11
+ To change default settings edit ~/.mpex/config.yaml
12
+
13
+ DESC
14
+
15
+ flag :h, :help, 'show help for this command' do |value, cmd|
16
+ puts cmd.help
17
+ exit 0
18
+ end
19
+
20
+ option :s, :url, 'URL to MPEX (defaults to mpex.co)'
21
+ option :u, :keyid, 'key id of your gnupg key to use'
22
+ option :m, :mpexkeyid, 'mpex public key id'
23
+ option :p, :password, 'passphrase of your private key (unless provided you\'ll be asked for it)'
24
+
25
+ opt :i, :interactive, "start alternative interactive mode to mpex, useful for irc" do
26
+ Mpex::Interactive.run
27
+ exit 0
28
+ end
29
+
30
+ opt :v, :version, 'show version information and quit' do
31
+ puts Mpex.version_information
32
+ exit 0
33
+ end
34
+
35
+ end
36
+
37
+ Mpex::Mpex.new.create_configfile_unless_exists # makes sure config file is present
38
+
39
+ @cmd.add_command Cri::Command.new_basic_help
40
+
41
+ @cmd.define_command do
42
+ name 'stat'
43
+ aliases [:STAT, :status]
44
+ usage 'stat [options]'
45
+ summary 'old style standard mpex STAT'
46
+
47
+ run do |opts, args|
48
+ mpex = Mpex::Mpex.new
49
+ mpex.send_plain('STAT', opts) do |answer|
50
+ puts answer
51
+ end
52
+ end
53
+ end
54
+
55
+ @cmd.define_command do
56
+ name 'statjson'
57
+ aliases :STATJSON
58
+ usage 'statjson [options]'
59
+ summary 'STATJSON returns status in json format'
60
+
61
+ run do |opts, args|
62
+ mpex = Mpex::Mpex.new
63
+ mpex.send_plain('STATJSON', opts) do |answer|
64
+ puts answer
65
+ end
66
+ end
67
+ end
68
+
69
+ @cmd.define_command do
70
+ name 'plain'
71
+ aliases :p
72
+ usage "plain [options] 'MPX|FOO|BAR'"
73
+ summary "send string as is signed/encrypted to mpex"
74
+
75
+ run do |opts, args|
76
+ mpex = Mpex::Mpex.new
77
+ mpex.send_plain(args[0], opts) do |answer|
78
+ puts answer
79
+ end
80
+ end
81
+ end
82
+
83
+ @cmd.define_command do
84
+ name 'buy'
85
+ aliases :BUY
86
+ usage "buy [options] [MPSIC] [quantity] [price]"
87
+
88
+ run do |opts, args|
89
+ mpex = Mpex::Mpex.new
90
+ mpsic = mpex.validate_mpsic(args[0])
91
+ if args[2].match(/\./)
92
+ puts "Provide price in Satoshis!"
93
+ exit 0
94
+ end
95
+ order_string = "BUY|#{mpsic}|#{args[1]}|#{args[2]}"
96
+ mpex.send_plain(order_string, opts) do |answer|
97
+ puts answer
98
+ end
99
+ end
100
+ end
101
+
102
+ @cmd.define_command do
103
+ name 'sell'
104
+ aliases :SELL
105
+ usage "sell [options] [MPSIC] [quantity] [price]"
106
+
107
+ run do |opts, args|
108
+ mpex = Mpex::Mpex.new
109
+ mpsic = mpex.validate_mpsic(args[0])
110
+ if args[2].match(/\./)
111
+ puts "Provide price in Satoshis!"
112
+ exit 0
113
+ end
114
+ order_string = "SELL|#{mpsic}|#{args[1]}|#{args[2]}"
115
+ mpex.send_plain(order_string, opts) do |answer|
116
+ puts answer
117
+ end
118
+ end
119
+ end
120
+
121
+ @cmd.define_command do
122
+ name 'cancel'
123
+ aliases :CANCEL
124
+ usage "cancel [options] [order-number]"
125
+
126
+ run do |opts, args|
127
+ mpex = Mpex::Mpex.new
128
+ order_string = "CANCEL|#{args[0]}"
129
+ mpex.send_plain(order_string, opts) do |answer|
130
+ puts answer
131
+ end
132
+ end
133
+ end
134
+
135
+ @cmd.define_command do
136
+ name 'deposit'
137
+ aliases :DEPOSIT
138
+ usage "deposit [options] [amount in BTC]"
139
+
140
+ run do |opts, args|
141
+ mpex = Mpex::Mpex.new
142
+ order_string = "DEPOSIT|#{args[0]}"
143
+ mpex.send_plain(order_string, opts) do |answer|
144
+ puts answer
145
+ end
146
+ end
147
+ end
148
+
149
+ @cmd.define_command do
150
+ name 'withdraw'
151
+ aliases :WITHDRAW
152
+ usage "withdraw [options] [address] [amount in satoshi]"
153
+
154
+ run do |opts, args|
155
+ puts .run('help'); exit 0 unless args.length == 2
156
+ mpex = Mpex::Mpex.new
157
+ order_string = "WITHDRAW|#{args[0]}|#{args[1]}"
158
+ mpex.send_plain(order_string, opts) do |answer|
159
+ puts answer
160
+ end
161
+ end
162
+ end
163
+
164
+ @cmd.define_command do
165
+ name 'orderbook'
166
+ usage 'orderbook [options]'
167
+ summary "show mpex orderbook"
168
+
169
+ run do |opts, args|
170
+ mpex = Mpex::Mpex.new
171
+ mpex.fetch_orderbook do |orderbook|
172
+ puts orderbook
173
+ end
174
+ end
175
+ end
176
+
177
+ @cmd.define_command do
178
+ name 'irc'
179
+ usage 'irc [options]'
180
+ summary 'connects an irc bot to freenode to talk to mpex via its bots'
181
+
182
+ run do |opts, args|
183
+ $IRC_LEAK = Mpex::Irc.new
184
+ $IRC_LEAK.connect
185
+ end
186
+ end
187
+
188
+ def self.run(args)
189
+ @cmd.run(ARGV)
190
+ end
191
+
192
+ def self.command
193
+ @cmd
194
+ end
195
+
196
+ end
197
+
@@ -0,0 +1,50 @@
1
+ module Mpex
2
+ class Converter
3
+
4
+ def self.btc_to_satoshi(btc)
5
+ leftright = btc.to_s.split("\.");
6
+ btcStr = leftright[0];
7
+ satoshiStr = leftright[1];
8
+
9
+ while (satoshiStr.length() < 8) do
10
+ satoshiStr = satoshiStr + "0";
11
+ end
12
+
13
+ resultstr = btcStr + satoshiStr;
14
+ resultstr.to_i.to_s
15
+ end
16
+
17
+ def self.satoshi_to_btc(satoshi)
18
+ satoshiStr = satoshi.to_s;
19
+
20
+ satoshiPart = "";
21
+ btcPart = "0";
22
+
23
+ denominator = "";
24
+
25
+ if (satoshiStr.size > 8)
26
+ btcPart = satoshiStr[0...(satoshiStr.size - 8)];
27
+ satoshiPart = satoshiStr[(satoshiStr.size - 8)..satoshiStr.size];
28
+ else
29
+ if (satoshiStr.start_with?("-"))
30
+ denominator = "-";
31
+ satoshiPart = satoshiStr[1..satoshiStr.size]; # cut denominator
32
+ else
33
+ satoshiPart = satoshiStr;
34
+ end
35
+ while (satoshiPart.size < 8) do
36
+ # prepend zeros
37
+ satoshiPart = "0" + satoshiPart;
38
+ end
39
+ end
40
+
41
+ # cut trailing zeros
42
+ while (satoshiPart.end_with?("0")) do
43
+ satoshiPart = satoshiPart.chomp("0");
44
+ end
45
+
46
+ return denominator + btcPart + "." + satoshiPart;
47
+ end
48
+
49
+ end
50
+ end
@@ -0,0 +1,25 @@
1
+ require 'net/yail'
2
+ require 'highline/import'
3
+
4
+ module Mpex::Interactive
5
+
6
+ def self.run
7
+ puts "Welcome to MPEX repl. Type 'help' and 'help [command]' to get a help or 'quit' to exit."
8
+ puts "Donations welcome: 1DrqwLjksrXZHdSzzieaNhQuhrnbNTeiQr"
9
+ puts "Type 'irc' to connect to Freenode to use MPEx IRC bots"
10
+ loop do
11
+ line = ask("mpex>> ") {|q| q.readline = true }
12
+
13
+ exit 0 if line =~ /^(exit|quit|q)$/
14
+
15
+ args = line.split(" ")
16
+
17
+ begin
18
+ Mpex::CLI.command.run(args) unless args.empty?
19
+ rescue Exception => ex
20
+ puts ex
21
+ end
22
+ end
23
+ end
24
+
25
+ end
data/lib/mpex/irc.rb ADDED
@@ -0,0 +1,84 @@
1
+ require 'net/yail'
2
+ require 'net/http'
3
+
4
+ module Mpex
5
+ # TODO to be improved and to be made configurable!
6
+ class Irc
7
+
8
+ ASSBOT = "assbot"
9
+ MPEXBOT = "mpexbot"
10
+
11
+ def initialize
12
+ @irc = Net::YAIL.new(
13
+ :address => 'irc.freenode.net',
14
+ :username => 'mp_rb_client',
15
+ :realname => 'mpex ruby irc client',
16
+ :nicknames => ["mp_rb_client#{Random.rand(42..4096)}", "mp_rb_client#{Random.rand(42..4096)}"]
17
+ )
18
+ log = Logger.new(STDOUT)
19
+ log.level = Logger::WARN
20
+ @irc.log = log
21
+ end
22
+
23
+ def connect
24
+ @irc.on_welcome do |event|
25
+ puts "\nConnected to IRC."
26
+ @connected = true
27
+ end
28
+
29
+ puts "Connecting. Please wait."
30
+
31
+ @irc.start_listening
32
+ end
33
+
34
+ def disconnect
35
+ @irc.stop_listening
36
+ end
37
+
38
+ def connected?
39
+ @connected
40
+ end
41
+
42
+ def send_encrypted(message, &block)
43
+ res = Net::HTTP.post_form(URI.parse("http://dpaste.com/api/v1/"), { 'content' => "#{message}" })
44
+ dpaste_url = res['Location']
45
+ @irc.msg(ASSBOT, "!mp " + dpaste_url)
46
+
47
+ @irc.hearing_msg do |event|
48
+ resp_url = parse_message(event.message)
49
+ mpex_res = Net::HTTP.get(URI.parse(resp_url)) if resp_url
50
+ yield mpex_res
51
+ end
52
+ end
53
+
54
+ def parse_message(msg)
55
+ if msg.start_with? "Response: http:"
56
+ return msg.split[1]
57
+ end
58
+ end
59
+
60
+ def vwap(&block)
61
+ @irc.msg MPEXBOT, '$vwap'
62
+
63
+ @irc.hearing_msg do |event|
64
+ mpexbot_res = Net::HTTP.get(URI.parse(event.message)) if event.message.start_with?("http:")
65
+ yield mpexbot_res.to_s if mpexbot_res
66
+ end
67
+ end
68
+
69
+ def depth(&block)
70
+ @irc.msg MPEXBOT, '$depth'
71
+
72
+ @irc.hearing_msg do |event|
73
+ if event.message.start_with?("http:")
74
+ uri = URI.parse(event.message);
75
+ id = uri.path[1..-1]
76
+ uri = URI.parse("http://pastebin.com/raw.php?i=" + id)
77
+ mpexbot_res = Net::HTTP.get(uri)
78
+ end
79
+ yield mpexbot_res.to_s if mpexbot_res
80
+ end
81
+ end
82
+
83
+ end
84
+ end
data/lib/mpex/mpex.rb ADDED
@@ -0,0 +1,236 @@
1
+ require 'fileutils'
2
+ require 'open-uri'
3
+ require 'net/http'
4
+ require 'json'
5
+ require 'yaml'
6
+ require 'highline/import'
7
+ require 'gpgme'
8
+ require 'digest/md5'
9
+ require 'logger'
10
+
11
+ module Mpex
12
+ class Mpex
13
+
14
+ CONFIG_FILE_PATH = File.join(Dir.home, ".mpex", "config.yaml")
15
+ LOGFILE_PATH = File.join(Dir.home, ".mpex", "response.log")
16
+
17
+ def initialize
18
+ @crypto = GPGME::Crypto.new(:armor => true)
19
+ unless File.exist?(File.expand_path(LOGFILE_PATH))
20
+ dirname = File.dirname(File.expand_path(LOGFILE_PATH))
21
+ Dir.mkdir(dirname) unless Dir.exist?(dirname)
22
+ end
23
+ @logger = Logger.new(LOGFILE_PATH)
24
+ end
25
+
26
+ def sign(msg, opts)
27
+ signed_message = @crypto.sign(msg, :signer => opts[:keyid], :password => opts[:password], :mode => GPGME::SIG_MODE_CLEAR)
28
+
29
+ verify(signed_message)
30
+ signed_message.to_s
31
+ end
32
+
33
+ def verify(msg)
34
+ @crypto.verify(msg) do |signature|
35
+ if signature.valid?
36
+ say("<%= color('#{signature}', :green) %>")
37
+ else
38
+ say("<%= color('WARNING', :red) %>: Invalid signature! Don't trust!")
39
+ raise "WARNING: Invalid signature! Don't trust!"
40
+ end
41
+ end
42
+ end
43
+
44
+ def encrypt(signed_msg, opts)
45
+ @crypto.encrypt(signed_msg, :recipients => opts[:mpexkeyid])
46
+ end
47
+
48
+ def decrypt(encrypted_data, opts)
49
+ @crypto.decrypt(encrypted_data, :password => opts[:password]) do |signature|
50
+ raise "Signature could not be verified" unless signature.valid?
51
+ end
52
+ end
53
+
54
+ def send_plain(cleartext_command, opts, &block)
55
+
56
+ puts "Sending order to MPEX: #{cleartext_command}"
57
+
58
+ opts = verify_opts_present(opts, [ :url, :keyid, :mpexkeyid, :password ])
59
+
60
+ signed_msg = sign(cleartext_command, opts)
61
+ say("<%= color('Track-ID: #{track_id(signed_msg)}', :blue) %>")
62
+ encrypted_msg = encrypt(signed_msg, opts)
63
+
64
+ if $IRC_LEAK && $IRC_LEAK.connected?
65
+ $IRC_LEAK.send_encrypted(encrypted_msg.to_s) do |encr_answer|
66
+ if encr_answer
67
+ yield handle_answer(encr_answer, opts)
68
+ end
69
+ end
70
+ else
71
+ res = Net::HTTP.post_form(mpex_uri(opts[:url]), { 'msg' => "#{encrypted_msg}" })
72
+ yield handle_answer(res.body, opts)
73
+ end
74
+ end
75
+
76
+ def handle_answer(encrypted_answer, opts)
77
+ decrypted_response = decrypt(encrypted_answer.to_s, opts)
78
+
79
+ @logger.info(decrypted_response.to_s)
80
+
81
+ verified_response = verify(decrypted_response)
82
+ verified_response.to_s
83
+ end
84
+
85
+ def mpex_uri(url)
86
+ URI.parse(url).merge("/")
87
+ end
88
+
89
+ def validate_mpsic(mpsic)
90
+ if mpsic.match(/^\w\./)
91
+ return mpsic
92
+ else
93
+ raise "invalid MPSIC #{mpsic}"
94
+ end
95
+ end
96
+
97
+ def track_id(signed_msg)
98
+ md5hex = Digest::MD5.hexdigest(signed_msg)
99
+ md5hex[0..3]
100
+ end
101
+
102
+ def orders_sum(stat)
103
+ orders_value = stat["Book"].map do |order|
104
+ order[order.keys.first]["Price"].to_i * order[order.keys.first]["Quantity"].to_i
105
+ end.inject(:+)
106
+ orders_value
107
+ end
108
+
109
+ def orders_vwap_sum(stat, vwaps)
110
+ orders_value = stat["Book"].map do |order|
111
+ if order[order.keys.first]["BS"] == "B"
112
+ order[order.keys.first]["Price"].to_i * order[order.keys.first]["Quantity"].to_i
113
+ elsif order[order.keys.first]["BS"] == "S"
114
+ mpsic = order[order.keys.first]["MPSIC"]
115
+ vwaps[mpsic]["1d"]["max"].to_i * order[order.keys.first]["Quantity"].to_i
116
+ else
117
+ 0
118
+ end
119
+ end.inject(:+)
120
+ orders_value
121
+ end
122
+
123
+ def fetch_mpex_vwaps(url, &block)
124
+ if $IRC_LEAK && $IRC_LEAK.connected?
125
+ $IRC_LEAK.vwap do |resp|
126
+ vwaps = JSON.parse(resp)
127
+ end
128
+ else
129
+ vwap_url = mpex_uri(url).merge("/mpex-vwap.php")
130
+ vwaps = JSON.parse(Net::HTTP.get(vwap_url))
131
+ end
132
+ yield vwaps
133
+ end
134
+
135
+ def fetch_orderbook(&block)
136
+ if $IRC_LEAK && $IRC_LEAK.connected?
137
+ $IRC_LEAK.depth do |depth|
138
+ orderbook = JSON.parse depth
139
+ orderbook.each do |s|
140
+ puts s.first
141
+ s.last["S"].sort_by { |price, amount| -price }.each do |o|
142
+ puts "SELL price: #{Converter.satoshi_to_btc(o.first)} amount: #{o.last}"
143
+ end
144
+ s.last["B"].sort_by { |price, amount| price }.each do |o|
145
+ puts "BUY price: #{Converter.satoshi_to_btc(o.first)} amount: #{o.last}"
146
+ end
147
+ end
148
+ end
149
+ else
150
+ end
151
+ end
152
+
153
+ def portfolio(opts, stat, &block)
154
+
155
+ return unless stat
156
+
157
+ opts = verify_opts_present(opts, [ :url, :keyid, :mpexkeyid, :password ])
158
+
159
+ fetch_mpex_vwaps(opts[:url]) do |vwaps|
160
+ return unless vwaps
161
+ holdings_value = holdings_avg_value(stat, vwaps)
162
+
163
+ optimistic_value = holdings_value + orders_sum(stat)
164
+ vwap_valuation = holdings_value + orders_vwap_sum(stat, vwaps)
165
+
166
+ portfolio = <<-PORTFOLIO
167
+ Your optimistic valuation: #{Converter.satoshi_to_btc(optimistic_value)}"
168
+ VWAP valuation: #{Converter.satoshi_to_btc(vwap_valuation)}
169
+ PORTFOLIO
170
+ yield portfolio
171
+ end
172
+ end
173
+
174
+ def holdings_avg_value(stat, vwaps)
175
+ # TODO improve!
176
+ holdings_value = stat["Holdings"].map do |h|
177
+ if h["CxBTC"]
178
+ h["CxBTC"].to_i
179
+ elsif h["S.MPOE"]
180
+ h["S.MPOE"].to_i*vwaps["S.MPOE"]["1d"]["avg"].to_i
181
+ elsif h["S.DICE"]
182
+ h["S.DICE"].to_i*vwaps["S.DICE"]["1d"]["avg"].to_i
183
+ else
184
+ 0
185
+ end
186
+ end.inject(:+)
187
+ end
188
+
189
+ def verify_opts_present(opts, req_opts)
190
+ config_opts = read_config
191
+ req_opts.each do |r_opt|
192
+ unless opts[r_opt]
193
+ if config_opts[r_opt.to_s]
194
+ opts[r_opt] = config_opts[r_opt.to_s]
195
+ elsif r_opt == :password
196
+ opts[:password] = ask("Enter Passphrase: "){|q| q.echo = false}
197
+ puts
198
+ else
199
+ $stderr.puts "--#{r_opt} option is required"
200
+ exit 1
201
+ end
202
+ end
203
+ end
204
+ opts
205
+ end
206
+
207
+ def read_config
208
+ begin
209
+ return YAML.load_file(File.expand_path(CONFIG_FILE_PATH))
210
+ rescue
211
+ create_configfile_unless_exists
212
+ end
213
+ return {}
214
+ end
215
+
216
+ def create_configfile_unless_exists
217
+ return if File.exist?(File.expand_path(CONFIG_FILE_PATH))
218
+ begin
219
+ current_dir = File.dirname(File.expand_path(__FILE__))
220
+
221
+ sample_config_file = File.expand_path(File.join(current_dir, "..", "..", "config.yaml.sample"))
222
+
223
+ unless File.exist?(File.expand_path(CONFIG_FILE_PATH))
224
+ mpex_dir = File.dirname(File.expand_path(CONFIG_FILE_PATH))
225
+ Dir.mkdir(mpex_dir) unless Dir.exist?(mpex_dir)
226
+ end
227
+
228
+ FileUtils.cp sample_config_file, File.expand_path(CONFIG_FILE_PATH)
229
+ return YAML.load_file(File.expand_path(CONFIG_FILE_PATH))
230
+ rescue
231
+ puts "WARN: no sample config file found!"
232
+ end
233
+ end
234
+
235
+ end
236
+ end
@@ -0,0 +1,3 @@
1
+ module Mpex
2
+ VERSION = "0.4.1"
3
+ end
data/lib/mpex.rb ADDED
@@ -0,0 +1,11 @@
1
+ require "mpex/version"
2
+ require "mpex/mpex"
3
+ require "mpex/converter"
4
+
5
+ module Mpex
6
+
7
+ def self.version_information
8
+ "MPEx commandline interface #{VERSION} (c) 2013 Fa Wuxi"
9
+ end
10
+
11
+ end
data/mpex.gemspec ADDED
@@ -0,0 +1,33 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "mpex/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "mpex"
7
+ s.version = Mpex::VERSION
8
+ s.authors = ["Fa Wuxi"]
9
+ s.email = [""]
10
+ s.homepage = "https://github.com/fawuxi/mpex"
11
+ s.summary = %q{Commandline Client for MPEx}
12
+ s.description = %q{Commandline client for "MPEx":http://mpex.co a Bitcoin security exchange. Make sure to carefully read its "FAQ":http://mpex.co/faq.html before using it.}
13
+
14
+ s.files = Dir['[A-Z]*'] + Dir['{bin,lib,tasks,test}/**/*'] + [ 'mpex.gemspec' ]
15
+ s.extra_rdoc_files = ['README.md']
16
+ s.rdoc_options = [ '--main', 'README.md' ]
17
+ s.executables = [ 'mpex' ]
18
+ s.require_paths = [ 'lib' ]
19
+
20
+ s.add_runtime_dependency "cri", '~> 2.2'
21
+ s.add_runtime_dependency "json"
22
+ s.add_runtime_dependency "highline"
23
+ s.add_runtime_dependency "gpgme"
24
+ s.add_runtime_dependency "net-yail"
25
+
26
+ s.add_development_dependency "cucumber"
27
+ s.add_development_dependency "rspec-expectations"
28
+
29
+ s.post_install_message = %q{------------------------------------------------------------------------------
30
+ run "mpex help" for usage information
31
+ ------------------------------------------------------------------------------
32
+ }
33
+ end
metadata ADDED
@@ -0,0 +1,163 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: mpex
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.4.1
5
+ platform: ruby
6
+ authors:
7
+ - Fa Wuxi
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-03-09 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: cri
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '2.2'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '2.2'
27
+ - !ruby/object:Gem::Dependency
28
+ name: json
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: highline
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: gpgme
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: net-yail
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - '>='
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - '>='
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: cucumber
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - '>='
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - '>='
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: rspec-expectations
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - '>='
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - '>='
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ description: Commandline client for "MPEx":http://mpex.co a Bitcoin security exchange.
112
+ Make sure to carefully read its "FAQ":http://mpex.co/faq.html before using it.
113
+ email:
114
+ - ''
115
+ executables:
116
+ - mpex
117
+ extensions: []
118
+ extra_rdoc_files:
119
+ - README.md
120
+ files:
121
+ - FAQ.html
122
+ - Gemfile
123
+ - Gemfile.lock
124
+ - Rakefile
125
+ - README.md
126
+ - bin/mpex
127
+ - lib/mpex/cli.rb
128
+ - lib/mpex/converter.rb
129
+ - lib/mpex/interactive.rb
130
+ - lib/mpex/irc.rb
131
+ - lib/mpex/mpex.rb
132
+ - lib/mpex/version.rb
133
+ - lib/mpex.rb
134
+ - mpex.gemspec
135
+ homepage: https://github.com/fawuxi/mpex
136
+ licenses: []
137
+ metadata: {}
138
+ post_install_message: |
139
+ ------------------------------------------------------------------------------
140
+ run "mpex help" for usage information
141
+ ------------------------------------------------------------------------------
142
+ rdoc_options:
143
+ - --main
144
+ - README.md
145
+ require_paths:
146
+ - lib
147
+ required_ruby_version: !ruby/object:Gem::Requirement
148
+ requirements:
149
+ - - '>='
150
+ - !ruby/object:Gem::Version
151
+ version: '0'
152
+ required_rubygems_version: !ruby/object:Gem::Requirement
153
+ requirements:
154
+ - - '>='
155
+ - !ruby/object:Gem::Version
156
+ version: '0'
157
+ requirements: []
158
+ rubyforge_project:
159
+ rubygems_version: 2.0.0
160
+ signing_key:
161
+ specification_version: 4
162
+ summary: Commandline Client for MPEx
163
+ test_files: []