Skip to content

Commit

Permalink
Merge branch 'master' of github.com:darkerego/bmcli
Browse files Browse the repository at this point in the history
  • Loading branch information
darkerego committed May 29, 2020
2 parents b6dc1fd + b9dd9b2 commit c388265
Show file tree
Hide file tree
Showing 7 changed files with 176 additions and 131 deletions.
6 changes: 0 additions & 6 deletions .idea/vcs.xml

This file was deleted.

229 changes: 147 additions & 82 deletions bmcli.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,111 @@
Features include: get account balance and position, create a new order,
"""
import argparse
from time import sleep

from bmexlib.bitmex_api_lib import BitmexApiTool
from bmexlib.conf import *
from bmexlib.conf import testnet, api_key, api_secret, keys
from bmexlib.colorprint import ColorPrint


class BitmexLogic:
"""
Functions for everything the frontend does!
"""
def __init__(self, symbol='XBTUSD', require_ws=False):

self.symbol = symbol
self.require_ws = require_ws
if self.require_ws:
self.api = BitmexApiTool(symbol=self.symbol, api_key=api_key, api_secret=api_secret, test_net=testnet,
require_ws=True)
else:
self.api = BitmexApiTool(symbol=self.symbol, api_key=api_key, api_secret=api_secret, test_net=testnet,
require_ws=False)

def monitor_account(self, symbol='XBTUSD'):

while True:
try:

bal = self.api.get_balance()
pos = self.api.get_position()
pnl = self.api.get_raw()
cp.green(f'Instrument: {symbol}')
cp.green(f'Balance: {bal}')
pos_qty = pos['openingQty'] + pos['execQty']
cp.green(f'Position: {pos_qty}')
if args.verbose:
cp.cyan(f'Raw: {pnl}')
prev_realized = pnl['prevRealisedPnl']
realized = pnl['realisedPnl']
unrealized = pnl['unrealisedPnl']
cp.red(f'Unrealized PNL: {unrealized}')
cp.green(f'Realized PNL: {realized}')
cp.yellow(f'Previous PNL: {prev_realized}')
cp.blue('-------------------------------------------')
except KeyboardInterrupt:
cp.red('Exiting...')
else:
sleep(5)

def balance(self):
bal = self.api.get_balance()
if bal == 0:
cp.red('Zero balance available!')
else:
cp.green(f'Balance: {bal}')

def position(self):
pos = self.api.get_position()

if pos == 0:
cp.red(f'No position for {self.symbol}')
exit(0)
pos_qty = pos['openingQty'] + pos['execQty']
cp.green(f'Position: {pos_qty}')

def pnl(self, _symbol):
pnl = self.api.get_raw()
prev_realized = pnl['prevRealisedPnl']
realized = pnl['realisedPnl']
unrealized = pnl['unrealisedPnl']
cp.green(f'Instrument: {_symbol}: Unrealized PNL: {unrealized}, Realized PNL: {realized}, Prev_realized: '
f'{prev_realized}')

def create_order(self):
cp.green(f'Creating new order of type {args.new_order}...')
api = BitmexApiTool(symbol=self.symbol, api_key=api_key, api_secret=api_secret, test_net=testnet,
require_ws=False)
cp.cyan(api.send_order(oq=args.quantity, ot=args.new_order, price=args.price, stopPx=args.stop_px,
pegOffsetValue=args.pegoffsetvalue))

def chase_order(self):
cp.green(f'Chasing order of qty {args.chase[0]}')
self.api.limit_chase(oq=args.chase[0], max_chase=args.max_chase, failsafe=args.failsafe, double_check=False)

def trail(self):
if args.chase_ts is not None:
max_chase_ts = float(args.chase_ts[0])
else:
max_chase_ts = None
offset = float(args.trailing_stop_order[0])
cp.green(f'Initializing Trailing Stop with offset: {offset}, Order Chase: {args.cts}')
api = BitmexApiTool(symbol=args.symbol, api_key=api_key, api_secret=api_secret, test_net=testnet,
require_ws=True)
api.trailing_stop(offset=offset, ts_o_type=args.ts_type, tschase=args.cts, max_chase=max_chase_ts)

def auto_stop_poll(self):
stop_loss = args.autostop[0]
enable_ts = args.autostop[1]
trail_offset = args.autostop[2]
cp.yellow(f'AutoStop: Stop Loss {stop_loss}, Enable Trailing Stop: {enable_ts}, Trail Offset: {trail_offset}')
api = BitmexApiTool(symbol=self.symbol, api_key=api_key, api_secret=api_secret, test_net=testnet,
require_ws=True)
api.auto_stop(symbol=args.symbol, stop_loss=stop_loss, enable_trailing_stop=enable_ts,
trail_offset=trail_offset)


def parse_args():
"""
Argparse Function
Expand All @@ -25,16 +125,21 @@ def parse_args():
general_opts.add_argument('-k', '--keys', dest='use_curr_keys', default=True,
help='Use instrument dict from conf.py to determine'
'which api keys to use', action='store_true')
general_opts.add_argument('-v', '--verbose', dest='verbose', action='store_true')
rest_api.add_argument('-b', '--balance', dest='balance', action='store_true', help='Get Balance')
rest_api.add_argument('-p', '--position', dest='position', action='store_true', help='Get Position')
rest_api.add_argument('-P', '--pnl', dest='pnl', action='store', nargs=1, type=str,
help='Get Un/Realized PNL of specified symbol <--pnl XBTUSD>')
monitor_opts = parser.add_argument_group('Various tools for monitoring trading')
monitor_opts.add_argument('-m', '--monitor', dest='monitor_acct', action='store', nargs=1, help='Monitor account'
'instrument'
'activity.')
order_opts = parser.add_argument_group('Flags for creating orders.')
order_opts.add_argument('-o', '--order', dest='new_order', help='Place an order', type=str,
choices=['limit', 'market', 'post', 'stop', 'stop_limit', 'limit_if_touched'])
order_opts.add_argument('-q', '--qty', '-oq', dest='quantity', type=float, help='Quantity for orders placed. '
'Use negative value to open a short '
'position.')
'Use negative value to open a '
'short position.')
order_opts.add_argument('--price', '-op', dest='price', type=float, default=None,
help='Price for limit or post orders (if required.')
order_opts.add_argument('--stop_px', dest='stop_px', type=float, default=None, help='Stop price for stop orders.')
Expand Down Expand Up @@ -62,47 +167,34 @@ def parse_args():
stop_opts.add_argument('-C', '--chase_ts', dest='chase_ts', action='store',
help='Use limit order chasing with trailing stops. Specify max chase like <-C 3.0>',
nargs=1, type=float)

