Skip to content

Commit 4675fea

Browse files
committed
Bug fixes related to Mimic wallets
Changes to be committed: modified: Base/DSR-PlaceOrder modified: Base/Library/CONDccxt.py modified: Base/Library/CONDmimic.py modified: Base/Library/JRRmimic.py modified: Extras/CodeProofs/placeOrder modified: Extras/OliverTwist/otProfits modified: Extras/TV2Exchange
1 parent a3cbfc8 commit 4675fea

File tree

7 files changed

+112
-41
lines changed

7 files changed

+112
-41
lines changed

Base/DSR-PlaceOrder

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,9 @@ def main():
6161
else:
6262
expire=DataTTL
6363
key=relay.Order['Recipe'].replace(" ","")+relay.GetExchangeLast()+relay.GetAccountLast()+relay.Order['Asset']+relay.Order['TCycles']+relay.Order['TBuys']
64-
results=dsrList.update(key,json.dumps(relay.Order),expire)
64+
ro=relay.Order.copy()
65+
ro.pop('Identity',None) # Remove Identity
66+
results=dsrList.update(key,json.dumps(ro),expire)
6567

6668
# Replaced is a special case where the itwem in the list expired, but is not unique.
6769
# Orders must be unique to be processed as legitimate.

Base/Library/CONDccxt.py

Lines changed: 5 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -121,17 +121,8 @@ def OrderProcessor(Orphan):
121121

122122
if makeNewOrder==True:
123123
# Copy original order
124-
newOrder=relay.Order
124+
newOrder=relay.Order.copy()
125125
newOrder['OliverTwist']='Repurchase'
126-
"""
127-
newOrder['Exchange']=relay.Order['Exchange']
128-
newOrder['Account']=relay.Order['Account']
129-
newOrder['Market']=relay.Order['Market']
130-
newOrder['Asset']=relay.Order['Asset']
131-
newOrder['Action']=relay.Order['SellAction']
132-
newOrder['Price']=str(strikePrice)
133-
newOrder['Base']=str(amount)
134-
"""
135126
if 'OrderType' in relay.Order:
136127
newOrder['OrderType']=relay.Order['OrderType']
137128
else:
@@ -177,10 +168,10 @@ def OrderProcessor(Orphan):
177168

178169
if ticker['Bid']>tp:
179170
profit=round((amount*ticker['Bid'])-(amount*price),8)
180-
LogMSG=f"{id}: TP {dir} hit: {tp}, {amount}: {price:.5f} -> {ticker['Bid']:5f}/{profit}"
171+
LogMSG=f"{id}: Prft {dir}, {tp}, {amount}: {price:.5f} -> {ticker['Bid']:5f}/{abs(profit)}"
181172
if 'StopLoss' in relay.Order and ticker['Bid']<sl:
182173
loss=round((amount*price)-(amount*ticker['Bid']),8)
183-
LogMSG=f"{id}: SL {dir} hit: {sl}, {amount}: {price:.5f} -> {ticker['Bid']:5f}/{loss}"
174+
LogMSG=f"{id}: Loss {dir}, {sl}, {amount}: {price:.5f} -> {ticker['Bid']:5f}/{abs(loss)}"
184175

185176
if ticker['Bid']>tp or ('StopLoss' in relay.Order and ticker['Bid']<sl):
186177
strikePrice=ticker['Bid']
@@ -191,10 +182,10 @@ def OrderProcessor(Orphan):
191182

192183
if ticker['Ask']<tp:
193184
profit=round((amount*price)-(amount*ticker['Ask']),8)
194-
LogMSG=f"{id}: TP {dir} hit: {tp}, {amount}: {price:.5f} -> {ticker['Ask']:5f}/{profit}"
185+
LogMSG=f"{id}: Prft {dir}, {tp}, {amount}: {price:.5f} -> {ticker['Ask']:5f}/{abs(profit)}"
195186
if 'StopLoss' in relay.Order and ticker['Ask']>sl:
196187
loss=round((amount*ticker['Ask'])-(amounts*price),8)
197-
LogMSG=f"{id}: SL {dir} hit: {sl}, {amount}: {price:.5f} -> {ticker['Ask']:5f}/{loss}"
188+
LogMSG=f"{id}: Loss {dir}, {sl}, {amount}: {price:.5f} -> {ticker['Ask']:5f}/{abs(loss)}"
198189

199190
if ticker['Ask']<tp or ('StopLoss' in relay.Order and ticker['Ask']>sl):
200191
strikePrice=ticker['Ask']

