Skip to content

Commit

Permalink
Bug fixes, code clean up.
Browse files Browse the repository at this point in the history
Added way to place trade com command line. Its more of a demonstration for properly working with the framework,
but still reasonably functional.

Version update.

Changes to be committed:
	modified:   Base/JackrabbitLocker
	modified:   Base/JackrabbitOliverTwist
	modified:   Base/JackrabbitRelay
	modified:   Base/Library/JRRmimic.py
	modified:   Base/Library/JackrabbitProxy.py
	modified:   Base/Library/JackrabbitRelay.py
	new file:   Extras/PlaceManualOrder
  • Loading branch information
rapmd73 committed Apr 12, 2024
1 parent c7c09b7 commit 930d324
Show file tree
Hide file tree
Showing 7 changed files with 223 additions and 6 deletions.
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.800"
Version="0.0.0.1.820"
BaseDirectory='/home/JackrabbitRelay2/Base'
ConfigDirectory='/home/JackrabbitRelay2/Config'
LogDirectory="/home/JackrabbitRelay2/Logs"
Expand Down
2 changes: 1 addition & 1 deletion Base/JackrabbitOliverTwist
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ import subprocess
import JRRsupport
import JackrabbitRelay as JRR

Version="0.0.0.1.800"
Version="0.0.0.1.820"
BaseDirectory='/home/JackrabbitRelay2/Base'
DataDirectory='/home/JackrabbitRelay2/Data'
ConfigDirectory='/home/JackrabbitRelay2/Config'
Expand Down
2 changes: 1 addition & 1 deletion Base/JackrabbitRelay
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import json

import JRRsupport

Version="0.0.0.1.800"
Version="0.0.0.1.820"
BaseDirectory='/home/JackrabbitRelay2/Base'
ConfigDirectory='/home/JackrabbitRelay2/Config'
LogDirectory="/home/JackrabbitRelay2/Logs"
Expand Down
2 changes: 1 addition & 1 deletion Base/Library/JRRmimic.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ class mimic:
# placed in init and released at exit.

def __init__(self,Exchange,Config,Active,DataDirectory=None):
self.Version="0.0.0.1.800"
self.Version="0.0.0.1.820"