scalp_opts = parser.add_argument_group('Options for Experimental Scalping')
scalp_opts.add_argument('--scalp', action='store', nargs=1, type=float, help='Experimental scalping engine')
# scalp_opts.add_argument('-')
return parser.parse_args()


def main():
"""
Main logic here
"""
global api_key, api_secret
global api_key, api_secret, args
args = parse_args() # define args
balance = args.balance
position = args.position
new_order = args.new_order
price = args.price
stop_px = args.stop_px
pegoffsetvalue = args.pegoffsetvalue
chase = args.chase
chase_ts = args.chase_ts
failsafe = args.failsafe
max_chase = args.max_chase
trailing_stop_order = args.trailing_stop
autostop = args.autostop
symbol = args.symbol
quantity = args.quantity
use_limit_order = args.use_limit_order
get_pnl = args.pnl
use_curr_keys = args.use_curr_keys
"""if use_curr_keys:
if symbol == 'XBTUSD':

if args.use_curr_keys:
if args.symbol == 'XBTUSD':
api_key = keys[0][0]['XBTUSD']['key']
api_secret = keys[0][0]['XBTUSD']['secret']
if symbol == 'ETHUSD':
if args.symbol == 'ETHUSD':
api_key = keys[1][0]['ETHUSD']['key']
api_secret = keys[1][0]['ETHUSD']['secret']"""
if use_limit_order:
api_secret = keys[1][0]['ETHUSD']['secret']
if args.use_limit_order:
ts_type = 'limit'
else:
ts_type = 'market'

