poloapi 1.0.0 → 1.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 +4 -4
- data/examples/lending.rb +329 -0
- data/lib/poloapi/version.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d291e88252736677abeeac54fa97dc00d0274ba6
|
4
|
+
data.tar.gz: 4f589d42a2c5aae5592f8c4bc01c3d30855a1fd4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 57a1ffcfff25ccb2c02193c1649cbfcc2950c0cd6205db0a75f50f37620b629e9449ffc0e8958199f77dc335a7d241310228e09054489b9481022a88bde20a1f
|
7
|
+
data.tar.gz: ce49d5966ea01642df506a88d4685d76348e84535587509b710e432c873352e5b3c76d69538be0f5aacd2fe41c7a68a042400bd7abce56f6dfeb07100782250b
|
data/examples/lending.rb
ADDED
@@ -0,0 +1,329 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# Kost
|
3
|
+
|
4
|
+
require 'bundler/setup'
|
5
|
+
require 'poloapi'
|
6
|
+
require 'logger'
|
7
|
+
require 'yaml'
|
8
|
+
require 'optparse'
|
9
|
+
require 'bigdecimal'
|
10
|
+
|
11
|
+
require 'pp'
|
12
|
+
|
13
|
+
|
14
|
+
$PRGNAME="lending"
|
15
|
+
$options = {}
|
16
|
+
$options['loglevel'] = 'WARN'
|
17
|
+
# $options['loglevel'] = "INFO"
|
18
|
+
$options['logname'] = nil
|
19
|
+
|
20
|
+
# $options['maxordertime']=300
|
21
|
+
$options['maxordertime']=1500
|
22
|
+
$options['loanduration']=2
|
23
|
+
$options['loanautorenew']=0
|
24
|
+
$options['sleeploop']=60
|
25
|
+
$options['loanminamount'] = 0.01 # minimum amount to lend
|
26
|
+
# $options['loanmin'] = 0.0005 # global loan minimum rate
|
27
|
+
$options['loanmin'] = 0.0001 # global loan minimum rate
|
28
|
+
# $options['loanmincur']= {'BTC' => 0.0007500, 'ETH' => 0.0002 } # minimum rate per currency
|
29
|
+
$options['loanmincur']= {'BTC' => 0.0003000, 'ETH' => 0.0002 } # minimum rate per currency
|
30
|
+
$options['loanmaxorderamount'] = '1.32' # in front of which max order to put
|
31
|
+
$options['loanmaxorderamountcur'] = {'BTC' => 1.32, 'ETH' => 10.1 }
|
32
|
+
$options['loanmaxordercount'] = '25' # when this number of orders reach, don't create new orders
|
33
|
+
$options['loanmaxordercountcur'] = {'BTC' => 25, 'ETH' => 30 } # when this number of orders reach, don't create new orders
|
34
|
+
|
35
|
+
# helpful class for logger
|
36
|
+
class MultiDelegator
|
37
|
+
def initialize(*targets)
|
38
|
+
@targets = targets
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.delegate(*methods)
|
42
|
+
methods.each do |m|
|
43
|
+
define_method(m) do |*args|
|
44
|
+
@targets.map { |t| t.send(m, *args) }
|
45
|
+
end
|
46
|
+
end
|
47
|
+
self
|
48
|
+
end
|
49
|
+
|
50
|
+
class <<self
|
51
|
+
alias to new
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
#begin
|
56
|
+
optyaml = YAML::load_file(ENV['HOME']+'/.pololending')
|
57
|
+
# rescue # Errno::ENOENT
|
58
|
+
#end
|
59
|
+
|
60
|
+
if optyaml != nil then
|
61
|
+
$options.merge!(optyaml)
|
62
|
+
end
|
63
|
+
|
64
|
+
# File.open(ENV['HOME']+'/.pololending-ex', 'w') {|f| f.write $options.to_yaml }
|
65
|
+
|
66
|
+
# initialize logger
|
67
|
+
if $options['logname'] != nil then
|
68
|
+
log_file = File.open($options['logname'], 'a')
|
69
|
+
$log = Logger.new MultiDelegator.delegate(:write, :close).to(STDERR, log_file)
|
70
|
+
else
|
71
|
+
$log = Logger.new MultiDelegator.delegate(:write, :close).to(STDERR)
|
72
|
+
end
|
73
|
+
loglevel = Logger.const_get $options['loglevel'] # Logger::INFO # default is ::WARN
|
74
|
+
$log.level = loglevel
|
75
|
+
|
76
|
+
|
77
|
+
OptionParser.new do |opts|
|
78
|
+
opts.banner = "Usage: #{$PRGNAME} [options]"
|
79
|
+
|
80
|
+
opts.on("-h", "--help", "Prints this help") do
|
81
|
+
puts opts
|
82
|
+
exit
|
83
|
+
end
|
84
|
+
|
85
|
+
opts.on("-v", "--[no-]verbose", "Run verbosely") do |v|
|
86
|
+
$options['verbose'] = v
|
87
|
+
$log.level = Logger::INFO
|
88
|
+
end
|
89
|
+
|
90
|
+
opts.on("-d", "--[no-]debug", "Run in debug mode") do |v|
|
91
|
+
$options['debug'] = v
|
92
|
+
$log.level = Logger::DEBUG
|
93
|
+
end
|
94
|
+
|
95
|
+
opts.on("-s", "--secret NAME", "use NAME as secret to poloniex") do |optarg|
|
96
|
+
$options['secret'] = optarg
|
97
|
+
end
|
98
|
+
|
99
|
+
opts.on("-k", "--key NAME", "use NAME as key to poloniex ") do |optarg|
|
100
|
+
$options['key'] = optarg
|
101
|
+
end
|
102
|
+
|
103
|
+
opts.on("-l", "--log FILE", "log to FILE") do |optarg|
|
104
|
+
$options['logname'] = optarg
|
105
|
+
end
|
106
|
+
|
107
|
+
opts.separator ""
|
108
|
+
opts.separator "Example #1: #{$PRGNAME} -k poloniex-key -s poloniex-secret"
|
109
|
+
end.parse!
|
110
|
+
|
111
|
+
# pp $options
|
112
|
+
|
113
|
+
if !$options.has_key?('key') or !$options.has_key?('secret') then
|
114
|
+
$log.error("No key/secrets specified! Specify with -k and -s!")
|
115
|
+
exit
|
116
|
+
end
|
117
|
+
|
118
|
+
Poloapi.setup do | config |
|
119
|
+
config.key = $options['key']
|
120
|
+
config.secret = $options['secret']
|
121
|
+
end
|
122
|
+
|
123
|
+
def toggleAutoRenew(onr)
|
124
|
+
result=JSON.parse(Poloapi.post('toggleAutoRenew', :orderNumber => onr))
|
125
|
+
return result
|
126
|
+
end
|
127
|
+
|
128
|
+
def cancelOrder(oid)
|
129
|
+
result=JSON.parse(Poloapi.post('cancelLoanOffer', :orderNumber => oid))
|
130
|
+
return result
|
131
|
+
end
|
132
|
+
|
133
|
+
def getBestLoanOrder(curid)
|
134
|
+
loanorders=JSON.parse(Poloapi.get('returnLoanOrders', :currency => curid))
|
135
|
+
unless loanorders["offers"].nil?
|
136
|
+
bestorder = loanorders["offers"].first
|
137
|
+
numloanoffers = loanorders["offers"].count
|
138
|
+
$log.info("With #{numloanoffers} order(s), lowest order is: #{bestorder['rate']}")
|
139
|
+
return bestorder['rate']
|
140
|
+
end
|
141
|
+
return nil
|
142
|
+
end
|
143
|
+
|
144
|
+
def getBestPossibleLoanOrder(curid)
|
145
|
+
loanorders=JSON.parse(Poloapi.get('returnLoanOrders', :currency => curid))
|
146
|
+
unless loanorders["offers"].nil?
|
147
|
+
numloanoffers = loanorders["offers"].count
|
148
|
+
exorder = loanorders["offers"].first
|
149
|
+
bestorder = loanorders["offers"].last
|
150
|
+
loanorders["offers"].each_with_index do |offer,offid|
|
151
|
+
if offer["amount"] > $options['loanmaxorderamount'] then
|
152
|
+
bestorder = offer
|
153
|
+
# bestorder['rate'] = (bestorder['rate'].to_f - 0.00000001).to_s
|
154
|
+
bestorder['rate'] = (BigDecimal.new(bestorder['rate']) - BigDecimal.new('0.00000001')).to_s('F')
|
155
|
+
$log.info("Looking best possible place, With #{numloanoffers} order(s), best possible order is (skipped #{offid}): #{bestorder['rate']}, higher is #{offer['rate']} with amount #{offer['amount']}")
|
156
|
+
break
|
157
|
+
else
|
158
|
+
exorder=offer
|
159
|
+
end
|
160
|
+
end
|
161
|
+
return bestorder['rate']
|
162
|
+
end
|
163
|
+
return nil
|
164
|
+
end
|
165
|
+
|
166
|
+
|
167
|
+
def getMinLoanOrder(curid,options)
|
168
|
+
minorder=0.0 # sane minimum
|
169
|
+
unless options['loanmin'].nil?
|
170
|
+
minorder=options['loanmin']
|
171
|
+
end
|
172
|
+
unless options['loanmincur'][curid].nil?
|
173
|
+
minorder=options['loanmincur'][curid]
|
174
|
+
end
|
175
|
+
return minorder
|
176
|
+
end
|
177
|
+
|
178
|
+
while true
|
179
|
+
$log.info("Starting loop")
|
180
|
+
|
181
|
+
begin
|
182
|
+
myofferloans=JSON.parse(Poloapi.post('returnOpenLoanOffers'))
|
183
|
+
unless myofferloans.nil?
|
184
|
+
myofferloans.each do |cur,items|
|
185
|
+
unless items.nil? then
|
186
|
+
olamount=0.0
|
187
|
+
olrate=0.0
|
188
|
+
items.each do |item|
|
189
|
+
olamount=olamount+item["amount"].to_f
|
190
|
+
olrate=olrate+item["rate"].to_f
|
191
|
+
end
|
192
|
+
$log.info("Open orders for #{cur}: #{items.count} with #{olamount} average rate #{olrate/items.count}")
|
193
|
+
bestorder=getBestLoanOrder(cur)
|
194
|
+
items.each do |item|
|
195
|
+
if bestorder.nil? then
|
196
|
+
bestorder=item["rate"]
|
197
|
+
end
|
198
|
+
dt=DateTime.parse(item["date"])
|
199
|
+
diff=Time.now.utc.to_i - dt.to_time.to_i
|
200
|
+
if diff > $options['maxordertime'] then
|
201
|
+
bOrder=getBestLoanOrder(cur)
|
202
|
+
puts "#{bOrder} - #{item['rate']}"
|
203
|
+
minorder=getMinLoanOrder(cur[0],$options)
|
204
|
+
if bOrder.to_f >= item["rate"].to_f or item["rate"].to_f <= minorder then
|
205
|
+
$log.info("Best order #{item['id']} with diff #{diff} - timeout reached, still best offer")
|
206
|
+
else
|
207
|
+
$log.warn("Canceling order #{item['id']} with time diff #{diff} - timeout reached")
|
208
|
+
cancelOrder(item['id'])
|
209
|
+
end
|
210
|
+
end
|
211
|
+
end
|
212
|
+
end
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
216
|
+
# Poloniex.balances
|
217
|
+
|
218
|
+
# if false
|
219
|
+
mybalances=JSON.parse(Poloapi.post('returnAvailableAccountBalances'))
|
220
|
+
|
221
|
+
|
222
|
+
unless mybalances.nil? or mybalances.empty?
|
223
|
+
balstr = ''
|
224
|
+
mybalances.each do |name,b|
|
225
|
+
balstr << name
|
226
|
+
balstr << ": "
|
227
|
+
b.each do |cur|
|
228
|
+
balstr << cur[0].to_s
|
229
|
+
balstr << " "
|
230
|
+
balstr << cur[1].to_s
|
231
|
+
balstr << " "
|
232
|
+
end
|
233
|
+
balstr << "; "
|
234
|
+
end
|
235
|
+
$log.info "Available balance(s): #{balstr}"
|
236
|
+
|
237
|
+
unless mybalances['lending'].nil? then
|
238
|
+
balstr=''
|
239
|
+
mybalances["lending"].each do |cur|
|
240
|
+
balstr << cur[0]
|
241
|
+
balstr << " "
|
242
|
+
balstr << cur[1]
|
243
|
+
balstr << " "
|
244
|
+
$log.info "Available lending balance: #{balstr}"
|
245
|
+
|
246
|
+
if cur[1].to_f < $options['loanminamount'] then
|
247
|
+
$log.info "Minimum balance not reached for #{cur[0]}: #{$options['loanminamount']}"
|
248
|
+
next
|
249
|
+
end
|
250
|
+
|
251
|
+
bestorder=getBestPossibleLoanOrder(cur[0])
|
252
|
+
# bestorder=getBestLoanOrder(cur[0])
|
253
|
+
|
254
|
+
unless bestorder.nil?
|
255
|
+
minorder=getMinLoanOrder(cur[0],$options)
|
256
|
+
|
257
|
+
# create order with minimum loan defined
|
258
|
+
bestorderf = bestorder.to_f
|
259
|
+
loanorder=bestorder.to_f
|
260
|
+
if bestorderf > minorder then
|
261
|
+
orderstate="Above minimum."
|
262
|
+
else
|
263
|
+
orderstate="Minimum reached: #{minorder}."
|
264
|
+
loanorder=minorder
|
265
|
+
end
|
266
|
+
# TODO if $options['loanmaxordercount']
|
267
|
+
$log.warn("#{orderstate} Creating lend offer for #{cur[0]} #{cur[1]} with rate #{loanorder}")
|
268
|
+
loanorders=JSON.parse(Poloapi.post('createLoanOffer', {:currency => cur[0], :amount => cur[1], :duration => $options['loanduration'], :autoRenew => $options['loanautorenew'], :lendingRate => loanorder}))
|
269
|
+
$log.info(loanorders.to_s)
|
270
|
+
end
|
271
|
+
end
|
272
|
+
else
|
273
|
+
$log.info "No available lending balance"
|
274
|
+
end
|
275
|
+
end
|
276
|
+
|
277
|
+
myactloans=JSON.parse(Poloapi.post('returnActiveLoans'))
|
278
|
+
unless myactloans["provided"].nil?
|
279
|
+
#lendprofit=0.0
|
280
|
+
lprofit=Hash.new
|
281
|
+
lamount=Hash.new
|
282
|
+
lcount=Hash.new
|
283
|
+
lendcount=myactloans["provided"].count
|
284
|
+
myactloans["provided"].each do |i|
|
285
|
+
if lprofit[i["currency"]].nil?
|
286
|
+
lprofit[i["currency"]]=BigDecimal.new(0)
|
287
|
+
end
|
288
|
+
if lamount[i["currency"]].nil?
|
289
|
+
lamount[i["currency"]]=BigDecimal.new(0)
|
290
|
+
end
|
291
|
+
if lcount[i["currency"]].nil?
|
292
|
+
lcount[i["currency"]]=1
|
293
|
+
else
|
294
|
+
lcount[i["currency"]]=lcount[i["currency"]]+1
|
295
|
+
end
|
296
|
+
lprofit[i["currency"]]=lprofit[i["currency"]]+BigDecimal.new(i["fees"])
|
297
|
+
lamount[i["currency"]]=lamount[i["currency"]]+BigDecimal.new(i["amount"])
|
298
|
+
# lendprofit=lendprofit+i["fees"].to_f
|
299
|
+
end
|
300
|
+
profitstr=''
|
301
|
+
lprofit.keys.each do |currency|
|
302
|
+
total=lamount[currency]+lprofit[currency]
|
303
|
+
profitstr << "#{currency} Orders: #{lcount[currency]}; #{lamount[currency].to_s('F')} with profit: #{lprofit[currency].to_s('F')} should be: #{total.to_s('F')} ; "
|
304
|
+
end
|
305
|
+
$log.info "With #{lendcount} loans active, #{profitstr}, "
|
306
|
+
end
|
307
|
+
|
308
|
+
unless myactloans["provided"].nil?
|
309
|
+
myactloans["provided"].each do |i|
|
310
|
+
if i["autoRenew"] == 1 then
|
311
|
+
loanid=i["id"]
|
312
|
+
$log.warn "Canceling auto renew on #{loanid}"
|
313
|
+
ret=toggleAutoRenew(loanid)
|
314
|
+
puts ret
|
315
|
+
sleep 1
|
316
|
+
end
|
317
|
+
end
|
318
|
+
end
|
319
|
+
|
320
|
+
rescue StandardError => e
|
321
|
+
$log.warn("Error #{$!}: #{e.backtrace}")
|
322
|
+
end
|
323
|
+
|
324
|
+
$log.info("Finishing up and sleeping for #{$options['sleeploop']}")
|
325
|
+
sleep $options['sleeploop']
|
326
|
+
end
|
327
|
+
|
328
|
+
|
329
|
+
|
data/lib/poloapi/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: poloapi
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Vlatko Kosturjak
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-06-
|
11
|
+
date: 2017-06-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -79,6 +79,7 @@ files:
|
|
79
79
|
- LICENSE.txt
|
80
80
|
- README.md
|
81
81
|
- Rakefile
|
82
|
+
- examples/lending.rb
|
82
83
|
- lib/poloapi.rb
|
83
84
|
- lib/poloapi/version.rb
|
84
85
|
- poloapi.gemspec
|