self.StableCoinUSD=['USDT','USDC','BUSD','UST','DAI','FRAX','TUSD', \
'USDP','LUSD','USDN','HUSD','FEI','TRIBE','RSR','OUSD','XSGD', \
Expand Down
2 changes: 1 addition & 1 deletion Base/Library/JackrabbitProxy.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@
class JackrabbitProxy:
def __init__(self,framework=None,payload=None,exchange=None,account=None,asset=None,Usage=None):
# All the default locations
self.Version="0.0.0.1.800"
self.Version="0.0.0.1.820"
self.BaseDirectory='/home/JackrabbitRelay2/Base'
self.ConfigDirectory='/home/JackrabbitRelay2/Config'
self.DataDirectory="/home/JackrabbitRelay2/Data"
Expand Down
2 changes: 1 addition & 1 deletion Base/Library/JackrabbitRelay.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ def Success(self,f,s):
class JackrabbitRelay:
def __init__(self,framework=None,payload=None,exchange=None,account=None,asset=None,secondary=None,NoIdentityVerification=False,Usage=None):
# All the default locations
self.Version="0.0.0.1.800"
self.Version="0.0.0.1.820"
self.NOhtml='<html><title>NO!</title><body style="background-color:#ffff00;display:flex;weight:100vw;height:100vh;align-items:center;justify-content:center"><h1 style="color:#ff0000;font-weight:1000;font-size:10rem">NO!</h1></body></html>'
self.BaseDirectory='/home/JackrabbitRelay2/Base'
self.ConfigDirectory='/home/JackrabbitRelay2/Config'
Expand Down
217 changes: 217 additions & 0 deletions Extras/PlaceManualOrder
Original file line number Diff line number Diff line change
@@ -0,0 +1,217 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
# Jackrabbit Relay
# 2021 Copyright © Robert APM Darin
# All rights reserved unconditionally.

# This program manually places trades through Jackrabbit Relay.

# This is more of a how-to for the framework, but its is useful just to be able to ram an order through quickly.

# This program can be easily modified with trading logic to be an automated strategy. The basic framework remains
# the same.

import sys
sys.path.append('/home/GitHub/JackrabbitRelay/Base/Library')
import os
import json

import JRRsupport
import JackrabbitRelay as JRR

# How to use this program.

# This is a basic boilerplate approach to simplify error checking, both during the Relay initialization and
# argument verification from the command line.

def Usage(args,arglen):
if arglen==0:
if sys.argv[0]!='':
cmd=sys.argv[0]
else:
cmd='./PlaceManualOrder'
else:
cmd=args[0]

print('An exchange, account, asset, action are required.')
print('If the last argument on the command line is RO, then a reduce only order is issued.')
print()
print(f' {cmd} kraken MAIN BTC/USD buy 0.001 spot')
print(f' {cmd} binance MAIN ADA/USDT buy 10 spot RO')
print(f' {cmd} binance MAIN ADA/USDT close spot')
print(f' {cmd} mimic krakenPublic LTC/USDT sell 10 spot diag')
print(f' {cmd} oanda RedRobbin EUR/USD buy 5')
sys.exit(1)

###
### Main code base. Place order on exchange
###

def main():

# Set this to True for additional diagnostics.

Diagnostics=False

# Relay verifies the exchange and account. Certain things are automatically loaded if the very first parameters
# are present. This is mostly for convience.

relay=JRR.JackrabbitRelay(Usage=Usage)

# if we reach this point in the program, Relay's minimum requirements of an exchange and account have been
# provided OR it has pulled in an order from standard input (STDIN). The command line has been consumed and
# copied to internal Relay variables.

if relay.GetArgsLen()>4:
# You can assign variables for convience, or use the Relay functions.
exchange=relay.GetExchange()
account=relay.GetAccount()
asset=relay.GetAsset()
action=relay.GetArgs(4).lower()
else:
Usage(relay.args,relay.argslen)

# Activate diagnostics
if 'diag' in str(relay.args).lower():
Diagnostics=True

if asset not in relay.Markets:
print(f"{asset} is not listed in the exchange's inventory, please check spelling or use ListMarkets to verify its presence.")
print()
Usage(relay.args,relay.argslen)

amount=0
if action!='close':
if relay.GetArgsLen()>5:
amount=float(relay.GetArgs(5)) # Base currency value
else:
print("This action requires a base amount")
print()
Usage(relay.args,relay.argslen)

# Verify the action is one of the required abilities.
if action!='long' and action!='short' and action!='buy' and action!='sell' and action!='close':
Usage()

if action=='long':
action='buy'
elif action=='short':
action='sell'

# Check for CCXT or MIMIC. Cryptocurrency markets require a 'Market' key

# Pull the information from the market list. The disadvantage to this is this approach could pick the wrong
# type if the exchange carried mixed pairs in one list. Is is often better to specify the market manually.

# For the purposes of demonstration though, this method will work.

marketType=None
mt=None
if relay.Framework=='ccxt' or relay.Framework=='mimic':
marketType="spot"
if "type" in relay.Markets[asset]:
if "type" in relay.Markets[asset]['info']:
if relay.Markets[asset]['info']['type']==relay.Markets[asset]['type']:
marketType=relay.Markets[asset]['type'].lower()
else:
marketType=relay.Markets[asset]['info']['type'].lower()
else:
if "permissions" in relay.Markets[asset]['info']:
marketType=' '.join(relay.Markets[asset]['info']['permissions']).lower()

found=False
for i in relay.args:
if i in marketType:
found=True
mt=i

# Did we find a market type?
if found==False:
print(f"Wrong or missing market type, this asset is type {marketType}")
print()
Usage(relay.args,relay.argslen)

# Is this going to be a reduce only order?

ro=(relay.GetArgs(-1).lower()=='ro')

# Get the ticker for current price.

ticker=relay.GetTicker(symbol=asset)
bPrice=ticker['Ask']
sPrice=ticker['Bid']

# Figure out the proper price to use. Long positions always uses the highest, while short positions use the
# lowest.

if action=='buy' and amount>0:
mPrice=max(bPrice,sPrice)
elif action=='buy' and amount<0:
mPrice=min(bPrice,sPrice)
elif action=='sell' and amount>0:
mPrice=min(bPrice,sPrice)
elif action=='sell' and amount<0:
mPrice=max(bPrice,sPrice)
else:
# Close the position, Relay will sort this out at place order API call
mPrice=(bPrice+sPrice)/2

# Build the order.

# The order of the keys doesn't matter. I prefer a certain order for mental clarity and checking for mistakes.
# Because the identity is so long, I prefer it at the bottom of the order. This is mostly a diagnostics tatic, is
# I need to print the order to screen for debugging.

NewOrder={}

# Meaningless to the system, but important as it show up in the logs. This is a commenting tactic. 'Recipe' is a
# term from Jackrabbit TV, and simply carried over. It has no meaning to the system, and is for YOU only.

NewOrder['Recipe']='Manual Trade'
NewOrder['Exchange']=exchange
NewOrder['Account']=account
if mt!=None:
NewOrder['Market']=mt
NewOrder['OrderType']='Market' # place a market order
NewOrder['Asset']=asset
NewOrder['Action']=action
NewOrder['Price']=str(mPrice)
if relay.Framework=='ccxt' or relay.Framework=='mimic':
NewOrder['Base']=str(amount)
else:
NewOrder['Units']=str(amount)

# Many options is Relay have this format. Quite a few of them ignoew the value, like 'Diagnostics'. All the
# matters is that the key is present. Check the Wiki for more details of which ones exhibit this behavior.

if ro==True:
NewOrder['ReduceOnly']='Yes'

# ALL order *MUST* have an identity. This only works if the program is running on the same server as the active
# Relay installation. Otherwise, you will need to put the identity string in like any other key.

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

# Send the order to the Relay server

result=relay.SendWebhook(NewOrder)

if Diagnostics==True:
print(result)
else:
# Get the order ID
oid=relay.GetOrderID(result)
if oid!=None:
# Get and print the details of the order
print(f"Order successful: {oid}")
print()
detail=relay.GetOrderDetails(id=oid,symbol=relay.Order['Asset'])
print(detail)
else:
# Why did it fail?
failed=relay.GetFailedReason(result)
print(f"Order failed: {failed}")

if __name__ == '__main__':
main()

0 comments on commit 930d324

Please sign in to comment.