Skip to content

Commit bd547b8

Browse files
committed
new spread algo, rounding issue fixed
1 parent 1f0aa56 commit bd547b8

File tree

1 file changed

+45
-63
lines changed

1 file changed

+45
-63
lines changed

lendingbot.py

Lines changed: 45 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22
from poloniex import Poloniex
33
from ConfigParser import SafeConfigParser
44
from Logger import Logger
5+
from decimal import *
6+
7+
SATOSHI = Decimal(10) ** -8
58

69
config = SafeConfigParser()
710
config_location = 'default.cfg'
@@ -16,15 +19,15 @@
1619
#sleep between iterations, time in seconds
1720
sleeptime = 60
1821
#minimum daily lend rate in percent
19-
mindailyrate = 0.04
22+
mindailyrate = 0.01
2023
#max rate. 2% is good choice because it's default at margin trader interface. 5% is max to be accepted by the exchange
2124
maxdailyrate = 2
2225
#The number of offers to split the available balance uniformly across the [gaptop, gapbottom] range.
2326
spreadlend = 3
2427
#The depth of lendbook (in percent of lendable balance) to move through before placing the first (gapbottom) and last (gaptop) offer.
2528
#if gapbottom is set to 0, the first offer will be at the lowest possible rate. However some low value is recommended (say 10%) to skip dust offers
26-
gapbottom = 10
27-
gaptop = 200
29+
gapbottom = 1
30+
gaptop = 100
2831
#Daily lend rate threshold after which we offer lends for 60 days as opposed to 2. If set to 0 all offers will be placed for a 2 day period
2932
sixtydaythreshold = 0.2
3033
#custom config per coin, useful when closing positions etc.
@@ -44,11 +47,11 @@
4447

4548

4649
sleepTime = float(config.get("BOT","sleeptime"))
47-
minDailyRate = float(config.get("BOT","mindailyrate"))/100
48-
maxDailyRate = float(config.get("BOT","maxdailyrate"))/100
50+
minDailyRate = Decimal(config.get("BOT","mindailyrate"))/100
51+
maxDailyRate = Decimal(config.get("BOT","maxdailyrate"))/100
4952
spreadLend = int(config.get("BOT","spreadlend"))
50-
gapBottom = float(config.get("BOT","gapbottom"))
51-
gapTop = float(config.get("BOT","gaptop"))
53+
gapBottom = Decimal(config.get("BOT","gapbottom"))
54+
gapTop = Decimal(config.get("BOT","gaptop"))
5255
sixtyDayThreshold = float(config.get("BOT","sixtydaythreshold"))/100
5356

5457
try:
@@ -57,7 +60,7 @@
5760
#coinconfig parser
5861
for cur in coinconfig:
5962
cur = cur.split(':')
60-
coincfg[cur[0]] = dict(minrate=(float(cur[1]))/100, maxactive=float(cur[2]))
63+
coincfg[cur[0]] = dict(minrate=(Decimal(cur[1]))/100, maxactive=Decimal(cur[2]))
6164
except Exception as e:
6265
pass
6366

@@ -89,33 +92,39 @@ def timestamp():
8992
bot = Poloniex(config.get("API","apikey"), config.get("API","secret"))
9093
log = Logger()
9194

92-
def totalLended():
95+
#total lended global variable
96+
totalLended = {}
97+
98+
def refreshTotalLended():
99+
global totalLended
93100
cryptoLended = bot.returnActiveLoans()
94101

95-
allPairs = {}
96-
cryptoLendedSum = float(0)
102+
totalLended = {}
103+
cryptoLendedSum = Decimal(0)
97104

98105
for item in cryptoLended["provided"]:
99106
itemStr = item["amount"].encode("utf-8")
100-
itemFloat = float(itemStr)
101-
if item["currency"] in allPairs:
102-
cryptoLendedSum = allPairs[item["currency"]] + itemFloat
103-
allPairs[item["currency"]] = cryptoLendedSum
107+
itemFloat = Decimal(itemStr)
108+
if item["currency"] in totalLended:
109+
cryptoLendedSum = totalLended[item["currency"]] + itemFloat
110+
totalLended[item["currency"]] = cryptoLendedSum
104111
else:
105112
cryptoLendedSum = itemFloat
106-
allPairs[item["currency"]] = cryptoLendedSum
113+
totalLended[item["currency"]] = cryptoLendedSum
114+
115+
def stringifyTotalLended():
107116
result = 'Lended: '
108-
for key in sorted(allPairs):
109-
result += '[' + "%.3f" % float(allPairs[key]) + ' '
117+
for key in sorted(totalLended):
118+
result += '[' + "%.3f" % Decimal(totalLended[key]) + ' '
110119
result += key + '] '
111120
return result
112121

