@@ -238,8 +238,63 @@ def GetOpenOrders(self,**kwargs):
238
238
def GetOpenTrades (self ,** kwargs ):
239
239
pass
240
240
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
+
241
293
# Manage the wallet. This is where the dirty side of Mimic takes place.
242
294
295
+ # if b>0, a>0: b+=a, q-=a
296
+ # if b<0, a<0: b-=a, q-=abs(a)
297
+
243
298
def UpdateWallet (self ,action ,asset ,amount ,price ,fee_rate = 0 ):
244
299
# if the account has already been disabled (liquidated), then don't waste time here
245
300
if self .Wallet ['Enabled' ]== 'N' :
@@ -254,17 +309,17 @@ def UpdateWallet(self,action,asset,amount,price,fee_rate=0):
254
309
if '-' in quote :
255
310
quote = quote .split ('-' )[0 ]
256
311
257
- # Time to F* with the trader. Simulate dust.
312
+ # Time to F* with the trader. Simulate dust/not a full fill .
258
313
# It is very rare that an order is filled exactly as requested.
259
314
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
262
317
if amount < 0 : # short
263
318
actualAmount = amount + dust
264
319
else : # long
265
320
actualAmount = amount - dust
266
321
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.
268
323
269
324
ticker = self .Broker .GetTicker (symbol = asset )
270
325
if actualAmount < 0 :
@@ -276,7 +331,7 @@ def UpdateWallet(self,action,asset,amount,price,fee_rate=0):
276
331
# Calculate the total cost for buying the asset including fees
277
332
total_cost = abs (actualAmount ) * actualPrice * (1 + fee_rate )
278
333
# 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 :
280
335
# Deduct the total cost including fees from the quote currency balance
281
336
self .Wallet ['Wallet' ][quote ]-= total_cost
282
337
# 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):
305
360
# Remove from allet
306
361
if self .Wallet ['Wallet' ][base ]== 0.0 :
307
362
self .Wallet ['Wallet' ].pop (base ,None )
363
+ JRRsupport .AppendFile (self .history ,json .dumps (order )+ '\n ' )
308
364
return order
309
365
else :
310
366
# Not enough balance, account liquidated.
@@ -351,6 +407,7 @@ def UpdateWallet(self,action,asset,amount,price,fee_rate=0):
351
407
# Remove from allet
352
408
if self .Wallet ['Wallet' ][base ]== 0.0 :
353
409
self .Wallet ['Wallet' ].pop (base ,None )
410
+ JRRsupport .AppendFile (self .history ,json .dumps (order )+ '\n ' )
354
411
return order
355
412
else :
356
413
# 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):
373
430
374
431
# CRITICAL:
375
432
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
381
436
382
437
def PlaceOrder (self ,** kwargs ):
383
438
pair = kwargs .get ('pair' )
@@ -418,10 +473,19 @@ def PlaceOrder(self,**kwargs):
418
473
if ro == True and action == 'sell' :
419
474
amount = self .Wallet ['Wallet' ][base ]
420
475
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 )
422
488
423
- if 'ID' in result :
424
- JRRsupport .AppendFile (self .history ,json .dumps (result )+ '\n ' )
425
489
self .PutWallet ()
426
490
if 'ID' in result and result ['ID' ]!= None :
427
491
# Required because most crypto exchanges don't retain order details after a certain length of time.
0 commit comments