Skip to content

Commit

Permalink
**MAJOR UPDATE**: Many bug fixes
Browse files Browse the repository at this point in the history
Multiprocessing functionality completely rewritten. No more memory leaks, dead locks, or VPS crashes.

Conditional order framework stable and working.

Orphan functionality improved.

Overall performance improvements are quite significant.

Version update.

**UpdatePlaceOrder needs to be ran for all exchanges you use. A full reboot is required.**

Changes to be committed:
	modified:   Base/CCXT-PlaceOrder.future
	modified:   Base/CCXT-PlaceOrder.margin
	modified:   Base/CCXT-PlaceOrder.spot
	modified:   Base/CCXT-PlaceOrder.swap
	modified:   Base/Conditional.ccxt
	modified:   Base/Conditional.oanda
	modified:   Base/JackrabbitLocker
	modified:   Base/JackrabbitOliverTwist
	modified:   Base/JackrabbitRelay
	modified:   Base/Library/JRRccxt.py
	modified:   Base/Library/JRRoanda.py
	modified:   Base/Library/JRRsupport.py
	modified:   Base/Library/JackrabbitRelay.py
	modified:   Base/OANDA-PlaceOrder
	modified:   Base/Orphan.ccxt
	modified:   Base/Orphan.oanda
	new file:   Extras/CodeProofs/BuyEveryMinute
	new file:   Extras/CodeProofs/ForkTest
	modified:   Extras/ListMarkets
	modified:   Extras/otcWatch
  • Loading branch information
rapmd73 committed Jul 3, 2023
1 parent f23f4ed commit 5f3e19e
Show file tree
Hide file tree
Showing 20 changed files with 645 additions and 371 deletions.
7 changes: 7 additions & 0 deletions Base/CCXT-PlaceOrder.future
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,13 @@ def main():

relay.JRLog.Write('PlaceOrder FUTURE '+relay.Version)

# Check for OneShot situation

if ("Conditional" in relay.Active or "Conditional" in relay.Order) \
and ("ConditionalOneShot" in relay.Active or "ConditionalOneShot" in relay.Order):
if relay.OliverTwistOneShot(relay.Order)==True:
relay.JRLog.Error("Conditional OneShot", f"{relay.Order['Exchange']}/{relay.Order['Account']}/{relay.Order['Asset']} already being managed by OliverTwist ")

# Now lets get down to business. The processed order is in:
# relay.Order

Expand Down
7 changes: 7 additions & 0 deletions Base/CCXT-PlaceOrder.margin
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,13 @@ def main():

relay.JRLog.Write('PlaceOrder MARGIN '+relay.Version)

# Check for OneShot situation

if ("Conditional" in relay.Active or "Conditional" in relay.Order) \
and ("ConditionalOneShot" in relay.Active or "ConditionalOneShot" in relay.Order):
if relay.OliverTwistOneShot(relay.Order)==True:
relay.JRLog.Error("Conditional OneShot", f"{relay.Order['Exchange']}/{relay.Order['Account']}/{relay.Order['Asset']} already being managed by OliverTwist ")

# Now lets get down to business. The processed order is in:
# relay.Order

Expand Down
7 changes: 7 additions & 0 deletions Base/CCXT-PlaceOrder.spot
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,13 @@ def main():
if ("Conditional" in relay.Active or "Conditional" in relay.Order) and relay.Order['Action']!='buy':
relay.JRLog.Error("Conditional", f"{relay.Order['Action']}: ignored")

# Check for OneShot situation

if ("Conditional" in relay.Active or "Conditional" in relay.Order) \
and ("ConditionalOneShot" in relay.Active or "ConditionalOneShot" in relay.Order):
if relay.OliverTwistOneShot(relay.Order)==True:
relay.JRLog.Error("Conditional OneShot", f"{relay.Order['Exchange']}/{relay.Order['Account']}/{relay.Order['Asset']} already being managed by OliverTwist ")

# Now lets get down to business. The processed order is in:
# relay.Order

Expand Down
7 changes: 7 additions & 0 deletions Base/CCXT-PlaceOrder.swap
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,13 @@ def main():

relay.JRLog.Write('PlaceOrder SWAP '+relay.Version)

# Check for OneShot situation

if ("Conditional" in relay.Active or "Conditional" in relay.Order) \
and ("ConditionalOneShot" in relay.Active or "ConditionalOneShot" in relay.Order):
if relay.OliverTwistOneShot(relay.Order)==True:
relay.JRLog.Error("Conditional OneShot", f"{relay.Order['Exchange']}/{relay.Order['Account']}/{relay.Order['Asset']} already being managed by OliverTwist ")