113122
def createLoanOffer(cur,amt,rate):
114123
days = '2'
115-
#if (minDailyRate - 0.000001) < rate and float(amt) > 0.001:
124+
#if (minDailyRate - 0.000001) < rate and Decimal(amt) > 0.001:
116125
if float(amt) > 0.001:
117126
rate = float(rate) - 0.000001 #lend offer just bellow the competing one
118-
amt = "%.8f" % float(amt)
127+
amt = "%.8f" % Decimal(amt)
119128
if rate > sixtyDayThreshold:
120129
days = '60'
121130
if sixtyDayThreshold == 0:
@@ -136,7 +145,7 @@ def cancelAndLoanAll():
136145
onOrderBalances = {}
137146
for cur in loanOffers:
138147
for offer in loanOffers[cur]:
139-
onOrderBalances[cur] = onOrderBalances.get(cur, 0) + float(offer['amount'])
148+
onOrderBalances[cur] = onOrderBalances.get(cur, 0) + Decimal(offer['amount'])
140149
if dryRun == False:
141150
msg = bot.cancelLoanOffer(cur,offer['id'])
142151
log.cancelOrders(cur, msg)
@@ -161,76 +170,49 @@ def cancelAndLoanAll():
161170
log.log('Using custom mindailyrate ' + str(coincfg[activeCur]['minrate']*100) + '% for ' + activeCur)
162171

163172
loans = bot.returnLoanOrders(activeCur)
164-
s = float(0) #sum
173+
s = Decimal(0) #sum
165174
i = int(0) #offer book iterator
166175
j = int(0) #spread step count
167-
lent = float(0)
176+
lent = Decimal(0)
168177
step = (gapTop - gapBottom)/spreadLend
169178
#TODO check for minimum lendable amount, and try to decrease the spread. e.g. at the moment balances lower than 0.001 won't be lent
170179
#in case of empty lendbook, lend at max
180+
activePlusLended = Decimal(activeBal)
181+
if activeCur in totalLended:
182+
activePlusLended += Decimal(totalLended[activeCur])
171183
if len(loans['offers']) == 0:
172-
createLoanOffer(activeCur,float(activeBal)-lent,maxDailyRate)
184+
createLoanOffer(activeCur,Decimal(activeBal)-lent,maxDailyRate)
173185
for offer in loans['offers']:
174-
s = s + float(offer['amount'])
186+
s = s + Decimal(offer['amount'])
175187
s2 = s
176188
while True:
177-
if s2 > float(activeBal)*(gapBottom/100+(step/100*j)) and float(offer['rate']) > curMinDailyRate:
189+
if s2 > activePlusLended*(gapBottom/100+(step/100*j)) and Decimal(offer['rate']) > curMinDailyRate:
178190
j += 1
179-
#ran into a problem were 14235.82451057 couldn't be lent because of rounding
180-
s2 = s2 + float(activeBal)/spreadLend - 0.00000001
191+
s2 = s2 + Decimal(activeBal)/spreadLend
181192
else:
182193
createLoanOffer(activeCur,s2-s,offer['rate'])
183-
lent = lent + (s2-s)
194+
lent = lent + (s2-s).quantize(SATOSHI)
184195
break
185196
if j == spreadLend:
186-
createLoanOffer(activeCur,float(activeBal)-lent,offer['rate'])
197+
createLoanOffer(activeCur,Decimal(activeBal)-lent,offer['rate'])
187198
break
188199
if j == spreadLend:
189200
break
190201
i += 1
191202
if i == len(loans['offers']): #end of the offers lend at max
192-
createLoanOffer(activeCur,float(activeBal)-lent,maxDailyRate)
193-
194-
cryptoLendedOld = {u'provided': []}
195-
cryptoLendedAll = {}
196-
197-
def profit():
198-
global cryptoLendedOld
199-
global cryptoLendedAll
200-
cryptoLended = bot.returnActiveLoans()
201-
202-
cryptoLendedSum = float(0)
203-
204-
for item in cryptoLended["provided"]:
205-
for itemOld in cryptoLendedOld["provided"]:
206-
if item["id"] == itemOld["id"]:
207-
itemFloat = float(item["fees"].encode("utf-8"))
208-
itemFloatOld = float(itemOld["fees"].encode("utf-8"))
209-
# log.log('Matching Loans: ' + str(item["id"]) + ' ' + str(itemOld["id"]) + ' ' + str(itemFloat) + ' ' + str(itemFloatOld))
210-
if item["currency"] in cryptoLendedAll:
211-
cryptoLendedSum = cryptoLendedAll[item["currency"]] + itemFloat - itemFloatOld
212-
cryptoLendedAll[item["currency"]] = cryptoLendedSum
213-
else:
214-
cryptoLendedSum = itemFloat - itemFloatOld
215-
cryptoLendedAll[item["currency"]] = cryptoLendedSum
216-
break
217-
cryptoLendedOld = cryptoLended
218-
result = 'Run-time: '
219-
for key in sorted(cryptoLendedAll):
220-
result += '[' + "%.8f" % float(cryptoLendedAll[key]) + ' '
221-
result += key + '] '
222-
return result
203+
createLoanOffer(activeCur,Decimal(activeBal)-lent,maxDailyRate)
223204

224205
log.log('Welcome to Poloniex Lending Bot')
225206

226207
while True:
227208
try:
228-
log.refreshStatus(totalLended() + profit())
209+
refreshTotalLended()
210+
log.refreshStatus(stringifyTotalLended())
229211
cancelAndLoanAll()
230212
except Exception as e:
231213
log.log("ERROR: " + str(e))
232214
pass
233215
except KeyboardInterrupt:
234216
print '\nbye'
235217
exit(0)
236-
time.sleep(sleepTime)
218+
time.sleep(sleepTime)

0 commit comments

Comments
 (0)