Base/Library/CONDmimic.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -120,10 +120,10 @@ def OrderProcessor(Orphan):
120120

121121
if ticker['Bid']>tp:
122122
profit=round((amount*ticker['Bid'])-(amount*price),8)
123-
LogMSG=f"{id}: TP {dir} hit: {tp}, {amount}: {price:.5f} -> {ticker['Bid']:5f}/{abs(profit)}"
123+
LogMSG=f"{id}: Prft {dir}, {tp}, {amount}: {price:.8f} -> {ticker['Bid']:5f}/{abs(profit)}"
124124
if 'StopLoss' in relay.Order and ticker['Bid']<sl:
125125
loss=round((amount*price)-(amount*ticker['Bid']),8)
126-
LogMSG=f"{id}: SL {dir} hit: {sl}, {amount}: {price:.5f} -> {ticker['Bid']:5f}/{loss}"
126+
LogMSG=f"{id}: prft {dir}, {sl}, {amount}: {price:.8f} -> {ticker['Bid']:5f}/{abs(loss)}"
127127

128128
if ticker['Bid']>tp or ('StopLoss' in relay.Order and ticker['Bid']<sl):
129129
strikePrice=ticker['Bid']
@@ -134,10 +134,10 @@ def OrderProcessor(Orphan):
134134

135135
if ticker['Ask']<tp:
136136
profit=round((amount*price)-(amount*ticker['Ask']),8)
137-
LogMSG=f"{id}: TP {dir} hit: {tp}, {amount}: {price:.5f} -> {ticker['Ask']:5f}/{abs(profit)}"
137+
LogMSG=f"{id}: Prft {dir}, {tp}, {amount}: {price:.8f} -> {ticker['Ask']:5f}/{abs(profit)}"
138138
if 'StopLoss' in relay.Order and ticker['Ask']>sl:
139139
loss=round((amount*ticker['Ask'])-(amount*price),8)
140-
LogMSG=f"{id}: SL {dir} hit: {sl}, {amount}: {price:.5f} -> {ticker['Ask']:5f}/{loss}"
140+
LogMSG=f"{id}: Loss {dir}, {sl}, {amount}: {price:.8f} -> {ticker['Ask']:5f}/{abs(loss)}"
141141

142142
if ticker['Ask']<tp or ('StopLoss' in relay.Order and ticker['Ask']>sl):
143143
strikePrice=ticker['Ask']

Base/Library/JRRmimic.py

Lines changed: 77 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -238,8 +238,63 @@ def GetOpenOrders(self,**kwargs):
238238
def GetOpenTrades(self,**kwargs):
239239
pass
240240

241+
# Liquidate a wallet, used for position flipping.
242+
243+
def LiquidateWallet(self,asset,fee_rate=0):
244+
base,quote=asset.split('/')
245+
if ':' in asset:
246+
quote=asset.split(':')[1]
247+
if '-' in quote:
248+
quote=quote.split('-')[0]
249+
250+
# Liquidate base value
251+
amount=self.Wallet['Wallet'][base]
252+
self.Wallet['Wallet'][base]=0
253+
254+
ticker=self.Broker.GetTicker(symbol=asset)
255+
if amount<0:
256+
actualPrice=min(ticker['Bid'],ticker['Ask'])-ticker['Spread'] # Short
257+
else:
258+
actualPrice=max(ticker['Bid'],ticker['Ask'])+ticker['Spread'] # Long
259+
260+
# Fees WILL be paid no watter what.
261+
fee=round(abs(amount) * actualPrice * fee_rate,8)
262+
if 'Fees' in self.Wallet['Wallet']:
263+
self.Wallet['Fees']+=fee
264+
else:
265+
self.Wallet['Fees']=fee # Initialize fee balance if not present
266+
267+
total_proceeds=round(abs(amount) * actualPrice * (1 - fee_rate),8)
268+
# Add the total proceeds minus fees to the quote currency balance
269+
if quote in self.Wallet['Wallet']:
270+
self.Wallet['Wallet'][quote]+=total_proceeds
271+
else:
272+
self.Wallet['Wallet'][quote]=total_proceeds # Initialize quote currency balance if not present
273+
274+
# Figure out liquidation direction
275+
if amount>0:
276+
action='sell'
277+
else:
278+
action='buy'
279+
# Update successful
280+
order={}
281+
order['DateTime']=(datetime.now().strftime('%Y-%m-%d %H:%M:%S.%f'))
282+
order['ID']=f"{time.time()*10000000:.0f}"
283+
order['Action']=action
284+
order['Asset']=asset
285+
order[base]=self.Wallet['Wallet'][base]
286+
order[quote]=self.Wallet['Wallet'][quote]
287+
order['Amount']=round(amount,8)
288+
order['Price']=round(actualPrice,8)
289+
order['Fee']=round(fee,8)
290+
JRRsupport.AppendFile(self.history,json.dumps(order)+'\n')
291+
return order
292+
241293
# Manage the wallet. This is where the dirty side of Mimic takes place.
242294