# Now lets get down to business. The processed order is in:
# relay.Order

Expand Down
156 changes: 96 additions & 60 deletions Base/Conditional.ccxt
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,35 @@ import time
import JRRsupport
import JackrabbitRelay as JRR

# Timeout before Locker auto-deletes this order result

OliverTwistTimeout=(15*60)

# Write the result to Locker memory so parent knows we are finished.

def FinishOrphan(Key,lID,mID,State):
# Get the lock read and set up the memory key. Locker doesn't care and which class this order belongs to. OliverTwist will
# match the ID to the right class list, orphan or conditional.

OliverTwistLock=JRRsupport.Locker("OliverTwist",ID=lID)
Memory=JRRsupport.Locker(Key,ID=mID)

OliverTwistLock.Lock()

State=State.lower()

if State!='delete':
# Return this order to a waiting state
Memory.Put(OliverTwistTimeout*100,"Waiting")
elif State=='delete':
# This order has been processed and needs to be removed from the system.
Memory.Put(OliverTwistTimeout*100,"Delete")

OliverTwistLock.Unlock()

# We're done. This child has completed its task
sys.exit(0)

# Get the order ID. If there isn't an ID, the order FAILED.

def GetOrderID(res):
Expand Down Expand Up @@ -78,7 +107,7 @@ def main():
data=sys.stdin.read().strip()
Orphan=json.loads(data)

# Use Relay to process and validate the order
# Use Relay to process and validate the order, must be a string
if type(Orphan['Order']) is dict:
order=json.dumps(Orphan['Order'])
else:
Expand All @@ -92,6 +121,8 @@ def main():
# Handle OANDa's weird order id sequencing
id=Orphan['ID']
saction=relay.Order['SellAction'].lower()
if type(Orphan['Response']) is str:
Orphan['Response']=json.loads(Orphan['Response'])
oDetail=Orphan['Response']['Details']

# Manage average and close extire position
Expand All @@ -102,26 +133,6 @@ def main():
price=float(oDetail['price'])
amount=float(oDetail['amount'])

# Check to see if we have enough balance, if not then delete this order. Deal with futures as well.

base=relay.Markets[relay.Order['Asset']]['base'].upper()
if relay.Order['Market']=='spot':
bal=relay.GetBalance(Base=base)
else:
bal=relay.GetPositions(symbols=[relay.Order['Asset']])
if amount>bal:
relay.JRLog.Write(f"{id}: Amount {amount:.8f} > Balance {bal:.8f} {base}, purge",stdOut=False)
rData={}
rData['Key']=Orphan['Key']
rData['lID']=Orphan['lID']
rData['mID']=Orphan['mID']
rData['Class']=Orphan['Class']
rData['Status']='Delete'
print(json.dumps(rData))
# Flush and exit
sys.stdout.flush()
sys.exit(0)

# Process the position

# We need to check TakeProfit and StopLoss. If one of them is hit, we need to build and order and backfeed it in
Expand All @@ -132,6 +143,63 @@ def main():
# Get Ticker
ticker=relay.GetTicker(symbol=relay.Order['Asset'])

# Check to see if we have enough balance, if not then delete this order. Deal with futures as well.

base=relay.Markets[relay.Order['Asset']]['base'].upper()
if relay.Order['Market']=='spot':
bal=relay.GetBalance(Base=base)
else:
bal=relay.GetPositions(symbols=[relay.Order['Asset']])

# if ticker is below price and spread, purge and re-purchase

if amount>bal:
if "ConditionalRepurchase" in relay.Active:
relay.JRLog.Write(f"Original: {json.dumps(relay.Order)}",stdOut=False)

# figure out direction and build replacement order
makeNewOrder=False
if dir=='long':
makeNewOrder=ticker['Bid']<(price-ticker['Spread'])
else:
makeNewOrder=ticker['Ask']>(price+ticker['Spread'])

if makeNewOrder==True:
# Copy original order
newOrder=relay.Order
newOrder['OliverTwist']=f'Repurchase @/<{price}'
"""
newOrder['Exchange']=relay.Order['Exchange']
newOrder['Account']=relay.Order['Account']
newOrder['Market']=relay.Order['Market']
newOrder['Asset']=relay.Order['Asset']
newOrder['Action']=relay.Order['SellAction']
newOrder['Price']=str(strikePrice)
newOrder['Base']=str(amount)
"""
if 'OrderType' in relay.Order:
newOrder['OrderType']=relay.Order['OrderType']
else:
newOrder['OrderType']='market'
relay.JRLog.Write(f"New: {json.dumps(newOrder)}",stdOut=False)
newOrder['Identity']=relay.Identity['Identity']

