poloniex_api 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: b9f6cc08ad5faec147135e5469ba13690c9e1a4d
4
+ data.tar.gz: 40139a798ac2ac7a4cc247ebf7fd7ce5f69fc102
5
+ SHA512:
6
+ metadata.gz: 1fc969743b1352410943254c242ce36c712ba2b436aeb2591795c91685506647a1edeb725a8cfb178d57c7038534ac20a23e89a1acf81c23baa9a08c92b0e57e
7
+ data.tar.gz: db528b1d2fcfd611ddb682beb4e6a081f52d4f8e154226c67220798b1d67ff638dbe651ebf185c7a0a4e383087ad00a77efbd91b1ec866eabe615e0ab94c9cb0
data/.gitignore ADDED
@@ -0,0 +1,3 @@
1
+
2
+ # Ignore gems built in this folder
3
+ *.gem
data/CONTRIBUTING.md ADDED
@@ -0,0 +1,25 @@
1
+ # Contributing
2
+
3
+ ### Users can contribute to this repository in a variety of ways:
4
+
5
+ #### Have a feature you want implemented?
6
+
7
+ Open an [issue](https://github.com/brianmcmichael/poloniex_api/issues) stating what feature you wish to implement, [pull requests](https://github.com/brianmcmichael/poloniex_api/pulls) are encouraged and will speed up implementation.
8
+
9
+ #### Found a bug that needs fixing?
10
+
11
+ If you know how to fix it, a [pull request](https://github.com/brianmcmichael/poloniex_api/pulls) is encouraged, otherwise open an issue providing details on the events leading up to the bug, including a traceback of the error.
12
+
13
+ #### Want to improve documentation?
14
+
15
+ Take a look at the [Wiki](https://github.com/brianmcmichael/poloniex_api/wiki) and docstrings. Improvement is always welcome.
16
+
17
+ #### Want to just show support?
18
+
19
+ You can simply star/fork [this repository at github.com](https://github.com/brianmcmichael/poloniex_api), and/or donate to the following:
20
+
21
+ BTC: `1Azh1Sn3nzHE5RMnx8dQnJ4dkWAxFbUWEg`
22
+
23
+ ETH/Tokens: `0x7e2185544f095230ba86915E5BfF498653A90A66`
24
+
25
+ Waves: `3P6FDphVYMEgy6ts4o8HLgRDUKoyRnMDJ9y`
data/LICENSE ADDED
@@ -0,0 +1,339 @@
1
+ GNU GENERAL PUBLIC LICENSE
2
+ Version 2, June 1991
3
+
4
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc., <http://fsf.org/>
5
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
6
+ Everyone is permitted to copy and distribute verbatim copies
7
+ of this license document, but changing it is not allowed.
8
+
9
+ Preamble
10
+
11
+ The licenses for most software are designed to take away your
12
+ freedom to share and change it. By contrast, the GNU General Public
13
+ License is intended to guarantee your freedom to share and change free
14
+ software--to make sure the software is free for all its users. This
15
+ General Public License applies to most of the Free Software
16
+ Foundation's software and to any other program whose authors commit to
17
+ using it. (Some other Free Software Foundation software is covered by
18
+ the GNU Lesser General Public License instead.) You can apply it to
19
+ your programs, too.
20
+
21
+ When we speak of free software, we are referring to freedom, not
22
+ price. Our General Public Licenses are designed to make sure that you
23
+ have the freedom to distribute copies of free software (and charge for
24
+ this service if you wish), that you receive source code or can get it
25
+ if you want it, that you can change the software or use pieces of it
26
+ in new free programs; and that you know you can do these things.
27
+
28
+ To protect your rights, we need to make restrictions that forbid
29
+ anyone to deny you these rights or to ask you to surrender the rights.
30
+ These restrictions translate to certain responsibilities for you if you
31
+ distribute copies of the software, or if you modify it.
32
+
33
+ For example, if you distribute copies of such a program, whether
34
+ gratis or for a fee, you must give the recipients all the rights that
35
+ you have. You must make sure that they, too, receive or can get the
36
+ source code. And you must show them these terms so they know their
37
+ rights.
38
+
39
+ We protect your rights with two steps: (1) copyright the software, and
40
+ (2) offer you this license which gives you legal permission to copy,
41
+ distribute and/or modify the software.
42
+
43
+ Also, for each author's protection and ours, we want to make certain
44
+ that everyone understands that there is no warranty for this free
45
+ software. If the software is modified by someone else and passed on, we
46
+ want its recipients to know that what they have is not the original, so
47
+ that any problems introduced by others will not reflect on the original
48
+ authors' reputations.
49
+
50
+ Finally, any free program is threatened constantly by software
51
+ patents. We wish to avoid the danger that redistributors of a free
52
+ program will individually obtain patent licenses, in effect making the
53
+ program proprietary. To prevent this, we have made it clear that any
54
+ patent must be licensed for everyone's free use or not licensed at all.
55
+
56
+ The precise terms and conditions for copying, distribution and
57
+ modification follow.
58
+
59
+ GNU GENERAL PUBLIC LICENSE
60
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
61
+
62
+ 0. This License applies to any program or other work which contains
63
+ a notice placed by the copyright holder saying it may be distributed
64
+ under the terms of this General Public License. The "Program", below,
65
+ refers to any such program or work, and a "work based on the Program"
66
+ means either the Program or any derivative work under copyright law:
67
+ that is to say, a work containing the Program or a portion of it,
68
+ either verbatim or with modifications and/or translated into another
69
+ language. (Hereinafter, translation is included without limitation in
70
+ the term "modification".) Each licensee is addressed as "you".
71
+
72
+ Activities other than copying, distribution and modification are not
73
+ covered by this License; they are outside its scope. The act of
74
+ running the Program is not restricted, and the output from the Program
75
+ is covered only if its contents constitute a work based on the
76
+ Program (independent of having been made by running the Program).
77
+ Whether that is true depends on what the Program does.
78
+
79
+ 1. You may copy and distribute verbatim copies of the Program's
80
+ source code as you receive it, in any medium, provided that you
81
+ conspicuously and appropriately publish on each copy an appropriate
82
+ copyright notice and disclaimer of warranty; keep intact all the
83
+ notices that refer to this License and to the absence of any warranty;
84
+ and give any other recipients of the Program a copy of this License
85
+ along with the Program.
86
+
87
+ You may charge a fee for the physical act of transferring a copy, and
88
+ you may at your option offer warranty protection in exchange for a fee.
89
+
90
+ 2. You may modify your copy or copies of the Program or any portion
91
+ of it, thus forming a work based on the Program, and copy and
92
+ distribute such modifications or work under the terms of Section 1
93
+ above, provided that you also meet all of these conditions:
94
+
95
+ a) You must cause the modified files to carry prominent notices
96
+ stating that you changed the files and the date of any change.
97
+
98
+ b) You must cause any work that you distribute or publish, that in
99
+ whole or in part contains or is derived from the Program or any
100
+ part thereof, to be licensed as a whole at no charge to all third
101
+ parties under the terms of this License.
102
+
103
+ c) If the modified program normally reads commands interactively
104
+ when run, you must cause it, when started running for such
105
+ interactive use in the most ordinary way, to print or display an
106
+ announcement including an appropriate copyright notice and a
107
+ notice that there is no warranty (or else, saying that you provide
108
+ a warranty) and that users may redistribute the program under
109
+ these conditions, and telling the user how to view a copy of this
110
+ License. (Exception: if the Program itself is interactive but
111
+ does not normally print such an announcement, your work based on
112
+ the Program is not required to print an announcement.)
113
+
114
+ These requirements apply to the modified work as a whole. If
115
+ identifiable sections of that work are not derived from the Program,
116
+ and can be reasonably considered independent and separate works in
117
+ themselves, then this License, and its terms, do not apply to those
118
+ sections when you distribute them as separate works. But when you
119
+ distribute the same sections as part of a whole which is a work based
120
+ on the Program, the distribution of the whole must be on the terms of
121
+ this License, whose permissions for other licensees extend to the
122
+ entire whole, and thus to each and every part regardless of who wrote it.
123
+
124
+ Thus, it is not the intent of this section to claim rights or contest
125
+ your rights to work written entirely by you; rather, the intent is to
126
+ exercise the right to control the distribution of derivative or
127
+ collective works based on the Program.
128
+
129
+ In addition, mere aggregation of another work not based on the Program
130
+ with the Program (or with a work based on the Program) on a volume of
131
+ a storage or distribution medium does not bring the other work under
132
+ the scope of this License.
133
+
134
+ 3. You may copy and distribute the Program (or a work based on it,
135
+ under Section 2) in object code or executable form under the terms of
136
+ Sections 1 and 2 above provided that you also do one of the following:
137
+
138
+ a) Accompany it with the complete corresponding machine-readable
139
+ source code, which must be distributed under the terms of Sections
140
+ 1 and 2 above on a medium customarily used for software interchange; or,
141
+
142
+ b) Accompany it with a written offer, valid for at least three
143
+ years, to give any third party, for a charge no more than your
144
+ cost of physically performing source distribution, a complete
145
+ machine-readable copy of the corresponding source code, to be
146
+ distributed under the terms of Sections 1 and 2 above on a medium
147
+ customarily used for software interchange; or,
148
+
149
+ c) Accompany it with the information you received as to the offer
150
+ to distribute corresponding source code. (This alternative is
151
+ allowed only for noncommercial distribution and only if you
152
+ received the program in object code or executable form with such
153
+ an offer, in accord with Subsection b above.)
154
+
155
+ The source code for a work means the preferred form of the work for
156
+ making modifications to it. For an executable work, complete source
157
+ code means all the source code for all modules it contains, plus any
158
+ associated interface definition files, plus the scripts used to
159
+ control compilation and installation of the executable. However, as a
160
+ special exception, the source code distributed need not include
161
+ anything that is normally distributed (in either source or binary
162
+ form) with the major components (compiler, kernel, and so on) of the
163
+ operating system on which the executable runs, unless that component
164
+ itself accompanies the executable.
165
+
166
+ If distribution of executable or object code is made by offering
167
+ access to copy from a designated place, then offering equivalent
168
+ access to copy the source code from the same place counts as
169
+ distribution of the source code, even though third parties are not
170
+ compelled to copy the source along with the object code.
171
+
172
+ 4. You may not copy, modify, sublicense, or distribute the Program
173
+ except as expressly provided under this License. Any attempt
174
+ otherwise to copy, modify, sublicense or distribute the Program is
175
+ void, and will automatically terminate your rights under this License.
176
+ However, parties who have received copies, or rights, from you under
177
+ this License will not have their licenses terminated so long as such
178
+ parties remain in full compliance.
179
+
180
+ 5. You are not required to accept this License, since you have not
181
+ signed it. However, nothing else grants you permission to modify or
182
+ distribute the Program or its derivative works. These actions are
183
+ prohibited by law if you do not accept this License. Therefore, by
184
+ modifying or distributing the Program (or any work based on the
185
+ Program), you indicate your acceptance of this License to do so, and
186
+ all its terms and conditions for copying, distributing or modifying
187
+ the Program or works based on it.
188
+
189
+ 6. Each time you redistribute the Program (or any work based on the
190
+ Program), the recipient automatically receives a license from the
191
+ original licensor to copy, distribute or modify the Program subject to
192
+ these terms and conditions. You may not impose any further
193
+ restrictions on the recipients' exercise of the rights granted herein.
194
+ You are not responsible for enforcing compliance by third parties to
195
+ this License.
196
+
197
+ 7. If, as a consequence of a court judgment or allegation of patent
198
+ infringement or for any other reason (not limited to patent issues),
199
+ conditions are imposed on you (whether by court order, agreement or
200
+ otherwise) that contradict the conditions of this License, they do not
201
+ excuse you from the conditions of this License. If you cannot
202
+ distribute so as to satisfy simultaneously your obligations under this
203
+ License and any other pertinent obligations, then as a consequence you
204
+ may not distribute the Program at all. For example, if a patent
205
+ license would not permit royalty-free redistribution of the Program by
206
+ all those who receive copies directly or indirectly through you, then
207
+ the only way you could satisfy both it and this License would be to
208
+ refrain entirely from distribution of the Program.
209
+
210
+ If any portion of this section is held invalid or unenforceable under
211
+ any particular circumstance, the balance of the section is intended to
212
+ apply and the section as a whole is intended to apply in other
213
+ circumstances.
214
+
215
+ It is not the purpose of this section to induce you to infringe any
216
+ patents or other property right claims or to contest validity of any
217
+ such claims; this section has the sole purpose of protecting the
218
+ integrity of the free software distribution system, which is
219
+ implemented by public license practices. Many people have made
220
+ generous contributions to the wide range of software distributed
221
+ through that system in reliance on consistent application of that
222
+ system; it is up to the author/donor to decide if he or she is willing
223
+ to distribute software through any other system and a licensee cannot
224
+ impose that choice.
225
+
226
+ This section is intended to make thoroughly clear what is believed to
227
+ be a consequence of the rest of this License.
228
+
229
+ 8. If the distribution and/or use of the Program is restricted in
230
+ certain countries either by patents or by copyrighted interfaces, the
231
+ original copyright holder who places the Program under this License
232
+ may add an explicit geographical distribution limitation excluding
233
+ those countries, so that distribution is permitted only in or among
234
+ countries not thus excluded. In such case, this License incorporates
235
+ the limitation as if written in the body of this License.
236
+
237
+ 9. The Free Software Foundation may publish revised and/or new versions
238
+ of the General Public License from time to time. Such new versions will
239
+ be similar in spirit to the present version, but may differ in detail to
240
+ address new problems or concerns.
241
+
242
+ Each version is given a distinguishing version number. If the Program
243
+ specifies a version number of this License which applies to it and "any
244
+ later version", you have the option of following the terms and conditions
245
+ either of that version or of any later version published by the Free
246
+ Software Foundation. If the Program does not specify a version number of
247
+ this License, you may choose any version ever published by the Free Software
248
+ Foundation.
249
+
250
+ 10. If you wish to incorporate parts of the Program into other free
251
+ programs whose distribution conditions are different, write to the author
252
+ to ask for permission. For software which is copyrighted by the Free
253
+ Software Foundation, write to the Free Software Foundation; we sometimes
254
+ make exceptions for this. Our decision will be guided by the two goals
255
+ of preserving the free status of all derivatives of our free software and
256
+ of promoting the sharing and reuse of software generally.
257
+
258
+ NO WARRANTY
259
+
260
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
261
+ FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
262
+ OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
263
+ PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
264
+ OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
265
+ MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
266
+ TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
267
+ PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
268
+ REPAIR OR CORRECTION.
269
+
270
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
271
+ WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
272
+ REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
273
+ INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
274
+ OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
275
+ TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
276
+ YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
277
+ PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
278
+ POSSIBILITY OF SUCH DAMAGES.
279
+
280
+ END OF TERMS AND CONDITIONS
281
+
282
+ How to Apply These Terms to Your New Programs
283
+
284
+ If you develop a new program, and you want it to be of the greatest
285
+ possible use to the public, the best way to achieve this is to make it
286
+ free software which everyone can redistribute and change under these terms.
287
+
288
+ To do so, attach the following notices to the program. It is safest
289
+ to attach them to the start of each source file to most effectively
290
+ convey the exclusion of warranty; and each file should have at least
291
+ the "copyright" line and a pointer to where the full notice is found.
292
+
293
+ {description}
294
+ Copyright (C) {year} {fullname}
295
+
296
+ This program is free software; you can redistribute it and/or modify
297
+ it under the terms of the GNU General Public License as published by
298
+ the Free Software Foundation; either version 2 of the License, or
299
+ (at your option) any later version.
300
+
301
+ This program is distributed in the hope that it will be useful,
302
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
303
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
304
+ GNU General Public License for more details.
305
+
306
+ You should have received a copy of the GNU General Public License along
307
+ with this program; if not, write to the Free Software Foundation, Inc.,
308
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
309
+
310
+ Also add information on how to contact you by electronic and paper mail.
311
+
312
+ If the program is interactive, make it output a short notice like this
313
+ when it starts in an interactive mode:
314
+
315
+ Gnomovision version 69, Copyright (C) year name of author
316
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
317
+ This is free software, and you are welcome to redistribute it
318
+ under certain conditions; type `show c' for details.
319
+
320
+ The hypothetical commands `show w' and `show c' should show the appropriate
321
+ parts of the General Public License. Of course, the commands you use may
322
+ be called something other than `show w' and `show c'; they could even be
323
+ mouse-clicks or menu items--whatever suits your program.
324
+
325
+ You should also get your employer (if you work as a programmer) or your
326
+ school, if any, to sign a "copyright disclaimer" for the program, if
327
+ necessary. Here is a sample; alter the names:
328
+
329
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
330
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
331
+
332
+ {signature of Ty Coon}, 1 April 1989
333
+ Ty Coon, President of Vice
334
+
335
+ This General Public License does not permit incorporating your program into
336
+ proprietary programs. If your program is a subroutine library, you may
337
+ consider it more useful to permit linking proprietary applications with the
338
+ library. If this is what you want to do, use the GNU Lesser General
339
+ Public License instead of this License.
data/README.md ADDED
@@ -0,0 +1,40 @@
1
+ # Poloniex API Wrapper - Ruby Edition
2
+
3
+ * Ruby 2.15+
4
+ * No additional dependencies
5
+
6
+ Ported from [this](https://github.com/s4w3d0ff/python-poloniex) wrapper written by 's4w3d0ff'
7
+
8
+ > I (brianmcmichael) am not affiliated with, nor paid by Poloniex. If you wish to contribute to this repository please read CONTRIBUTING.md. All and any help is appreciated.
9
+
10
+ ## Getting Started
11
+
12
+ Add the Api wrapper to your `Gemfile`
13
+
14
+ ```
15
+ gem 'poloniex_api'
16
+ ```
17
+
18
+ Require the gem in your application
19
+
20
+ ```
21
+ require 'poloniex'
22
+ ```
23
+
24
+ Basic Usage
25
+
26
+ ```
27
+ poloniex = Poloniex::API.new
28
+ ```
29
+
30
+
31
+ Initialize a new object with your API key, Secret Key, and timeout in seconds.
32
+
33
+ ```
34
+ poloniex = Poloniex::API.new('YOUR_API_KEY', 'YOUR_SECRET_KEY', 3)
35
+ ```
36
+
37
+ Get your API key [here](https://poloniex.com/apiKeys)
38
+
39
+
40
+
@@ -0,0 +1,10 @@
1
+ module Poloniex
2
+ # Exception for handling poloniex api errors
3
+ class PoloniexError < StandardError; end
4
+
5
+ # Exception for retry decorator
6
+ class RetryException < PoloniexError; end
7
+
8
+ # Exception when there's an issue with the request
9
+ class RequestException < PoloniexError; end
10
+ end
@@ -0,0 +1,3 @@
1
+ module Poloniex
2
+ VERSION = "0.0.1"
3
+ end
data/lib/poloniex.rb ADDED
@@ -0,0 +1,711 @@
1
+ # Poloniex API wrapper for Ruby 2.1.5+
2
+ #
3
+ # https://github.com/brianmcmichael/poloniex_api
4
+ #
5
+ # BTC: 1Azh1Sn3nzHE5RMnx8dQnJ4dkWAxFbUWEg
6
+ # ETH/Tokens: 0x7e2185544f095230ba86915E5BfF498653A90A66
7
+ # Waves: 3P6FDphVYMEgy6ts4o8HLgRDUKoyRnMDJ9y
8
+ #
9
+ # Copyright (C) 2017 https://github.com/brianmcmichael
10
+ #
11
+ # This program is free software; you can redistribute it and/or modify
12
+ # it under the terms of the GNU General Public License as published by
13
+ # the Free Software Foundation; either version 2 of the License, or
14
+ # (at your option) any later version.
15
+ #
16
+ # This program is distributed in the hope that it will be useful,
17
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
18
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19
+ # GNU General Public License for more details.
20
+ #
21
+ # You should have received a copy of the GNU General Public License along
22
+ # with this program; if not, write to the Free Software Foundation, Inc.,
23
+ # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24
+
25
+
26
+ # TODO
27
+ # [ ] Add retries functionality
28
+ # [ ] Test withdraw method
29
+ # [ ] Test margin_buy method
30
+ # [ ] Better mapping of _get method
31
+ # [ ] Clean up the post request
32
+ # [ ] Refactor market_trade_hist
33
+ # [ ] Add examples
34
+ # [ ] Convert responses to objects
35
+ # [ ] Add test suite
36
+ # [ ] Add websockets support
37
+
38
+ require 'net/http'
39
+ require 'json'
40
+ require 'logger'
41
+ require 'uri'
42
+ require 'base64'
43
+ require 'digest'
44
+
45
+ module Poloniex
46
+
47
+ RETRY_DELAYS = [0, 2, 5, 30]
48
+
49
+ # Possible Commands
50
+ PUBLIC_COMMANDS = %w(returnTicker return24hVolume returnOrderBook marketTradeHist returnChartData returnCurrencies returnLoanOrders)
51
+
52
+ PRIVATE_COMMANDS = %w(returnBalances returnCompleteBalances returnDepositAddresses generateNewAddress returnDepositsWithdrawals returnOpenOrders returnTradeHistory returnAvailableAccountBalances returnTradableBalances returnOpenLoanOffers returnOrderTrades returnActiveLoans returnLendingHistory createLoanOffer cancelLoanOffer toggleAutoRenew buy sell cancelOrder moveOrder withdraw returnFeeInfo transferBalance returnMarginAccountSummary marginBuy marginSell getMarginPosition closeMarginPosition)
53
+
54
+ POSITION_TYPES = %w(fillOrKill immediateOrCancel postOnly)
55
+
56
+ PUBLIC_API_BASE = 'https://poloniex.com/public?'
57
+ PRIVATE_API_BASE = 'https://poloniex.com/tradingApi'
58
+
59
+ UTF_8 = 'utf-8'
60
+ SHA512 = 'sha512'
61
+
62
+ # Time Placeholders: (MONTH == 30*DAYS)
63
+ # MINUTE, HOUR, DAY, WEEK, MONTH, YEAR
64
+ MINUTE = 60
65
+ HOUR = MINUTE * 60
66
+ DAY = HOUR * 24
67
+ WEEK = DAY * 7
68
+ MONTH = DAY * 30
69
+ YEAR = DAY * 365
70
+
71
+ # The Poloniex Object
72
+ class API
73
+ attr_accessor :key, :secret
74
+
75
+ # @param [String] key api key supplied by Poloniex
76
+ # @param [String] secret hash supplied by Poloniex
77
+ # @param [int] timeout time in sec to wait for an api response
78
+ # (otherwise 'requests.exceptions.Timeout' is raised)
79
+ # @param [datatype] json_nums to use when parsing json ints and floats
80
+ def initialize(key = false, secret = false, timeout = nil, json_nums = false)
81
+ self.logger = Logger.new(STDOUT)
82
+
83
+ # create nonce
84
+ self._nonce = nonce_time
85
+ self.json_nums = json_nums
86
+ self.key = key
87
+ self.secret = secret
88
+ self.timeout = timeout
89
+ end
90
+
91
+ # FIXME make this a decorator
92
+ def retry(func)
93
+ end
94
+
95
+ def retrying(*args, **kwargs)
96
+ problems = []
97
+ RETRY_DELAYS.each do |delay|
98
+ begin
99
+ # attempt call
100
+ return func(*args, **kwargs)
101
+ rescue Poloniex::RequestException.new => problem
102
+ problems.push problem
103
+ if delay == RETRY_DELAYS.last
104
+ raise Poloniex::RetryException.new "Retry delays exhausted #{problem}"
105
+ end
106
+ end
107
+ if problems.any?
108
+ LOGGER.debug problems.join("\n")
109
+ end
110
+ end
111
+ end
112
+
113
+ # """ Main Api Function
114
+ # - encodes and sends <command> with optional [args] to Poloniex api
115
+ # - raises 'poloniex.PoloniexError' if an api key or secret is missing
116
+ # (and the command is 'private'), if the <command> is not valid, or
117
+ # if an error is returned from poloniex.com
118
+ # - returns decoded json api message """
119
+ def call(command, args = {})
120
+ # Get command type
121
+ cmd_type = self.check_command(command)
122
+
123
+ # Pass the command
124
+ args['command'] = command
125
+ payload = {}
126
+ payload['timeout'] = self.timeout
127
+
128
+ # private?
129
+ if cmd_type == 'Private'
130
+ payload['uri'] = PRIVATE_API_BASE
131
+
132
+ # Set nonce
133
+ args['nonce'] = self.nonce
134
+
135
+ # Add args to payload
136
+ payload['data'] = args
137
+
138
+ digest = Digest::SHA512
139
+ # Sign data with secret key
140
+ sign = Digest::HMAC.hexdigest(
141
+ URI.encode_www_form(args).encode(UTF_8),
142
+ secret.encode(UTF_8),
143
+ digest
144
+ )
145
+
146
+ # Add headers to payload
147
+ payload['headers'] = {
148
+ 'Content-Type' => 'application/x-www-form-urlencoded',
149
+ 'Sign' => sign,
150
+ 'Key' => key
151
+ }
152
+
153
+ # Send the call
154
+ # FIXME
155
+ ret = _post(PRIVATE_API_BASE, args, payload['headers'])
156
+
157
+ # Return the data
158
+ return self.handle_returned(ret.body)
159
+ end
160
+ if cmd_type == 'Public'
161
+
162
+ # Encode URL
163
+ payload['url'] = PUBLIC_API_BASE + URI.encode_www_form(args)
164
+
165
+ # Send the call
166
+ ret = _get(payload['url'])
167
+
168
+ return self.handle_returned(ret)
169
+ end
170
+ end
171
+
172
+ # Returns if the command is private of public, raises PoloniexError
173
+ # if command is not found
174
+ def check_command(command)
175
+ if PRIVATE_COMMANDS.include? command
176
+ # Check for keys
177
+ unless self.key && self.secret
178
+ raise Poloniex::PoloniexError.new "An API key and Secret Key are required!"
179
+ end
180
+ return 'Private'
181
+ end
182
+ if PUBLIC_COMMANDS.include? command
183
+ return 'Public'
184
+ end
185
+ raise Poloniex::PoloniexError.new "Invalid command: #{command}"
186
+ end
187
+
188
+ # Handles the returned data from Poloniex
189
+ def handle_returned(data)
190
+ begin
191
+ unless self.json_nums
192
+ out = JSON.parse(data)
193
+ else
194
+ out = JSON.parse(data, parse_float = self.json_nums, parse_int = self.json_nums)
195
+ end
196
+ rescue
197
+ self.logger.error(data)
198
+ raise Poloniex::PoloniexError.new "Invalid json response returned!"
199
+ end
200
+
201
+ if out.include? 'error'
202
+
203
+ # update nonce if we fell behind
204
+ if out['error'].include? "Nonce must be greater"
205
+ nonce
206
+ # raise RequestException so we try again
207
+ raise Poloniex::RequestException.new("PoloniexError #{out['error']}")
208
+ end
209
+
210
+ if out['error'].downcase.include? "please try again"
211
+ # Raise RequestException so we try again
212
+ raise Poloniex::RequestException.new("PoloniexError #{out['error']}")
213
+ end
214
+
215
+ raise Poloniex::PoloniexError.new(out['error'])
216
+ end
217
+ return out
218
+ end
219
+
220
+ # PUBLIC COMMANDS
221
+
222
+ # Returns the ticker for all markets
223
+ def return_ticker
224
+ return self.call('returnTicker')
225
+ end
226
+
227
+ # Returns the 24-hour volume for all markets, plus totals for primary currencies.
228
+ def return_24h_volume
229
+ return self.call('return24hVolume')
230
+ end
231
+
232
+ # Returns the order book for a given market as well as a sequence
233
+ # number for use with the Push API and an indicator specifying whether the
234
+ # market is frozen. (defaults to 'all' markets, at a 'depth' of 20 orders)
235
+ def return_order_book(currency_pair='all', depth=20)
236
+ args = {
237
+ 'currencyPair' => currency_pair.to_s.upcase,
238
+ 'depth' => depth.to_s
239
+ }
240
+ return self.call('returnOrderBook', args)
241
+ end
242
+
243
+ # Returns the past 200 trades for a given market, or up to 50,000
244
+ # trades between a range specified in UNIX timestamps by the "start" and
245
+ # "end" parameters.
246
+ #
247
+ # FIXME: Why is this performing it's own GET? Can this use self.call()?
248
+ def market_trade_hist(currency_pair, _start: false, _end: false)
249
+ args = {
250
+ "command" => 'returnTradeHistory',
251
+ "currencyPair" => currency_pair.to_s.upcase
252
+ }
253
+ if _start
254
+ args['start'] = _start
255
+ end
256
+ if _end
257
+ args['end'] = _end
258
+ end
259
+ url = URI.parse(PUBLIC_API_BASE)
260
+ url.query = URI.encode_www_form(args)
261
+ ret = _get(url.to_s, timeout: self.timeout)
262
+
263
+ self.handle_returned(ret)
264
+ end
265
+
266
+ # Returns candlestick chart data. Parameters are "currencyPair",
267
+ # "period" (candlestick period in seconds; valid values are 300, 900,
268
+ # 1800, 7200, 14400, and 86400), "_start", and "_end". "Start" and "end"
269
+ # are given in UNIX timestamp format and used to specify the date range
270
+ # for the data returned (default date range is _start='1 day ago' to
271
+ # _end='now')
272
+ def return_chart_data(currency_pair, period: false, _start: false, _end: false)
273
+ unless [300, 900, 1800, 7200, 14400, 86400].include? period
274
+ raise Poloniex::PoloniexError.new("#{period.to_s} invalid candle period")
275
+ end
276
+
277
+ unless _start
278
+ _start = Time.now.to_i - DAY
279
+ end
280
+ unless _end
281
+ _end = Time.now.to_i
282
+ end
283
+ args = {
284
+ 'currencyPair' => currency_pair.to_s.upcase,
285
+ 'period' => period.to_s,
286
+ 'start' => _start.to_s,
287
+ 'end' => _end.to_s
288
+ }
289
+ self.call('returnChartData', args)
290
+ end
291
+
292
+ # Returns information about all currencies.
293
+ def return_currencies
294
+ self.call('returnCurrencies')
295
+ end
296
+
297
+ # Returns the list of loan offers and demands for a given currency,
298
+ # specified by the "currency" parameter
299
+ def return_loan_orders(currency)
300
+ args = {
301
+ 'currency' => currency.to_s.upcase
302
+ }
303
+ self.call('returnLoanOrders', args )
304
+ end
305
+
306
+ # PRIVATE COMMANDS
307
+
308
+ # Returns all of your available balances.
309
+ def return_balances
310
+ self.call('returnBalances')
311
+ end
312
+
313
+ # Returns all of your balances, including available balance, balance
314
+ # on orders, and the estimated BTC value of your balance. By default,
315
+ # this call is limited to your exchange account; set the "account"
316
+ # parameter to "all" to include your margin and lending accounts.
317
+ def return_complete_balances(account = 'all')
318
+ args = {
319
+ 'account' => account.to_s
320
+ }
321
+ return self.call('returnCompleteBalances', args)
322
+ end
323
+
324
+ # Returns all of your deposit addresses.
325
+ def return_deposit_addresses
326
+ return self.call('returnDepositAddresses')
327
+ end
328
+
329
+ # Generates a new deposit address for the currency specified by the
330
+ # "currency" parameter.
331
+ def generate_new_address(currency)
332
+ args = {
333
+ 'currency' => currency.to_s.upcase
334
+ }
335
+ return self.call('generateNewAddress', args)
336
+ end
337
+
338
+ # Returns your deposit and withdrawal history within a range,
339
+ # specified by the "_start" and "_end" parameters, both of which should be
340
+ # given as UNIX timestamps. (defaults to 1 month)
341
+ def return_deposits_withdrawals(_start = false, _end = false)
342
+ unless _start
343
+ _start = Time.now.to_i - MONTH
344
+ end
345
+ unless _end
346
+ _end = Time.now.to_i
347
+ end
348
+ args = {
349
+ 'start' => _start.to_s,
350
+ 'end' => _end.to_s
351
+ }
352
+
353
+ return self.call('returnDepositsWithdrawals', args)
354
+ end
355
+
356
+ # Returns your open orders for a given market, specified by the
357
+ # "currencyPair" parameter, e.g. "BTC_XCP". Set "currencyPair" to
358
+ # "all" to return open orders for all markets.
359
+ def return_open_orders(currency_pair = 'all')
360
+ args = {
361
+ 'currencyPair' => currency_pair.to_s.upcase
362
+ }
363
+ return self.call('returnOpenOrders', args)
364
+ end
365
+
366
+ #Returns your trade history for a given market, specified by the
367
+ # "currencyPair" parameter. You may specify "all" as the currencyPair to
368
+ # receive your trade history for all markets. You may optionally specify
369
+ # a range via "start" and/or "end" POST parameters, given in UNIX
370
+ # timestamp format; if you do not specify a range, it will be limited to
371
+ # one day.
372
+ def return_trade_history(currency_pair = 'all', _start = false, _end = false)
373
+ args = {
374
+ 'currencyPair' => currency_pair.to_s.upcase
375
+ }
376
+ if _start
377
+ args['start'] = _start
378
+ end
379
+ if _end
380
+ args['end'] = _end
381
+ end
382
+ return self.call('returnTradeHistory', args)
383
+ end
384
+
385
+ # Returns all trades involving a given order, specified by the
386
+ # "orderNumber" parameter. If no trades for the order have occurred
387
+ # or you specify an order that does not belong to you, you will receive
388
+ # an error.
389
+ def return_order_trades(order_number)
390
+ args = {
391
+ 'orderNumber' => order_number.to_s
392
+ }
393
+ return self.call('returnOrderTrades', args)
394
+ end
395
+
396
+ # Places a limit buy order in a given market. Required parameters are
397
+ # "currencyPair", "rate", and "amount". You may optionally set "orderType"
398
+ # to "fillOrKill", "immediateOrCancel" or "postOnly". A fill-or-kill order
399
+ # will either fill in its entirety or be completely aborted. An
400
+ # immediate-or-cancel order can be partially or completely filled, but
401
+ # any portion of the order that cannot be filled immediately will be
402
+ # canceled rather than left on the order book. A post-only order will
403
+ # only be placed if no portion of it fills immediately; this guarantees
404
+ # you will never pay the taker fee on any part of the order that fills.
405
+ # If successful, the method will return the order number.
406
+ def buy(currency_pair, rate, amount, order_type = false)
407
+ args = {
408
+ 'currencyPair' => currency_pair.to_s.upcase,
409
+ 'rate' => rate.to_s,
410
+ 'amount' => amount.to_s
411
+ }
412
+ # Order type specified?
413
+ if order_type
414
+ # Check type
415
+ unless POSITION_TYPES.include? order_type
416
+ raise Poloniex::PoloniexError.new('Invalid order type.')
417
+ end
418
+ args[order_type] = 1
419
+ end
420
+ return self.call('buy', args)
421
+ end
422
+
423
+ # Places a sell order in a given market. Parameters and output are
424
+ # the same as for the buy method.
425
+ def sell(currency_pair, rate, amount, order_type = false)
426
+ args = {
427
+ 'currencyPair' => currency_pair.to_s.upcase,
428
+ 'rate' => rate.to_s,
429
+ 'amount' => amount.to_s
430
+ }
431
+ # Order type specified?
432
+ if order_type
433
+ unless POSITION_TYPES.include? order_type
434
+ raise Poloniex::PoloniexError.new('Invalid order type.')
435
+ end
436
+ args[order_type] = 1
437
+ end
438
+
439
+ return self.call('sell', args)
440
+ end
441
+
442
+ # Cancels an order you have placed in a given market. Required
443
+ # parameter is "order_number".
444
+ def cancel_order(order_number)
445
+ args = {
446
+ 'orderNumber' => order_number.to_s
447
+ }
448
+ return self.call('cancelOrder', args)
449
+ end
450
+
451
+ # Cancels an order and places a new one of the same type in a single
452
+ # atomic transaction, meaning either both operations will succeed or both
453
+ # will fail. Required parameters are "orderNumber" and "rate"; you may
454
+ # optionally specify "amount" if you wish to change the amount of the new
455
+ # order. "postOnly" or "immediateOrCancel" may be specified as the
456
+ # "orderType" param for exchange orders, but will have no effect on
457
+ # margin orders.
458
+ def move_order(order_number, rate, amount = false, order_type = false )
459
+ args = {
460
+ 'orderNumber' => order_number.to_s,
461
+ 'rate' => rate.to_s
462
+ }
463
+ if amount
464
+ args['amount'] = amount.to_s
465
+ end
466
+
467
+ # Order type specified?
468
+ if order_type
469
+ # 'immediateOrCancel', 'postOnly'
470
+ unless POSITION_TYPES[1,2].include? order_type
471
+ raise Poloniex::PoloniexError.new("Invalid order type #{order_type.to_s}")
472
+ end
473
+ args[order_type] = 1
474
+ end
475
+
476
+ return self.call('moveOrder', args)
477
+ end
478
+
479
+ # Immediately places a withdrawal for a given currency, with no email
480
+ # confirmation. In order to use this method, the withdrawal privilege
481
+ # must be enabled for your API key. Required parameters are
482
+ # "currency", "amount", and "address". For XMR withdrawals, you may
483
+ # optionally specify "paymentId".
484
+ #
485
+ # TODO: UNTESTED
486
+ def withdraw(currency, amount, address, payment_id = false)
487
+ args = {
488
+ 'currency' => currency.to_s.upcase,
489
+ 'amount' => amount.to_s,
490
+ 'address' => address.to_s
491
+ }
492
+
493
+ if payment_id
494
+ args['paymentId'] = payment_id.to_s
495
+ end
496
+
497
+ return self.call('withdraw', args)
498
+ end
499
+
500
+ # If you are enrolled in the maker-taker fee schedule, returns your
501
+ # current trading fees and trailing 30-day volume in BTC. This
502
+ # information is updated once every 24 hours.
503
+ def return_fee_info
504
+ return self.call('returnFeeInfo')
505
+ end
506
+
507
+ # Returns your balances sorted by account. You may optionally specify
508
+ # the "account" parameter if you wish to fetch only the balances of
509
+ # one account. Please note that balances in your margin account may not
510
+ # be accessible if you have any open margin positions or orders.
511
+ def return_available_account_balances(account = false)
512
+ if account
513
+ args = {
514
+ 'account' => account.to_s.upcase
515
+ }
516
+ return self.call('returnAvailableAccountBalances', args)
517
+ else
518
+ return self.call('returnAvailableAccountBalances')
519
+ end
520
+ end
521
+
522
+ # Returns your current tradable balances for each currency in each
523
+ # market for which margin trading is enabled. Please note that these
524
+ # balances may vary continually with market conditions.
525
+ def return_tradable_balances
526
+ return self.call('returnTradableBalances')
527
+ end
528
+
529
+ # Transfers funds from one account to another (e.g. from your
530
+ # exchange account to your margin account). Required parameters are
531
+ # "currency", "amount", "fromAccount", and "toAccount"
532
+ def transfer_balance(currency, amount, from_account, to_account, confirmed = false)
533
+ args = {
534
+ 'currency' => currency.to_s.upcase,
535
+ 'amount' => amount.to_s,
536
+ 'fromAccount' => from_account.to_s,
537
+ 'toAccount' => to_account.to_s
538
+ }
539
+ if confirmed
540
+ args['confirmed'] = 1
541
+ end
542
+
543
+ return self.call('transferBalance', args)
544
+ end
545
+
546
+ # Returns a summary of your entire margin account. This is the same
547
+ # information you will find in the Margin Account section of the Margin
548
+ # Trading page, under the Markets list
549
+ def return_margin_account_summary
550
+ return self.call('returnMarginAccountSummary')
551
+ end
552
+
553
+ # Places a margin buy order in a given market. Required parameters are
554
+ # "currencyPair", "rate", and "amount". You may optionally specify a
555
+ # maximum lending rate using the "lendingRate" parameter (defaults to 2).
556
+ # If successful, the method will return the order number and any trades
557
+ # immediately resulting from your order.
558
+ #
559
+ # TODO: UNTESTED
560
+ def margin_buy(currency_pair, rate, amount, lending_rate = 2)
561
+ args = {
562
+ 'currencyPair' => currency_pair.to_s.upcase,
563
+ 'rate' => rate.to_s,
564
+ 'amount' => amount.to_s,
565
+ 'lendingRate' => lending_rate.to_s
566
+ }
567
+ return self.call('marginBuy', args)
568
+ end
569
+
570
+ # Places a margin sell order in a given market. Parameters and output
571
+ # are the same as for the marginBuy method.
572
+ def margin_sell(currency_pair, rate, amount, lending_rate = 2)
573
+ args = {
574
+ 'currencyPair' => currency_pair.to_s.upcase,
575
+ 'rate' => rate.to_s,
576
+ 'amount' => amount.to_s,
577
+ 'lendingRate' => lending_rate.to_s
578
+ }
579
+ self.call('marginSell', args)
580
+ end
581
+
582
+ # Returns information about your margin position in a given market,
583
+ # specified by the "currencyPair" parameter. You may set
584
+ # "currencyPair" to "all" if you wish to fetch all of your margin
585
+ # positions at once. If you have no margin position in the specified
586
+ # market, "type" will be set to "none". "liquidationPrice" is an
587
+ # estimate, and does not necessarily represent the price at which an
588
+ # actual forced liquidation will occur. If you have no liquidation price,
589
+ # the value will be -1. (defaults to 'all')
590
+ def get_margin_position(currency_pair = 'all')
591
+ args = {
592
+ 'currencyPair' => currency_pair.to_s.upcase
593
+ }
594
+ return self.call('getMarginPosition', args)
595
+ end
596
+
597
+ # Closes your margin position in a given market (specified by the
598
+ # "currencyPair" parameter) using a market order. This call will also
599
+ # return success if you do not have an open position in the specified
600
+ # market.
601
+ def close_margin_position(currency_pair)
602
+ args = {
603
+ 'currencyPair' => currency_pair.to_s_upcase
604
+ }
605
+ return self.call('currencyPair', args)
606
+ end
607
+
608
+ # Creates a loan offer for a given currency. Required parameters are
609
+ # "currency", "amount", "lendingRate", "duration" (num of days, defaults
610
+ # to 2), "autoRenew" (0 or 1, defaults to 0 'off').
611
+ def create_loan_offer(currency, amount, lending_rate, auto_renew = 0, duration = 2)
612
+ args = {
613
+ 'currency' => currency.to_s.upcase,
614
+ 'amount' => amount.to_s,
615
+ 'duration' => duration.to_s,
616
+ 'autoRenew' => auto_renew.to_s,
617
+ 'lendingRate' => lending_rate.to_s
618
+ }
619
+ return self.call('createLoanOffer', args)
620
+ end
621
+
622
+ # Cancels a loan offer specified by the "orderNumber" parameter.
623
+ def cancel_loan_offer(order_number)
624
+ args = {
625
+ 'orderNumber' => order_number.to_s
626
+ }
627
+ return self.call('cancelLoanOffer', args)
628
+ end
629
+
630
+ # Returns your open loan offers for each currency.
631
+ def return_open_loan_offers
632
+ return self.call('returnOpenLoanOffers')
633
+ end
634
+
635
+ # Returns your active loans for each currency.
636
+ def return_active_loans
637
+ return self.call('returnActiveLoans')
638
+ end
639
+
640
+ # Returns your lending history within a time range specified by the
641
+ # "start" and "end" parameters as UNIX timestamps. "limit" may also
642
+ # be specified to limit the number of rows returned. (defaults to the last
643
+ # months history)
644
+ def return_lending_history(_start = false, _end = false, limit = false)
645
+ unless _start
646
+ _start = Time.now.to_i - Poloniex::MONTH
647
+ end
648
+ unless _end
649
+ _end = Time.now.to_i
650
+ end
651
+ args = {
652
+ 'start' => _start.to_s,
653
+ 'end' => _end.to_s
654
+ }
655
+ if limit
656
+ args['limit'] = limit.to_s
657
+ end
658
+ return self.call('returnLendingHistory', args)
659
+ end
660
+
661
+ # Toggles the autoRenew setting on an active loan, specified by the
662
+ # "orderNumber" parameter. If successful, "message" will indicate
663
+ # the new autoRenew setting.
664
+ def toggle_auto_renew(order_number)
665
+ args = {
666
+ 'orderNumber' => order_number.to_s
667
+ }
668
+ self.call('toggleAutoRenew', args)
669
+ end
670
+
671
+ protected
672
+
673
+ attr_accessor :logger, :_nonce, :json_nums, :timeout
674
+
675
+ # Increments the nonce
676
+ def nonce
677
+ self._nonce += 42
678
+ end
679
+
680
+ # Gets the current time-based nonce
681
+ # example: 15038536855080986
682
+ def nonce_time
683
+ "#{'%.6f' % Time.now.to_f}".gsub('.', '').to_i
684
+ end
685
+
686
+ # TODO utilize path and port
687
+ def _get(uri, path = nil, port = nil)
688
+ address = URI.parse(uri)
689
+ Net::HTTP.get(address)
690
+ end
691
+
692
+ def _post(url, data = {}, initheader = nil, dest = nil)
693
+ address = URI.parse(url)
694
+ form_data = data
695
+ headers = initheader
696
+
697
+ http = Net::HTTP.new(address.host, address.port)
698
+ http.use_ssl = true
699
+
700
+ request = Net::HTTP::Post.new(address.request_uri, headers)
701
+ request.body = URI.encode_www_form(form_data).encode(UTF_8)
702
+
703
+ response = http.request(request)
704
+ response
705
+ end
706
+
707
+ end
708
+
709
+ end
710
+
711
+ require 'poloniex/exceptions'
@@ -0,0 +1,21 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+
5
+ require 'poloniex/version'
6
+
7
+ Gem::Specification.new do |s|
8
+ s.name = 'poloniex_api'
9
+ s.version = Poloniex::VERSION
10
+ s.date = '2017-08-27'
11
+ s.summary = "Poloniex API Wrapper"
12
+ s.description = "Poloniex API wrapper for Ruby 2.1.5+"
13
+ s.authors = ["Brian McMichael"]
14
+ s.email = 'brian@brianmcmichael.com'
15
+ s.files = `git ls-files`.split("\n")
16
+ s.require_paths = ["lib"]
17
+ s.homepage =
18
+ 'http://rubygems.org/gems/poloniex_api'
19
+ s.license = 'GPLv2'
20
+ end
21
+
metadata ADDED
@@ -0,0 +1,51 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: poloniex_api
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Brian McMichael
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2017-08-27 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: Poloniex API wrapper for Ruby 2.1.5+
14
+ email: brian@brianmcmichael.com
15
+ executables: []
16
+ extensions: []
17
+ extra_rdoc_files: []
18
+ files:
19
+ - ".gitignore"
20
+ - CONTRIBUTING.md
21
+ - LICENSE
22
+ - README.md
23
+ - lib/poloniex.rb
24
+ - lib/poloniex/exceptions.rb
25
+ - lib/poloniex/version.rb
26
+ - poloniex_api.gemspec
27
+ homepage: http://rubygems.org/gems/poloniex_api
28
+ licenses:
29
+ - GPLv2
30
+ metadata: {}
31
+ post_install_message:
32
+ rdoc_options: []
33
+ require_paths:
34
+ - lib
35
+ required_ruby_version: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ version: '0'
40
+ required_rubygems_version: !ruby/object:Gem::Requirement
41
+ requirements:
42
+ - - ">="
43
+ - !ruby/object:Gem::Version
44
+ version: '0'
45
+ requirements: []
46
+ rubyforge_project:
47
+ rubygems_version: 2.2.2
48
+ signing_key:
49
+ specification_version: 4
50
+ summary: Poloniex API Wrapper
51
+ test_files: []