295+
# if b>0, a>0: b+=a, q-=a
296+
# if b<0, a<0: b-=a, q-=abs(a)
297+
243298
def UpdateWallet(self,action,asset,amount,price,fee_rate=0):
244299
# if the account has already been disabled (liquidated), then don't waste time here
245300
if self.Wallet['Enabled']=='N':
@@ -254,17 +309,17 @@ def UpdateWallet(self,action,asset,amount,price,fee_rate=0):
254309
if '-' in quote:
255310
quote=quote.split('-')[0]
256311

257-
# Time to F* with the trader. Simulate dust.
312+
# Time to F* with the trader. Simulate dust/not a full fill.
258313
# It is very rare that an order is filled exactly as requested.
259314
rpct=random.uniform(0, 1)
260-
mda=amount*0.0013
261-
dust=abs(mda)*rpct
315+
mda=abs(amount)*0.0013
316+
dust=mda*rpct
262317
if amount<0: # short
263318
actualAmount=amount+dust
264319
else: # long
265320
actualAmount=amount-dust
266321

267-
# Need to recheck minimum values
322+
# Need to get the actual price of the asset at THIS time, not the price the user wwanted.
268323

269324
ticker=self.Broker.GetTicker(symbol=asset)
270325
if actualAmount<0:
@@ -276,7 +331,7 @@ def UpdateWallet(self,action,asset,amount,price,fee_rate=0):
276331
# Calculate the total cost for buying the asset including fees
277332
total_cost=abs(actualAmount) * actualPrice * (1 + fee_rate)
278333
# Check if the wallet has enough balance for the purchase including fees
279-
if quote in self.Wallet['Wallet'] and self.Wallet['Wallet'][quote] >= total_cost:
334+
if quote in self.Wallet['Wallet'] and self.Wallet['Wallet'][quote]>=total_cost:
280335
# Deduct the total cost including fees from the quote currency balance
281336
self.Wallet['Wallet'][quote]-=total_cost
282337
# Add the appropriate amount of the base currency to the base currency wallet.
@@ -305,6 +360,7 @@ def UpdateWallet(self,action,asset,amount,price,fee_rate=0):
305360
# Remove from allet
306361
if self.Wallet['Wallet'][base]==0.0:
307362
self.Wallet['Wallet'].pop(base,None)
363+
JRRsupport.AppendFile(self.history,json.dumps(order)+'\n')
308364
return order
309365
else:
310366
# Not enough balance, account liquidated.
@@ -351,6 +407,7 @@ def UpdateWallet(self,action,asset,amount,price,fee_rate=0):
351407
# Remove from allet
352408
if self.Wallet['Wallet'][base]==0.0:
353409
self.Wallet['Wallet'].pop(base,None)
410+
JRRsupport.AppendFile(self.history,json.dumps(order)+'\n')
354411
return order
355412
else:
356413
# Not enough balance, but account is not liquidated. Need to cross analyze this on shorting.
@@ -373,11 +430,9 @@ def UpdateWallet(self,action,asset,amount,price,fee_rate=0):
373430

374431
# CRITICAL:
375432

376-
# When subtracting amounts for the wallet, the positional tracking system MUST substract from the OLDEST
377-
# (first in/first out) position in the list at the CURRENT (ticker) market value. Extensive research in
378-
# this shows that FIFO is THE account standard practiced globally.
379-
380-
# Cryprocurreny selling never selld by ID, only AMOUNT
433+
# For position fliping
434+
# if b>0, a<0: sell base, buy amount
435+
# if b<0, a>0: buy bbase, sell amount
381436

382437
def PlaceOrder(self,**kwargs):
383438
pair=kwargs.get('pair')
@@ -418,10 +473,19 @@ def PlaceOrder(self,**kwargs):
418473
if ro==True and action=='sell':
419474
amount=self.Wallet['Wallet'][base]
420475