# Feed the new order to Relay
result=relay.SendWebhook(newOrder)
oid=GetOrderID(result)
if oid!=None:
# Repurchase was successful, remove this order
FinishOrphan(Orphan['Key'],Orphan['lID'],Orphan['mID'],'Delete')
else:
# Something went wrong, leave it and try again later
FinishOrphan(Orphan['Key'],Orphan['lID'],Orphan['mID'],Orphan['Status'])
else:
# Not time to make a new purchase, leave it
FinishOrphan(Orphan['Key'],Orphan['lID'],Orphan['mID'],'Delete')
else:
relay.JRLog.Write(f"{id}: Amount {amount:.8f} > Balance {bal:.8f} {base}, purge",stdOut=False)
FinishOrphan(Orphan['Key'],Orphan['lID'],Orphan['mID'],'Delete')

# Fsilsafe, in the WORST way possible. Do NOT leave a take profit out of the order. At this stage, the whole thing is
# an absolute nightmare to fix. The is a very brutal way of dealing with poor user choices.
if 'TakeProfit' not in relay.Order:
Expand Down Expand Up @@ -194,7 +262,7 @@ def main():

# relay.JRLog.Write(f"{id}: {json.dumps(newOrder)}",stdOut=False)

newOrder['Identity']=relay.Identity['Identity']
newOrder['Identity']=relay.Active['Identity']

# Feed the new order to Relay
result=relay.SendWebhook(newOrder)
Expand All @@ -203,53 +271,21 @@ def main():
resp=relay.GetOrderDetails(id=oid,symbol=relay.Order['Asset'])
# Order must be closed as it succedded
newOrder['ID']=oid
rData={}
rData['Key']=Orphan['Key']
rData['lID']=Orphan['lID']
rData['mID']=Orphan['mID']
rData['Class']=Orphan['Class']
rData['Status']='Delete'
print(json.dumps(rData))
relay.WriteLedger(Order=newOrder,Response=resp)
FinishOrphan(Orphan['Key'],Orphan['lID'],Orphan['mID'],'Delete')
else:
# Give OliverTwist a response
relay.JRLog.Write(f"{id}: Order failed",stdOut=False)
rData={}
rData['Key']=Orphan['Key']
rData['lID']=Orphan['lID']
rData['mID']=Orphan['mID']
rData['Class']=Orphan['Class']
rData['Status']=Orphan['Status']
print(json.dumps(rData))
# Flush and exit
sys.stdout.flush()
sys.exit(0)
FinishOrphan(Orphan['Key'],Orphan['lID'],Orphan['mID'],Orphan['Status'])
else:
# Strike did not happen
rData={}
rData['Key']=Orphan['Key']
rData['lID']=Orphan['lID']
rData['mID']=Orphan['mID']
rData['Class']=Orphan['Class']
rData['Status']=Orphan['Status']
print(json.dumps(rData))
#relay.JRLog.Write(f"{id}: {cur['state']}",stdOut=False)
# Flush and exit
sys.stdout.flush()
sys.exit(0)
FinishOrphan(Orphan['Key'],Orphan['lID'],Orphan['mID'],Orphan['Status'])
except Exception as e:
# Something went wrong
rData={}
rData['Key']=Orphan['Key']
rData['lID']=Orphan['lID']
rData['mID']=Orphan['mID']
rData['Class']=Orphan['Class']
rData['Status']=Orphan['Status']
print(json.dumps(rData))
relay.JRLog.Write(f"{Orphan['Key']}: Code Error - {str(e)}",stdOut=False)
# Flush and exit
sys.stdout.flush()
sys.exit(0)
if 'Diagnostics' in relay.Active:
relay.JRLog.Write(f"{Orphan['Key']}: {data}",stdOut=False)
FinishOrphan(Orphan['Key'],Orphan['lID'],Orphan['mID'],Orphan['Status'])

if __name__ == '__main__':
main()
Expand Down
85 changes: 35 additions & 50 deletions Base/Conditional.oanda
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,35 @@ import time
import JRRsupport
import JackrabbitRelay as JRR

# Timeout before Locker auto-deletes this order result

OliverTwistTimeout=(15*60)

# Write the result to Locker memory so parent knows we are finished.