if chase_ts:
cp.red(f'Warn: Limit chasing for trailing stops is enabled with max chase {chase_ts[0]}.')
if args.chase_ts:
cp.red(f'Warn: Limit chasing for trailing stops is enabled with max chase {args.chase_ts[0]}.')
cts = True
else:
cts = False
Expand All @@ -111,60 +203,33 @@ def main():
Main functionality % logic
"""

if balance:
api = BitmexApiTool(symbol=symbol, api_key=api_key, api_secret=api_secret, test_net=testnet, require_ws=False)
bal = api.get_balance()
if bal == 0:
cp.red('Zero balance available!')
else:
cp.green(f'Balance: {bal}')

if position:
api = BitmexApiTool(symbol=symbol, api_key=api_key, api_secret=api_secret, test_net=testnet, require_ws=False)
pos = api.get_position()
if pos == 0:
cp.red(f'No position for {symbol}')
exit(0)
pos_qty = pos['openingQty'] + pos['execQty']
cp.green(f'Position: {pos_qty}')

if get_pnl:
_symbol = get_pnl[0]
api = BitmexApiTool(symbol=_symbol, api_key=api_key, api_secret=api_secret, test_net=testnet, require_ws=False)
pnl = api.get_raw()
prev_realized = pnl['prevRealisedPnl']
realized = pnl['realisedPnl']
unrealized = pnl['unrealisedPnl']
cp.green(f'Instrument: {_symbol}: Unrealized PNL: {unrealized}, Realized PNL: {realized}, Prev_realized: '
f'{prev_realized}')

if new_order:
cp.green(f'Creating new order of type {new_order}...')
api = BitmexApiTool(symbol=symbol, api_key=api_key, api_secret=api_secret, test_net=testnet, require_ws=False)
cp.cyan(api.send_order(oq=quantity, ot=args.new_order, price=price, stopPx=stop_px,
pegOffsetValue=pegoffsetvalue))

if chase:
api = BitmexApiTool(symbol=symbol, api_key=api_key, api_secret=api_secret, test_net=testnet, require_ws=True)
api.limit_chase(oq=chase[0], max_chase=max_chase, failsafe=failsafe, double_check=False)

if trailing_stop_order:
if chase_ts is not None:
max_chase_ts = float(chase_ts[0])
else:
max_chase_ts = None
offset = float(trailing_stop_order[0])
cp.green(f'Initializing Trailing Stop with offset: {offset}, Order Chase: {cts}')
api = BitmexApiTool(symbol=symbol, api_key=api_key, api_secret=api_secret, test_net=testnet, require_ws=True)
api.trailing_stop(offset=offset, ts_o_type=ts_type, tschase=cts, max_chase=max_chase_ts)

if autostop:
stop_loss = autostop[0]
enable_ts = autostop[1]
trail_offset = autostop[2]
cp.yellow(f'AutoStop: Stop Loss {stop_loss}, Enable Trailing Stop: {enable_ts}, Trail Offset: {trail_offset}')
api = BitmexApiTool(symbol=symbol, api_key=api_key, api_secret=api_secret, test_net=testnet, require_ws=True)
api.auto_stop(symbol=symbol, stop_loss=stop_loss, enable_trailing_stop=enable_ts, trail_offset=trail_offset)
if args.monitor_acct:
bmx = BitmexLogic(symbol=symbol, require_ws=False)
bmx.monitor_account(symbol)
if args.balance:
bmx = BitmexLogic(symbol=symbol, require_ws=False)
bmx.balance()
if args.position:
bmx = BitmexLogic(symbol=symbol, require_ws=False)
bmx.position()
if args.pnl:
bmx = BitmexLogic(symbol=symbol, require_ws=False)
_symbol = args.get_pnl[0]
bmx.pnl(_symbol)
if args.new_order:
bmx = BitmexLogic(symbol=symbol, require_ws=False)
bmx.create_order()
if args.chase:
bmx = BitmexLogic(symbol=symbol, require_ws=True)
bmx.chase_order()
if args.trailing_stop:
bmx = BitmexLogic(symbol=symbol, require_ws=True)
bmx.trail()
if args.autostop:
bmx = BitmexLogic(symbol=symbol, require_ws=True)
bmx.auto_stop_poll()
#if scalp:
# bmx = BitmexLogic(symbol=symbol, require_ws=True)


if __name__ == '__main__':
Expand Down
27 changes: 20 additions & 7 deletions bmexlib/bitmex_api_lib.py
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,12 @@ def get_quote(self):
self.logger.error('error in quote')
self.logger.error(ex)

def get_pnl(self):
pnl = self.get_raw()
realized = pnl['realisedPnl']
unrealized = pnl['unrealisedPnl']
return realized, unrealized

def send_order(self, oq, ot, price=None, stopPx=0.0, pegOffsetValue=0, text='bmx_api_tool'):
if price is None:
if self.ws:
Expand Down Expand Up @@ -420,31 +426,38 @@ def auto_stop(self, symbol='XBTUSD', stop_loss=0.01, enable_trailing_stop=0.01,

open_position = True
ts = timestamp()
(r, u) = self.get_pnl()
r = float(r) * 0.00000001
u = float(u) * 0.00000001
bal = float(self.get_balance()) * 0.00000001
entry_price = self.get_position()['avgEntryPrice']
last_price = self.ws.get_ticker()['last']
if last_price > high:
high = last_price


self.logger.info(Fore.RED + '[ ' + Style.RESET_ALL +
f'Autostop Running: Params: {stop_loss}|{enable_trailing_stop}|{trail_offset} '
f'High: {high}, Diff: {diff}'
+ Fore.RED + ' ]' + Style.RESET_ALL)

self.logger.info(f'[ Params: {stop_loss}|{enable_trailing_stop}|{trail_offset}] | '
+ f'[ High: {high}|Diff: {diff} ]')
self.logger.info(Fore.RED + f'[ Unrealized PNL: {u}' + Style.RESET_ALL + ' | ' + Fore.GREEN +
f'Realized PNL: {r} ' + Style.RESET_ALL + ' | ' + Fore.BLUE + f'Balance: {bal}'
+ Fore.RED + ' ]')
self.logger.info(
f'Time: {ts}, Position: {posQty}, Entry Price: {entry_price}, Current Price: {last_price}')
f'{ts}, [ Position: {posQty} | Entry Price: {entry_price} ]')
if posQty > 0: # long
stop_loss_price = entry_price - (entry_price * (1 * stop_loss))
trailing_stop_price = entry_price + (entry_price * (1 * enable_trailing_stop))
diff = float(trailing_stop_price) - float(last_price)
else: # elif posQty < 0: # short
stop_loss_price = entry_price + (entry_price * (1 * stop_loss))
trailing_stop_price = entry_price - (entry_price * (1 * enable_trailing_stop))
self.logger.info(f'Stop Loss: {stop_loss_price}, Trailing Stop: {trailing_stop_price}')
diff = float(last_price) - float(trailing_stop_price)
self.logger.info(f'[ Stop Loss: {stop_loss_price} | Current Price: {last_price} | Trailing Stop: {trailing_stop_price} ]')

open_orders = self.rest_open_order()
# stop loss
has_stop = False
for order in open_orders:
print(order)
if order['ordType'] == 'Stop' and order['symbol'] == symbol:
oid = order['orderID']
if float(order['orderQty']) == float(posQty) or float(order['orderQty']) == (float(posQty * -1)):
Expand Down
2 changes: 1 addition & 1 deletion bmexlib/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@


rwc = ReadWriteConfig()
config = rwc.read_config('config.json')
config = rwc.read_config('bmexlib/config.json') # <-- ADD YOUR API KEYS TO THIS FILE
keys = config['config'][0]['keys']

api_key = keys[0][0]['XBTUSD']['key']
Expand Down
1 change: 0 additions & 1 deletion bmexlib/config.example.json

This file was deleted.

9 changes: 8 additions & 1 deletion bmexlib/config_tool.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,11 @@ def test_my_config(self, jdata={}, fnmame='config.json'):
except Exception as err:
print('Error with your json: ', err)
else:
print('Test succeeded!')
print('Test succeeded!')


def test():

c = ReadWriteConfig()
ret = c.read_config()
c.pp_json(ret)
Loading

0 comments on commit c388265

Please sign in to comment.