421-
result=self.UpdateWallet(action,pair,amount,price,Fee)
476+
# Handle long/short flipping
477+
478+
result=None
479+
if amount>0 and self.Wallet['Wallet'][base]>=0 \
480+
or amount<0 and self.Wallet['Wallet'][base]<=0:
481+
result=self.UpdateWallet(action,pair,amount,price,Fee)
482+
elif amount<0 and self.Wallet['Wallet'][base]>0:
483+
result=self.LiquidateWallet(pair,Fee)
484+
result=self.UpdateWallet('buy',pair,amount,price,Fee)
485+
elif amount>0 and self.Wallet['Wallet'][base]<0:
486+
result=self.LiquidateWallet(pair,Fee)
487+
result=self.UpdateWallet('buy',pair,amount,price,Fee)
422488

423-
if 'ID' in result:
424-
JRRsupport.AppendFile(self.history,json.dumps(result)+'\n')
425489
self.PutWallet()
426490
if 'ID' in result and result['ID']!=None:
427491
# Required because most crypto exchanges don't retain order details after a certain length of time.

Extras/CodeProofs/placeOrder

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@ if relay.GetArgsLen() > 4:
2121
exchangeName=relay.GetExchange()
2222
account=relay.GetAccount()
2323
asset=relay.GetAsset()
24-
side=relay.GetArgs(4)
25-
amount=relay.GetArgs(5)
24+
side=relay.GetArgs(4).lower()
25+
amount=float(relay.GetArgs(5))
2626
else:
2727
print("An exchange, (sub)account, an asset, a side (buy/sell), and an amount must be provided.")
2828
sys.exit(1)
@@ -31,7 +31,14 @@ ticker=relay.GetTicker(symbol=asset)
3131
bPrice=ticker['Ask']
3232
sPrice=ticker['Bid']
3333

34-
mPrice=min(bPrice,sPrice)
34+
if side=='buy' and amount>0:
35+
mPrice=max(bPrice,sPrice)
36+
elif side=='buy' and amount<0:
37+
mPrice=min(bPrice,sPrice)
38+
elif side=='sell' and amount>0:
39+
mPrice=min(bPrice,sPrice)
40+
elif side=='sell' and amount<0:
41+
mPrice=max(bPrice,sPrice)
3542

3643
result=relay.PlaceOrder(pair=asset,orderType="market",action=side,amount=amount,price=bPrice,ReduceOnly=False,LedgerNote="Dry Run")
3744
print(result)

Extras/OliverTwist/otProfits

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,11 @@ for i in range(1,len(sys.argv)):
2727
if len(sys.argv)>2:
2828
print(sys.argv[i])
2929

30+
if 'oanda' in sys.argv[i]:
31+
perc=4
32+
else:
33+
perc=8
34+
3035
lines=JRRsupport.ReadFile(sys.argv[i]).strip().split('\n')
3136

3237
# Running Sum
@@ -61,16 +66,16 @@ for i in range(1,len(sys.argv)):
6166
sl+=1
6267

6368
for d in sorted(day.keys()):
64-
print(f"{d} {round(day[d],4):10.4f}")
69+
print(f"{d} {round(day[d],4):14.{perc}f}")
6570

6671
print()
6772

6873
# Trades/Month
6974
tpm=int(tt/len(day.keys()))
70-
atm=round(rs/tt,4)
71-
apm=round(atm*tpm,4)
75+
atm=round(rs/tt,perc)
76+
apm=round(atm*tpm,perc)
7277

73-
print(f"Total Profits/StopLosses/Trades: {round(rs,4):.4f}/{sl}/{tt}")
74-
print(f"Average/Trade: {atm:.4f}")
78+
print(f"Total Profits/StopLosses/Trades: {round(rs,perc):.{perc}f}/{sl}/{tt}")
79+
print(f"Average/Trade: {atm:.{perc}f}")
7580
print(f"Average Trades/Month: {tpm:.0f}")
76-
print(f"Average Profit/Month: {apm:.4f}")
81+
print(f"Average Profit/Month: {apm:.{perc}f}")

Extras/TV2Exchange

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
# 2021 Copyright © Robert APM Darin
66
# All rights reserved unconditionally.
77

8+
# wget "https://scanner.tradingview.com/crypto/scan"
9+
810
import sys
911
sys.path.append('/home/JackrabbitRelay2/Base/Library')
1012
import os

0 commit comments

Comments
 (0)