def FinishOrphan(Key,lID,mID,State):
# Get the lock read and set up the memory key. Locker doesn't care and which class this order belongs to. OliverTwist will
# match the ID to the right class list, orphan or conditional.

OliverTwistLock=JRRsupport.Locker("OliverTwist",ID=lID)
Memory=JRRsupport.Locker(Key,ID=mID)

OliverTwistLock.Lock()

State=State.lower()

if State!='delete':
# Return this order to a waiting state
Memory.Put(OliverTwistTimeout*100,"Waiting")
elif State=='delete':
# This order has been processed and needs to be removed from the system.
Memory.Put(OliverTwistTimeout*100,"Delete")

OliverTwistLock.Unlock()

# We're done. This child has completed its task
sys.exit(0)

# Get the order ID. If there isn't an ID, the order FAILED.

def GetOrderID(res):
Expand Down Expand Up @@ -200,7 +229,7 @@ def main():

# relay.JRLog.Write(f"{id}: {json.dumps(newOrder)}",stdOut=False)

newOrder['Identity']=relay.Identity['Identity']
newOrder['Identity']=relay.Active['Identity']

# Feed the new order to Relay
result=relay.SendWebhook(newOrder)
Expand All @@ -209,66 +238,22 @@ def main():
resp=relay.GetOrderDetails(OrderID=oid)
# Order must be closed as it succedded
newOrder['ID']=oid
rData={}
rData['Key']=Orphan['Key']
rData['lID']=Orphan['lID']
rData['mID']=Orphan['mID']
rData['Class']=Orphan['Class']
rData['Status']='Delete'
print(json.dumps(rData))
relay.WriteLedger(Order=newOrder,Response=resp)
FinishOrphan(Orphan['Key'],Orphan['lID'],Orphan['mID'],'Delete')
else:
# Give OliverTwist a response
relay.JRLog.Write(f"{id}: Order failed",stdOut=False)
rData={}
rData['Key']=Orphan['Key']
rData['lID']=Orphan['lID']
rData['mID']=Orphan['mID']
rData['Class']=Orphan['Class']
rData['Status']=Orphan['Status']
print(json.dumps(rData))
#relay.JRLog.Write(f"{id}: {cur['state']}",stdOut=False)
# Flush and exit
sys.stdout.flush()
sys.exit(0)
FinishOrphan(Orphan['Key'],Orphan['lID'],Orphan['mID'],cur['state'])
else:
# Strike did not happen
rData={}
rData['Key']=Orphan['Key']
rData['lID']=Orphan['lID']
rData['mID']=Orphan['mID']
rData['Class']=Orphan['Class']
rData['Status']=Orphan['Status']
print(json.dumps(rData))
#relay.JRLog.Write(f"{id}: {cur['state']}",stdOut=False)
# Flush and exit
sys.stdout.flush()
sys.exit(0)
FinishOrphan(Orphan['Key'],Orphan['lID'],Orphan['mID'],cur['state'])

# Fall through. No order matching the ID.
rData={}
rData['Key']=Orphan['Key']
rData['lID']=Orphan['lID']
rData['mID']=Orphan['mID']
rData['Class']=Orphan['Class']
rData['Status']="Delete"
print(json.dumps(rData))
sys.stdout.flush()
sys.exit(0)
#relay.JRLog.Write(f"{id}: {cur['state']}",stdOut=False)
FinishOrphan(Orphan['Key'],Orphan['lID'],Orphan['mID'],'Delete')
except Exception as e:
# Something broke or went horrible wrong
rData={}
rData['Key']=Orphan['Key']
rData['lID']=Orphan['lID']
rData['mID']=Orphan['mID']
rData['Class']=Orphan['Class']
rData['Status']=Orphan['Status']
print(json.dumps(rData))
relay.JRLog.Write(f"{Orphan['Key']}: Code Error - {str(e)}",stdOut=False)
# Flush and exit
sys.stdout.flush()
sys.exit(0)
FinishOrphan(Orphan['Key'],Orphan['lID'],Orphan['mID'],cur['state'])

if __name__ == '__main__':
main()
2 changes: 1 addition & 1 deletion Base/JackrabbitLocker
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ import json

import JRRsupport

Version="0.0.0.1.340"
Version="0.0.0.1.370"
BaseDirectory='/home/JackrabbitRelay2/Base'
ConfigDirectory='/home/JackrabbitRelay2/Config'
LogDirectory="/home/JackrabbitRelay2/Logs"
Expand Down
Loading

0 comments on commit 5f3e19e

Please sign in to comment.