mirror of
https://github.com/aljazceru/bitfinex-api-py.git
synced 2025-12-19 06:44:22 +01:00
Merge branch 'master' into readme
This commit is contained in:
13
CHANGELOG
13
CHANGELOG
@@ -1,3 +1,16 @@
|
||||
1.1.0
|
||||
|
||||
- Adds rest.submit_funding_offer
|
||||
- Adds rest.submit_cancel_funding_offer
|
||||
- Adds rest.submit_wallet_transfer
|
||||
- Adds rest.get_wallet_deposit_address
|
||||
- Adds rest.create_wallet_deposit_address
|
||||
- Adds rest.submit_wallet_withdraw
|
||||
- Adds rest.submit_order
|
||||
- Adds rest.submit_cancel_order
|
||||
- Adds rest.submit_update_order
|
||||
- Updates websocket notification event to use Notfication model object
|
||||
|
||||
1.0.1
|
||||
|
||||
- Added ws event `status_update`
|
||||
|
||||
51
README.md
51
README.md
@@ -45,13 +45,12 @@ python3 subscribe_trades_candles.py
|
||||
```
|
||||
|
||||
# Features
|
||||
- Fast websocket connection
|
||||
- Event-based routing
|
||||
- Subscribe to trade, candles and orderbook channels
|
||||
- Authenticate with API key/secret
|
||||
- Orderbook checksum validation
|
||||
- Wbsocket support with multiplexing
|
||||
- Real-time Trade, Orderbook, Account data feeds and more
|
||||
- Authenticate with api key/secret
|
||||
- Data checksum verifications
|
||||
- Create, update and close orders
|
||||
- Track wallet updates
|
||||
- Wallet withdraws/transfers
|
||||
|
||||
# Quickstart
|
||||
|
||||
@@ -116,7 +115,7 @@ The websocket exposes a collection of events that are triggered when certain dat
|
||||
- `disconnected`: () called when a connection is ended (A reconnect attempt may follow)
|
||||
- `stopped`: () called when max amount of connection retries is met and the socket is closed
|
||||
- `authenticated` (): called when the websocket passes authentication
|
||||
- `notification` (array): incoming account notification
|
||||
- `notification` (Notification): incoming account notification
|
||||
- `error` (array): error from the websocket
|
||||
- `order_closed` (Order, Trade): when an order has been closed
|
||||
- `order_new` (Order, Trade): when an order has been created but not closed. Note: will not be called if order is executed and filled instantly
|
||||
@@ -177,7 +176,7 @@ The websocket exposes a collection of events that are triggered when certain dat
|
||||
|
||||
#### `submit_order(symbol, price, amount, market_type, hidden=False, onConfirm=None, onClose=None, *args, **kwargs)`
|
||||
|
||||
Submits an order to the Bitfinex api. When it has been verified that bitfine xhas received the order then the `onConfirm` callback will be called followed by the `order_confirmed` event. Once it has been verified that the order has completely closed due to either being filled or canceled then the `onClose` function will be called, followed by the `order_closed` event.
|
||||
Submits an order to the Bitfinex api. When it has been verified that bitfinex has received the order then the `onConfirm` callback will be called followed by the `order_confirmed` event. Once it has been verified that the order has completely closed due to either being filled or canceled then the `onClose` function will be called, followed by the `order_closed` event.
|
||||
|
||||
#### `update_order(orderId, price=None, amount=None, delta=None, price_aux_limit=None, price_trailing=None, flags=None, time_in_force=None, onConfirm=None, onClose=None)`
|
||||
|
||||
@@ -301,6 +300,42 @@ Get the public orderbook of a given symbol
|
||||
|
||||
Set the amount of collateral used to back a derivative position.
|
||||
|
||||
#### `submit_order(symbol, price, amount, market_type, hidden=False, *args, **kwargs)`
|
||||
|
||||
Submits an order to the Bitfinex api.
|
||||
|
||||
#### `update_order(orderId, price=None, amount=None, delta=None, price_aux_limit=None, price_trailing=None, flags=None, time_in_force=None)`
|
||||
|
||||
Attempts to update an order with the given values. If the order is no longer open then the update will be ignored.
|
||||
|
||||
#### `close_order(self, orderId):`
|
||||
|
||||
Close the order with the given orderId if it still open.
|
||||
|
||||
#### `submit_wallet_withdraw(wallet, method, amount, address):`
|
||||
|
||||
Withdraw funds from the given wallet to the provided address
|
||||
|
||||
#### `create_wallet_deposit_address(wallet, method):`
|
||||
|
||||
Create a new deposit address for the given wallet and currency protocol.
|
||||
|
||||
#### `get_wallet_deposit_address(wallet, method):`
|
||||
|
||||
Get the deposit address for the given wallet and currency protocol
|
||||
|
||||
#### `submit_wallet_transfer(from_wallet, to_wallet, from_currency, to_currency, amount):`
|
||||
|
||||
Transfer funds from one internal wallet to another
|
||||
|
||||
#### `submit_cancel_funding_offer(fundingId):`
|
||||
|
||||
Cancel a funding offer
|
||||
|
||||
### `submit_funding_offer(self, symbol, amount, rate, period, funding_type, hidden=False):`
|
||||
|
||||
Submit a new fund offer
|
||||
|
||||
# Examples
|
||||
|
||||
For more info on how to use this library please see the example scripts in the `bfxapi/examples` directory. Here you will find usage of all interface exposed functions for both the rest and websocket.
|
||||
|
||||
35
bfxapi/examples/rest/create_funding.py
Normal file
35
bfxapi/examples/rest/create_funding.py
Normal file
@@ -0,0 +1,35 @@
|
||||
import os
|
||||
import sys
|
||||
import asyncio
|
||||
import time
|
||||
sys.path.append('../')
|
||||
|
||||
from bfxapi import Client
|
||||
|
||||
API_KEY=os.getenv("BFX_KEY")
|
||||
API_SECRET=os.getenv("BFX_SECRET")
|
||||
|
||||
bfx = Client(
|
||||
API_KEY=API_KEY,
|
||||
API_SECRET=API_SECRET,
|
||||
logLevel='DEBUG'
|
||||
)
|
||||
|
||||
async def create_funding():
|
||||
response = await bfx.rest.submit_funding_offer("fUSD", 1000, 0.012, 7)
|
||||
# response is in the form of a Notification object
|
||||
# notify_info is in the form of a FundingOffer
|
||||
print ("Offer: ", response.notify_info)
|
||||
|
||||
async def cancel_funding():
|
||||
response = await bfx.rest.submit_cancel_funding_offer(41235958)
|
||||
# response is in the form of a Notification object
|
||||
# notify_info is in the form of a FundingOffer
|
||||
print ("Offer: ", response.notify_info)
|
||||
|
||||
async def run():
|
||||
await create_funding()
|
||||
await cancel_funding()
|
||||
|
||||
t = asyncio.ensure_future(run())
|
||||
asyncio.get_event_loop().run_until_complete(t)
|
||||
43
bfxapi/examples/rest/create_order.py
Normal file
43
bfxapi/examples/rest/create_order.py
Normal file
@@ -0,0 +1,43 @@
|
||||
import os
|
||||
import sys
|
||||
import asyncio
|
||||
import time
|
||||
sys.path.append('../')
|
||||
|
||||
from bfxapi import Client
|
||||
|
||||
API_KEY=os.getenv("BFX_KEY")
|
||||
API_SECRET=os.getenv("BFX_SECRET")
|
||||
|
||||
bfx = Client(
|
||||
API_KEY=API_KEY,
|
||||
API_SECRET=API_SECRET,
|
||||
logLevel='DEBUG'
|
||||
)
|
||||
|
||||
async def create_order():
|
||||
response = await bfx.rest.submit_order("tBTCUSD", 10, 0.1)
|
||||
# response is in the form of a Notification object
|
||||
for o in response.notify_info:
|
||||
# each item is in the form of an Order object
|
||||
print ("Order: ", o)
|
||||
|
||||
async def cancel_order():
|
||||
response = await bfx.rest.submit_cancel_order(1185510865)
|
||||
# response is in the form of a Notification object
|
||||
# notify_info is in the form of an order object
|
||||
print ("Order: ", response.notify_info)
|
||||
|
||||
async def update_order():
|
||||
response = await bfx.rest.submit_update_order(1185510771, price=15, amount=0.055)
|
||||
# response is in the form of a Notification object
|
||||
# notify_info is in the form of an order object
|
||||
print ("Order: ", response.notify_info)
|
||||
|
||||
async def run():
|
||||
await create_order()
|
||||
await cancel_order()
|
||||
await update_order()
|
||||
|
||||
t = asyncio.ensure_future(run())
|
||||
asyncio.get_event_loop().run_until_complete(t)
|
||||
49
bfxapi/examples/rest/transfer_wallet.py
Normal file
49
bfxapi/examples/rest/transfer_wallet.py
Normal file
@@ -0,0 +1,49 @@
|
||||
import os
|
||||
import sys
|
||||
import asyncio
|
||||
import time
|
||||
sys.path.append('../')
|
||||
|
||||
from bfxapi import Client
|
||||
|
||||
API_KEY=os.getenv("BFX_KEY")
|
||||
API_SECRET=os.getenv("BFX_SECRET")
|
||||
|
||||
bfx = Client(
|
||||
API_KEY=API_KEY,
|
||||
API_SECRET=API_SECRET,
|
||||
logLevel='DEBUG'
|
||||
)
|
||||
|
||||
async def transfer_wallet():
|
||||
response = await bfx.rest.submit_wallet_transfer("exchange", "margin", "BTC", "BTC", 0.1)
|
||||
# response is in the form of a Notification object
|
||||
# notify_info is in the form of a Transfer object
|
||||
print ("Transfer: ", response.notify_info)
|
||||
|
||||
async def deposit_address():
|
||||
response = await bfx.rest.get_wallet_deposit_address("exchange", "bitcoin")
|
||||
# response is in the form of a Notification object
|
||||
# notify_info is in the form of a DepositAddress object
|
||||
print ("Address: ", response.notify_info)
|
||||
|
||||
async def create_new_address():
|
||||
response = await bfx.rest.create_wallet_deposit_address("exchange", "bitcoin")
|
||||
# response is in the form of a Notification object
|
||||
# notify_info is in the form of a DepositAddress object
|
||||
print ("Address: ", response.notify_info)
|
||||
|
||||
async def withdraw():
|
||||
# tetheruse = Tether (ERC20)
|
||||
response = await bfx.rest.submit_wallet_withdraw("exchange", "tetheruse", 5, "0xc5bbb852f82c24327693937d4012f496cff7eddf")
|
||||
# response is in the form of a Notification object
|
||||
# notify_info is in the form of a DepositAddress object
|
||||
print ("Address: ", response.notify_info)
|
||||
|
||||
async def run():
|
||||
await transfer_wallet()
|
||||
await deposit_address()
|
||||
await withdraw()
|
||||
|
||||
t = asyncio.ensure_future(run())
|
||||
asyncio.get_event_loop().run_until_complete(t)
|
||||
@@ -10,20 +10,18 @@ API_SECRET=os.getenv("BFX_SECRET")
|
||||
bfx = Client(
|
||||
API_KEY=API_KEY,
|
||||
API_SECRET=API_SECRET,
|
||||
logLevel='INFO'
|
||||
logLevel='DEBUG'
|
||||
)
|
||||
|
||||
@bfx.ws.on('order_closed')
|
||||
def order_cancelled(order, trade):
|
||||
def order_cancelled(order):
|
||||
print ("Order cancelled.")
|
||||
print (order)
|
||||
print (trade)
|
||||
|
||||
@bfx.ws.on('order_confirmed')
|
||||
async def trade_completed(order, trade):
|
||||
async def trade_completed(order):
|
||||
print ("Order confirmed.")
|
||||
print (order)
|
||||
print (trade)
|
||||
await bfx.ws.cancel_order(order.id)
|
||||
|
||||
@bfx.ws.on('error')
|
||||
@@ -32,7 +30,7 @@ def log_error(msg):
|
||||
|
||||
@bfx.ws.once('authenticated')
|
||||
async def submit_order(auth_message):
|
||||
# create an inital order a really low price so it stays open
|
||||
# create an initial order at a really low price so it stays open
|
||||
await bfx.ws.submit_order('tBTCUSD', 10, 1, Order.Type.EXCHANGE_LIMIT)
|
||||
|
||||
bfx.ws.run()
|
||||
|
||||
@@ -12,5 +12,9 @@ from .position import Position
|
||||
from .funding_loan import FundingLoan
|
||||
from .funding_offer import FundingOffer
|
||||
from .funding_credit import FundingCredit
|
||||
from .notification import Notification
|
||||
from .transfer import Transfer
|
||||
from .deposit_address import DepositAddress
|
||||
from .withdraw import Withdraw
|
||||
|
||||
NAME = 'models'
|
||||
|
||||
42
bfxapi/models/deposit_address.py
Normal file
42
bfxapi/models/deposit_address.py
Normal file
@@ -0,0 +1,42 @@
|
||||
"""
|
||||
Module used to describe a DepositAddress object
|
||||
"""
|
||||
|
||||
class DepositModel:
|
||||
"""
|
||||
Enum used to index the location of each value in a raw array
|
||||
"""
|
||||
METHOD = 1
|
||||
CURRENCY = 2
|
||||
ADDRESS = 4
|
||||
|
||||
class DepositAddress:
|
||||
"""
|
||||
[None, 'BITCOIN', 'BTC', None, '38zsUkv8q2aiXK9qsZVwepXjWeh3jKvvZw']
|
||||
|
||||
METHOD string Protocol used for funds transfer
|
||||
SYMBOL string Currency symbol
|
||||
ADDRESS string Deposit address for funds transfer
|
||||
"""
|
||||
|
||||
def __init__(self, method, currency, address):
|
||||
self.method = method
|
||||
self.currency = currency
|
||||
self.address = address
|
||||
|
||||
@staticmethod
|
||||
def from_raw_deposit_address(raw_add):
|
||||
"""
|
||||
Parse a raw deposit object into a DepositAddress object
|
||||
|
||||
@return DepositAddress
|
||||
"""
|
||||
method = raw_add[DepositModel.METHOD]
|
||||
currency = raw_add[DepositModel.CURRENCY]
|
||||
address = raw_add[DepositModel.ADDRESS]
|
||||
return DepositAddress(method, currency, address)
|
||||
|
||||
def __str__(self):
|
||||
''' Allow us to print the Transfer object in a pretty format '''
|
||||
text = "DepositAddress <{} method={} currency={}>"
|
||||
return text.format(self.address, self.method, self.currency)
|
||||
@@ -2,6 +2,12 @@
|
||||
Module used to describe all of the different data types
|
||||
"""
|
||||
|
||||
class FundingOfferTypes:
|
||||
"""
|
||||
Enum used to define the different funding offer types
|
||||
"""
|
||||
LIMIT = 'LIMIT'
|
||||
FRR_DELTA = 'FRRDELTAVAR'
|
||||
|
||||
class FundingOfferModel:
|
||||
"""
|
||||
@@ -41,6 +47,8 @@ class FundingOffer:
|
||||
RENEW int 0 if false, 1 if true
|
||||
"""
|
||||
|
||||
Type = FundingOfferTypes()
|
||||
|
||||
def __init__(self, fid, symbol, mts_create, mts_updated, amount, amount_orig, f_type,
|
||||
flags, status, rate, period, notify, hidden, renew):
|
||||
# pylint: disable=invalid-name
|
||||
|
||||
119
bfxapi/models/notification.py
Normal file
119
bfxapi/models/notification.py
Normal file
@@ -0,0 +1,119 @@
|
||||
"""
|
||||
Module used to describe all of the different notification data types
|
||||
"""
|
||||
|
||||
from .order import Order
|
||||
from .funding_offer import FundingOffer
|
||||
from .transfer import Transfer
|
||||
from .deposit_address import DepositAddress
|
||||
from .withdraw import Withdraw
|
||||
|
||||
class NotificationModal:
|
||||
"""
|
||||
Enum used index the different values in a raw order array
|
||||
"""
|
||||
MTS = 0
|
||||
TYPE = 1
|
||||
MESSAGE_ID = 2
|
||||
NOTIFY_INFO = 4
|
||||
CODE = 5
|
||||
STATUS = 6
|
||||
TEXT = 7
|
||||
|
||||
class NotificationError:
|
||||
"""
|
||||
Enum used to hold the error response statuses
|
||||
"""
|
||||
SUCCESS = "SUCCESS"
|
||||
ERROR = "ERROR"
|
||||
FAILURE = "FAILURE"
|
||||
|
||||
class NotificationTypes:
|
||||
"""
|
||||
Enum used to hold the different notification types
|
||||
"""
|
||||
ORDER_NEW_REQ = "on-req"
|
||||
ORDER_CANCELED_REQ = "oc-req"
|
||||
ORDER_UPDATED_REQ = "ou-req"
|
||||
FUNDING_OFFER_NEW = "fon-req"
|
||||
FUNDING_OFFER_CANCEL = "foc-req"
|
||||
ACCOUNT_TRANSFER = "acc_tf"
|
||||
ACCOUNT_DEPOSIT = "acc_dep"
|
||||
ACCOUNT_WITHDRAW_REQ = "acc_wd-req"
|
||||
# uca ?
|
||||
# pm-req ?
|
||||
|
||||
|
||||
class Notification:
|
||||
"""
|
||||
MTS int Millisecond Time Stamp of the update
|
||||
TYPE string Purpose of notification ('on-req', 'oc-req', 'uca', 'fon-req', 'foc-req')
|
||||
MESSAGE_ID int unique ID of the message
|
||||
NOTIFY_INFO array/object A message containing information regarding the notification
|
||||
CODE null or integer Work in progress
|
||||
STATUS string Status of the notification; it may vary over time (SUCCESS, ERROR, FAILURE, ...)
|
||||
TEXT string Text of the notification
|
||||
"""
|
||||
|
||||
def __init__(self, mts, notify_type, message_id, notify_info, code, status, text):
|
||||
self.mts = mts
|
||||
self.notify_type = notify_type
|
||||
self.message_id = message_id
|
||||
self.notify_info = notify_info
|
||||
self.code = code
|
||||
self.status = status
|
||||
self.text = text
|
||||
|
||||
def is_success(self):
|
||||
"""
|
||||
Check if the notification status was a success.
|
||||
|
||||
@return bool: True if is success else False
|
||||
"""
|
||||
if self.status == NotificationError.SUCCESS:
|
||||
return True
|
||||
return False
|
||||
|
||||
@staticmethod
|
||||
def from_raw_notification(raw_notification):
|
||||
"""
|
||||
Parse a raw notification object into an Order object
|
||||
|
||||
@return Notification
|
||||
"""
|
||||
mts = raw_notification[NotificationModal.MTS]
|
||||
notify_type = raw_notification[NotificationModal.TYPE]
|
||||
message_id = raw_notification[NotificationModal.MESSAGE_ID]
|
||||
notify_info = raw_notification[NotificationModal.NOTIFY_INFO]
|
||||
code = raw_notification[NotificationModal.CODE]
|
||||
status = raw_notification[NotificationModal.STATUS]
|
||||
text = raw_notification[NotificationModal.TEXT]
|
||||
|
||||
basic = Notification(mts, notify_type, message_id, notify_info, code,
|
||||
status, text)
|
||||
# if failure notification then just return as is
|
||||
if not basic.is_success():
|
||||
return basic
|
||||
# parse additional notification data
|
||||
if basic.notify_type == NotificationTypes.ORDER_NEW_REQ:
|
||||
basic.notify_info = Order.from_raw_order_snapshot(basic.notify_info)
|
||||
elif basic.notify_type == NotificationTypes.ORDER_CANCELED_REQ:
|
||||
basic.notify_info = Order.from_raw_order(basic.notify_info)
|
||||
elif basic.notify_type == NotificationTypes.ORDER_UPDATED_REQ:
|
||||
basic.notify_info = Order.from_raw_order(basic.notify_info)
|
||||
elif basic.notify_type == NotificationTypes.FUNDING_OFFER_NEW:
|
||||
basic.notify_info = FundingOffer.from_raw_offer(basic.notify_info)
|
||||
elif basic.notify_type == NotificationTypes.FUNDING_OFFER_CANCEL:
|
||||
basic.notify_info = FundingOffer.from_raw_offer(basic.notify_info)
|
||||
elif basic.notify_type == NotificationTypes.ACCOUNT_TRANSFER:
|
||||
basic.notify_info = Transfer.from_raw_transfer(basic.notify_info)
|
||||
elif basic.notify_type == NotificationTypes.ACCOUNT_DEPOSIT:
|
||||
basic.notify_info = DepositAddress.from_raw_deposit_address(basic.notify_info)
|
||||
elif basic.notify_type == NotificationTypes.ACCOUNT_WITHDRAW_REQ:
|
||||
basic.notify_info = Withdraw.from_raw_withdraw(basic.notify_info)
|
||||
return basic
|
||||
|
||||
def __str__(self):
|
||||
''' Allow us to print the Notification object in a pretty format '''
|
||||
text = "Notification <'{}' ({}) - {} notify_info={}>"
|
||||
return text.format(self.notify_type, self.status, self.text, self.notify_info)
|
||||
@@ -1,5 +1,5 @@
|
||||
"""
|
||||
Module used to describe all of the different data types
|
||||
Module used to describe all of the different order data types
|
||||
"""
|
||||
|
||||
import time
|
||||
@@ -38,8 +38,7 @@ class OrderSide:
|
||||
|
||||
class OrderClosedModel:
|
||||
"""
|
||||
Enum used ad an index match to locate the different values in a
|
||||
raw order array
|
||||
Enum used index the different values in a raw order array
|
||||
"""
|
||||
ID = 0
|
||||
GID = 1
|
||||
@@ -151,7 +150,7 @@ class Order:
|
||||
@staticmethod
|
||||
def from_raw_order(raw_order):
|
||||
"""
|
||||
Parse a raw order object into an Order oject
|
||||
Parse a raw order object into an Order object
|
||||
|
||||
@return Order
|
||||
"""
|
||||
@@ -178,6 +177,18 @@ class Order:
|
||||
amount_orig, o_type, type_prev, flags, status, price, price_avg,
|
||||
price_trailing, price_aux_limit, notfiy, place_id)
|
||||
|
||||
@staticmethod
|
||||
def from_raw_order_snapshot(raw_order_snapshot):
|
||||
"""
|
||||
Parse a raw order snapshot array into an array of order objects
|
||||
|
||||
@return Orders: array of order objects
|
||||
"""
|
||||
parsed_orders = []
|
||||
for raw_order in raw_order_snapshot:
|
||||
parsed_orders += [Order.from_raw_order(raw_order)]
|
||||
return parsed_orders
|
||||
|
||||
def set_confirmed(self):
|
||||
"""
|
||||
Set the state of the order to be confirmed
|
||||
|
||||
53
bfxapi/models/transfer.py
Normal file
53
bfxapi/models/transfer.py
Normal file
@@ -0,0 +1,53 @@
|
||||
"""
|
||||
Module used to describe a transfer object
|
||||
"""
|
||||
|
||||
class TransferModel:
|
||||
"""
|
||||
Enum used to index the location of each value in a raw array
|
||||
"""
|
||||
MTS = 0
|
||||
W_FROM = 1
|
||||
W_TO = 2
|
||||
C_FROM = 4
|
||||
C_TO = 5
|
||||
AMOUNT = 7
|
||||
|
||||
class Transfer:
|
||||
"""
|
||||
MTS int Millisecond Time Stamp of the update
|
||||
WALLET_FROM string Wallet name (exchange, margin, funding)
|
||||
WALLET_TO string Wallet name (exchange, margin, funding)
|
||||
CURRENCY_FROM string Currency (BTC, etc)
|
||||
CURRENCY_TO string Currency (BTC, etc)
|
||||
AMOUNT string Amount of funds to transfer
|
||||
"""
|
||||
|
||||
def __init__(self, mts, wallet_from, wallet_to, currency_from, currency_to, amount):
|
||||
self.mts = mts
|
||||
self.wallet_from = wallet_from
|
||||
self.wallet_to = wallet_to
|
||||
self.currency_from = currency_from
|
||||
self.currency_to = currency_to
|
||||
self.amount = amount
|
||||
|
||||
@staticmethod
|
||||
def from_raw_transfer(raw_transfer):
|
||||
"""
|
||||
Parse a raw transfer object into a Transfer object
|
||||
|
||||
@return Transfer
|
||||
"""
|
||||
mts = raw_transfer[TransferModel.MTS]
|
||||
wallet_from = raw_transfer[TransferModel.W_FROM]
|
||||
wallet_to = raw_transfer[TransferModel.W_TO]
|
||||
currency_from = raw_transfer[TransferModel.C_FROM]
|
||||
currency_to = raw_transfer[TransferModel.C_TO]
|
||||
amount = raw_transfer[TransferModel.AMOUNT]
|
||||
return Transfer(mts, wallet_from, wallet_to, currency_from, currency_to, amount)
|
||||
|
||||
def __str__(self):
|
||||
''' Allow us to print the Transfer object in a pretty format '''
|
||||
text = "Transfer <{} from {} ({}) to {} ({}) mts={}>"
|
||||
return text.format(self.amount, self.wallet_from, self.currency_from,
|
||||
self.wallet_to, self.currency_to, self.mts)
|
||||
51
bfxapi/models/withdraw.py
Normal file
51
bfxapi/models/withdraw.py
Normal file
@@ -0,0 +1,51 @@
|
||||
"""
|
||||
Module used to describe a withdraw object
|
||||
"""
|
||||
|
||||
class WithdrawModel:
|
||||
"""
|
||||
Enum used to index the location of each value in a raw array
|
||||
"""
|
||||
ID = 0
|
||||
METHOD = 2
|
||||
WALLET = 4
|
||||
AMOUNT = 5
|
||||
FEE = 7
|
||||
|
||||
class Withdraw:
|
||||
"""
|
||||
[13063236, None, 'tetheruse', None, 'exchange', 5, None, None, 0.00135]
|
||||
|
||||
MTS int Millisecond Time Stamp of the update
|
||||
WALLET_FROM string Wallet name (exchange, margin, funding)
|
||||
WALLET_TO string Wallet name (exchange, margin, funding)
|
||||
CURRENCY_FROM string Currency (BTC, etc)
|
||||
CURRENCY_TO string Currency (BTC, etc)
|
||||
AMOUNT string Amount of funds to transfer
|
||||
"""
|
||||
|
||||
def __init__(self, w_id, method, wallet, amount, fee=0):
|
||||
self.id = w_id
|
||||
self.method = method
|
||||
self.wallet = wallet
|
||||
self.amount = amount
|
||||
self.fee = fee
|
||||
|
||||
@staticmethod
|
||||
def from_raw_withdraw(raw_withdraw):
|
||||
"""
|
||||
Parse a raw withdraw object into a Withdraw object
|
||||
|
||||
@return Withdraw
|
||||
"""
|
||||
w_id = raw_withdraw[WithdrawModel.ID]
|
||||
method = raw_withdraw[WithdrawModel.METHOD]
|
||||
wallet = raw_withdraw[WithdrawModel.WALLET]
|
||||
amount = raw_withdraw[WithdrawModel.AMOUNT]
|
||||
return Withdraw(w_id, method, wallet, amount)
|
||||
|
||||
def __str__(self):
|
||||
''' Allow us to print the Transfer object in a pretty format '''
|
||||
text = "Withdraw <id={} from {} ({}) fee={}>"
|
||||
return text.format(self.id, self.wallet, self.method, self.amount,
|
||||
self.fee)
|
||||
@@ -8,9 +8,9 @@ import time
|
||||
import json
|
||||
|
||||
from ..utils.custom_logger import CustomLogger
|
||||
from ..utils.auth import generate_auth_headers
|
||||
from ..utils.auth import generate_auth_headers, calculate_order_flags, gen_unique_cid
|
||||
from ..models import Wallet, Order, Position, Trade, FundingLoan, FundingOffer
|
||||
from ..models import FundingCredit
|
||||
from ..models import FundingCredit, Notification
|
||||
|
||||
|
||||
class BfxRest:
|
||||
@@ -61,7 +61,7 @@ class BfxRest:
|
||||
async with aiohttp.ClientSession() as session:
|
||||
async with session.post(url + params, headers=headers, data=sData) as resp:
|
||||
text = await resp.text()
|
||||
if resp.status is not 200:
|
||||
if resp.status < 200 or resp.status > 299:
|
||||
raise Exception('POST {} failed with status {} - {}'
|
||||
.format(url, resp.status, text))
|
||||
parsed = json.loads(text, parse_float=self.parse_float)
|
||||
@@ -351,48 +351,227 @@ class BfxRest:
|
||||
credits = await self.post(endpoint, params=params)
|
||||
return [FundingCredit.from_raw_credit(c) for c in credits]
|
||||
|
||||
async def submit_funding_offer(self, symbol, amount, rate, period,
|
||||
funding_type=FundingOffer.Type.LIMIT, hidden=False):
|
||||
"""
|
||||
Submits a new funding offer
|
||||
|
||||
@param symbol string: pair symbol i.e fUSD
|
||||
@param amount float: funding size
|
||||
@param rate float: percentage rate to charge per a day
|
||||
@param period int: number of days for funding to remain active once accepted
|
||||
"""
|
||||
payload = {
|
||||
"type": funding_type,
|
||||
"symbol": symbol,
|
||||
"amount": str(amount),
|
||||
"rate": str(rate),
|
||||
"period": period,
|
||||
}
|
||||
# calculate and add flags
|
||||
flags = calculate_order_flags(hidden, None, None, None, None)
|
||||
payload['flags'] = flags
|
||||
endpoint = "auth/w/funding/offer/submit"
|
||||
raw_notification = await self.post(endpoint, payload)
|
||||
return Notification.from_raw_notification(raw_notification)
|
||||
|
||||
async def submit_cancel_funding_offer(self, fundingId):
|
||||
"""
|
||||
Cancel a funding offer
|
||||
|
||||
@param fundingId int: the id of the funding offer
|
||||
"""
|
||||
endpoint = "auth/w/funding/offer/cancel"
|
||||
raw_notification = await self.post(endpoint, { 'id': fundingId })
|
||||
return Notification.from_raw_notification(raw_notification)
|
||||
|
||||
async def submit_wallet_transfer(self, from_wallet, to_wallet, from_currency, to_currency, amount):
|
||||
"""
|
||||
Transfer funds between wallets
|
||||
|
||||
@param from_wallet string: wallet name to transfer from i.e margin, exchange
|
||||
@param to_wallet string: wallet name to transfer to i.e margin, exchange
|
||||
@param from_currency string: currency symbol to tranfer from i.e BTC, USD
|
||||
@param to_currency string: currency symbol to transfer to i.e BTC, USD
|
||||
@param amount float: amount of funds to transfer
|
||||
"""
|
||||
endpoint = "auth/w/transfer"
|
||||
payload = {
|
||||
"from": from_wallet,
|
||||
"to": to_wallet,
|
||||
"currency": from_currency,
|
||||
"currency_to": to_currency,
|
||||
"amount": str(amount),
|
||||
}
|
||||
raw_transfer = await self.post(endpoint, payload)
|
||||
return Notification.from_raw_notification(raw_transfer)
|
||||
|
||||
async def get_wallet_deposit_address(self, wallet, method, renew=0):
|
||||
"""
|
||||
Get the deposit address for the given wallet and protocol
|
||||
|
||||
@param wallet string: wallet name i.e margin, exchange
|
||||
@param method string: transfer protocol i.e bitcoin
|
||||
"""
|
||||
endpoint = "auth/w/deposit/address"
|
||||
payload = {
|
||||
"wallet": wallet,
|
||||
"method": method,
|
||||
"op_renew": renew,
|
||||
}
|
||||
raw_deposit = await self.post(endpoint, payload)
|
||||
return Notification.from_raw_notification(raw_deposit)
|
||||
|
||||
async def create_wallet_deposit_address(self, wallet, method):
|
||||
"""
|
||||
Creates a new deposit address for the given wallet and protocol.
|
||||
Previously generated addresses remain linked.
|
||||
|
||||
@param wallet string: wallet name i.e margin, exchange
|
||||
@param method string: transfer protocol i.e bitcoin
|
||||
"""
|
||||
return await self.get_wallet_deposit_address(wallet, method, renew=1)
|
||||
|
||||
async def submit_wallet_withdraw(self, wallet, method, amount, address):
|
||||
"""
|
||||
`/v2/auth/w/withdraw` (params: `wallet`, `method`, `amount`, `address
|
||||
"""
|
||||
endpoint = "auth/w/withdraw"
|
||||
payload = {
|
||||
"wallet": wallet,
|
||||
"method": method,
|
||||
"amount": str(amount),
|
||||
"address": str(address)
|
||||
}
|
||||
raw_deposit = await self.post(endpoint, payload)
|
||||
return Notification.from_raw_notification(raw_deposit)
|
||||
|
||||
# async def submit_close_funding(self, id, type):
|
||||
# """
|
||||
# `/v2/auth/w/funding/close` (params: `id`, `type` (credit|loan))
|
||||
# """
|
||||
# pass
|
||||
|
||||
# async def submit_auto_funding(self, ):
|
||||
# """
|
||||
# `/v2/auth/w/funding/auto` (params: `status` (1|0), `currency`, `amount`, `rate`, `period`)
|
||||
# (`rate === 0` means `FRR`)
|
||||
# """
|
||||
# pass
|
||||
|
||||
##################################################
|
||||
# Orders #
|
||||
##################################################
|
||||
|
||||
async def __submit_order(self, symbol, amount, price, oType=Order.Type.LIMIT,
|
||||
is_hidden=False, is_postonly=False, use_all_available=False,
|
||||
stop_order=False, stop_buy_price=0, stop_sell_price=0):
|
||||
async def submit_order(self, symbol, price, amount, market_type=Order.Type.LIMIT,
|
||||
hidden=False, price_trailing=None, price_aux_limit=None,
|
||||
oco_stop_price=None, close=False, reduce_only=False,
|
||||
post_only=False, oco=False, time_in_force=None, leverage=None,
|
||||
gid=None):
|
||||
"""
|
||||
Submit a new order
|
||||
|
||||
@param gid: assign the order to a group identifier
|
||||
@param symbol: the name of the symbol i.e 'tBTCUSD
|
||||
@param price: the price you want to buy/sell at (must be positive)
|
||||
@param amount: order size: how much you want to buy/sell,
|
||||
a negative amount indicates a sell order and positive a buy order
|
||||
@param price: the price you want to buy/sell at (must be positive)
|
||||
@param oType: order type, see Order.Type enum
|
||||
@param is_hidden: True if order should be hidden from orderbooks
|
||||
@param is_postonly: True if should be post only. Only relevant for limit
|
||||
@param use_all_available: True if order should use entire balance
|
||||
@param stop_order: True to set an additional STOP OCO order linked to the
|
||||
current order
|
||||
@param stop_buy_price: set the OCO stop buy price (requires stop_order True)
|
||||
@param stop_sell_price: set the OCO stop sell price (requires stop_order True)
|
||||
@param market_type Order.Type: please see Order.Type enum
|
||||
amount decimal string Positive for buy, Negative for sell
|
||||
@param hidden: if True, order should be hidden from orderbooks
|
||||
@param price_trailing: decimal trailing price
|
||||
@param price_aux_limit: decimal auxiliary Limit price (only for STOP LIMIT)
|
||||
@param oco_stop_price: set the oco stop price (requires oco = True)
|
||||
@param close: if True, close position if position present
|
||||
@param reduce_only: if True, ensures that the executed order does not flip the opened position
|
||||
@param post_only: if True, ensures the limit order will be added to the order book and not
|
||||
match with a pre-existing order
|
||||
@param oco: cancels other order option allows you to place a pair of orders stipulating
|
||||
that if one order is executed fully or partially, then the other is automatically canceled
|
||||
@param time_in_force: datetime for automatic order cancellation ie. 2020-01-01 10:45:23
|
||||
@param leverage: the amount of leverage to apply to the order as an integer
|
||||
"""
|
||||
raise NotImplementedError(
|
||||
"V2 submit order has not yet been added to the bfx api. Please use bfxapi.ws")
|
||||
side = Order.Side.SELL if amount < 0 else Order.Side.BUY
|
||||
use_all_balance = 1 if use_all_available else 0
|
||||
payload = {}
|
||||
payload['symbol'] = symbol
|
||||
payload['amount'] = abs(amount)
|
||||
payload['price'] = price
|
||||
payload['side'] = side
|
||||
payload['type'] = oType
|
||||
payload['is_hidden'] = is_hidden
|
||||
payload['is_postonly'] = is_postonly
|
||||
payload['use_all_available'] = use_all_balance
|
||||
payload['ocoorder'] = stop_order
|
||||
if stop_order:
|
||||
payload['buy_price_oco'] = stop_buy_price
|
||||
payload['sell_price_oco'] = stop_sell_price
|
||||
endpoint = 'order/new'
|
||||
return await self.post(endpoint, data=payload)
|
||||
cid = gen_unique_cid()
|
||||
payload = {
|
||||
"cid": cid,
|
||||
"type": str(market_type),
|
||||
"symbol": symbol,
|
||||
"amount": str(amount),
|
||||
"price": str(price),
|
||||
}
|
||||
# calculate and add flags
|
||||
flags = calculate_order_flags(hidden, close, reduce_only, post_only, oco)
|
||||
payload['flags'] = flags
|
||||
# add extra parameters
|
||||
if price_trailing is not None:
|
||||
payload['price_trailing'] = price_trailing
|
||||
if price_aux_limit is not None:
|
||||
payload['price_aux_limit'] = price_aux_limit
|
||||
if oco_stop_price is not None:
|
||||
payload['price_oco_stop'] = str(oco_stop_price)
|
||||
if time_in_force is not None:
|
||||
payload['tif'] = time_in_force
|
||||
if gid is not None:
|
||||
payload['gid'] = gid
|
||||
if leverage is not None:
|
||||
payload['lev'] = str(leverage)
|
||||
endpoint = "auth/w/order/submit"
|
||||
raw_notification = await self.post(endpoint, payload)
|
||||
return Notification.from_raw_order(raw_notification)
|
||||
|
||||
async def submit_cancel_order(self, orderId):
|
||||
"""
|
||||
Cancel an existing open order
|
||||
|
||||
@param orderId: the id of the order that you want to update
|
||||
"""
|
||||
endpoint = "auth/w/order/cancel"
|
||||
raw_notification = await self.post(endpoint, { 'id': orderId })
|
||||
return Notification.from_raw_order(raw_notification)
|
||||
|
||||
async def submit_update_order(self, orderId, price=None, amount=None, delta=None, price_aux_limit=None,
|
||||
price_trailing=None, hidden=False, close=False, reduce_only=False,
|
||||
post_only=False, time_in_force=None, leverage=None):
|
||||
"""
|
||||
Update an existing order
|
||||
|
||||
@param orderId: the id of the order that you want to update
|
||||
@param price: the price you want to buy/sell at (must be positive)
|
||||
@param amount: order size: how much you want to buy/sell,
|
||||
a negative amount indicates a sell order and positive a buy order
|
||||
@param delta: change of amount
|
||||
@param price_trailing: decimal trailing price
|
||||
@param price_aux_limit: decimal auxiliary Limit price (only for STOP LIMIT)
|
||||
@param hidden: if True, order should be hidden from orderbooks
|
||||
@param close: if True, close position if position present
|
||||
@param reduce_only: if True, ensures that the executed order does not flip the opened position
|
||||
@param post_only: if True, ensures the limit order will be added to the order book and not
|
||||
match with a pre-existing order
|
||||
@param time_in_force: datetime for automatic order cancellation ie. 2020-01-01 10:45:23
|
||||
@param leverage: the amount of leverage to apply to the order as an integer
|
||||
"""
|
||||
payload = {"id": orderId}
|
||||
if price is not None:
|
||||
payload['price'] = str(price)
|
||||
if amount is not None:
|
||||
payload['amount'] = str(amount)
|
||||
if delta is not None:
|
||||
payload['delta'] = str(delta)
|
||||
if price_aux_limit is not None:
|
||||
payload['price_aux_limit'] = str(price_aux_limit)
|
||||
if price_trailing is not None:
|
||||
payload['price_trailing'] = str(price_trailing)
|
||||
if time_in_force is not None:
|
||||
payload['time_in_force'] = str(time_in_force)
|
||||
if leverage is not None:
|
||||
payload["lev"] = str(leverage)
|
||||
flags = calculate_order_flags(
|
||||
hidden, close, reduce_only, post_only, False)
|
||||
payload['flags'] = flags
|
||||
endpoint = "auth/w/order/update"
|
||||
raw_notification = await self.post(endpoint, payload)
|
||||
return Notification.from_raw_order(raw_notification)
|
||||
|
||||
|
||||
##################################################
|
||||
# Derivatives #
|
||||
|
||||
@@ -122,7 +122,7 @@ async def test_closed_callback_on_submit_order_closed():
|
||||
client.ws._emit('c1', order)
|
||||
callback_wait = EventWatcher.watch(client.ws, 'c1')
|
||||
# override cid generation
|
||||
client.ws.orderManager._gen_unqiue_cid = lambda: 123
|
||||
client.ws.orderManager._gen_unique_cid = lambda: 123
|
||||
await client.ws.submit_order('tBTCUSD', 19000, 0.01, 'EXCHANGE MARKET', onClose=c)
|
||||
await client.ws.publish([0,"oc",[123,None,1548262833910,"tBTCUSD",1548262833379,1548262888016,0,-1,"EXCHANGE LIMIT",None,None,None,0,"EXECUTED @ 15980.0(-0.5): was PARTIALLY FILLED @ 15980.0(-0.5)",None,None,15980,15980,0,0,None,None,None,0,0,None,None,None,"API>BFX",None,None,None]])
|
||||
callback_wait.wait_until_complete()
|
||||
@@ -139,7 +139,7 @@ async def test_confirmed_callback_on_submit_order_closed():
|
||||
client.ws._emit('c1', order)
|
||||
callback_wait = EventWatcher.watch(client.ws, 'c1')
|
||||
# override cid generation
|
||||
client.ws.orderManager._gen_unqiue_cid = lambda: 123
|
||||
client.ws.orderManager._gen_unique_cid = lambda: 123
|
||||
await client.ws.submit_order('tBTCUSD', 19000, 0.01, 'EXCHANGE MARKET', onConfirm=c)
|
||||
await client.ws.publish([0,"oc",[123,None,1548262833910,"tBTCUSD",1548262833379,1548262888016,0,-1,"EXCHANGE LIMIT",None,None,None,0,"EXECUTED @ 15980.0(-0.5): was PARTIALLY FILLED @ 15980.0(-0.5)",None,None,15980,15980,0,0,None,None,None,0,0,None,None,None,"API>BFX",None,None,None]])
|
||||
callback_wait.wait_until_complete()
|
||||
@@ -155,7 +155,7 @@ async def test_confirmed_callback_on_submit_new_order():
|
||||
client.ws._emit('c1', order)
|
||||
callback_wait = EventWatcher.watch(client.ws, 'c1')
|
||||
# override cid generation
|
||||
client.ws.orderManager._gen_unqiue_cid = lambda: 123
|
||||
client.ws.orderManager._gen_unique_cid = lambda: 123
|
||||
await client.ws.submit_order('tBTCUSD', 19000, 0.01, 'EXCHANGE MARKET', onConfirm=c)
|
||||
await client.ws.publish([0,"on",[123,None,1548262833910,"tBTCUSD",1548262833379,1548262833410,-1,-1,"EXCHANGE LIMIT",None,None,None,0,"ACTIVE",None,None,15980,0,0,0,None,None,None,0,0,None,None,None,"API>BFX",None,None,None]])
|
||||
callback_wait.wait_until_complete()
|
||||
@@ -171,7 +171,7 @@ async def test_confirmed_callback_on_submit_order_update():
|
||||
client.ws._emit('c1', order)
|
||||
callback_wait = EventWatcher.watch(client.ws, 'c1')
|
||||
# override cid generation
|
||||
client.ws.orderManager._gen_unqiue_cid = lambda: 123
|
||||
client.ws.orderManager._gen_unique_cid = lambda: 123
|
||||
await client.ws.update_order(123, price=100, onConfirm=c)
|
||||
await client.ws.publish([0,"ou",[123,None,1548262833910,"tBTCUSD",1548262833379,1548262846964,-0.5,-1,"EXCHANGE LIMIT",None,None,None,0,"PARTIALLY FILLED @ 15980.0(-0.5)",None,None,15980,15980,0,0,None,None,None,0,0,None,None,None,"API>BFX",None,None,None]])
|
||||
callback_wait.wait_until_complete()
|
||||
@@ -187,7 +187,7 @@ async def test_confirmed_callback_on_submit_cancel_order():
|
||||
client.ws._emit('c1', order)
|
||||
callback_wait = EventWatcher.watch(client.ws, 'c1')
|
||||
# override cid generation
|
||||
client.ws.orderManager._gen_unqiue_cid = lambda: 123
|
||||
client.ws.orderManager._gen_unique_cid = lambda: 123
|
||||
await client.ws.cancel_order(123, onConfirm=c)
|
||||
await client.ws.publish([0,"oc",[123,None,1548262833910,"tBTCUSD",1548262833379,1548262888016,0,-1,"EXCHANGE LIMIT",None,None,None,0,"EXECUTED @ 15980.0(-0.5): was PARTIALLY FILLED @ 15980.0(-0.5)",None,None,15980,15980,0,0,None,None,None,0,0,None,None,None,"API>BFX",None,None,None]])
|
||||
callback_wait.wait_until_complete()
|
||||
@@ -203,7 +203,7 @@ async def test_confirmed_callback_on_submit_cancel_group_order():
|
||||
client.ws._emit('c1', order)
|
||||
callback_wait = EventWatcher.watch(client.ws, 'c1')
|
||||
# override cid generation
|
||||
client.ws.orderManager._gen_unqiue_cid = lambda: 123
|
||||
client.ws.orderManager._gen_unique_cid = lambda: 123
|
||||
await client.ws.cancel_order_group(123, onConfirm=c)
|
||||
await client.ws.publish([0,"oc",[1548262833910,123,1548262833910,"tBTCUSD",1548262833379,1548262888016,0,-1,"EXCHANGE LIMIT",None,None,None,0,"EXECUTED @ 15980.0(-0.5): was PARTIALLY FILLED @ 15980.0(-0.5)",None,None,15980,15980,0,0,None,None,None,0,0,None,None,None,"API>BFX",None,None,None]])
|
||||
callback_wait.wait_until_complete()
|
||||
|
||||
@@ -6,6 +6,7 @@ to handle the http authentication of the client
|
||||
import hashlib
|
||||
import hmac
|
||||
import time
|
||||
from ..models import Order
|
||||
|
||||
def generate_auth_payload(API_KEY, API_SECRET):
|
||||
"""
|
||||
@@ -48,3 +49,15 @@ def _gen_signature(API_KEY, API_SECRET, nonce):
|
||||
|
||||
def _gen_nonce():
|
||||
return int(round(time.time() * 1000000))
|
||||
|
||||
def gen_unique_cid():
|
||||
return int(round(time.time() * 1000))
|
||||
|
||||
def calculate_order_flags(hidden, close, reduce_only, post_only, oco):
|
||||
flags = 0
|
||||
flags = flags + Order.Flags.HIDDEN if hidden else flags
|
||||
flags = flags + Order.Flags.CLOSE if close else flags
|
||||
flags = flags + Order.Flags.REDUCE_ONLY if reduce_only else flags
|
||||
flags = flags + Order.Flags.POST_ONLY if post_only else flags
|
||||
flags = flags + Order.Flags.OCO if oco else flags
|
||||
return flags
|
||||
|
||||
@@ -2,4 +2,4 @@
|
||||
This module contains the current version of the bfxapi lib
|
||||
"""
|
||||
|
||||
__version__ = '1.0.1'
|
||||
__version__ = '1.1.0'
|
||||
|
||||
@@ -7,6 +7,7 @@ import asyncio
|
||||
|
||||
from ..utils.custom_logger import CustomLogger
|
||||
from ..models import Order
|
||||
from ..utils.auth import calculate_order_flags, gen_unique_cid
|
||||
|
||||
|
||||
class OrderManager:
|
||||
@@ -83,18 +84,15 @@ class OrderManager:
|
||||
self.logger.info("Order new: {}".format(order))
|
||||
self.bfxapi._emit('order_new', order)
|
||||
|
||||
def _gen_unqiue_cid(self):
|
||||
return int(round(time.time() * 1000))
|
||||
|
||||
async def submit_order(self, symbol, price, amount, market_type=Order.Type.LIMIT,
|
||||
hidden=False, price_trailing=None, price_aux_limit=None,
|
||||
oco_stop_price=None, close=False, reduce_only=False,
|
||||
post_only=False, oco=False, time_in_force=None,
|
||||
post_only=False, oco=False, time_in_force=None, leverage=None,
|
||||
onConfirm=None, onClose=None, gid=None, *args, **kwargs):
|
||||
"""
|
||||
Submit a new order
|
||||
|
||||
@param gid: assign the order to a group identitfier
|
||||
@param gid: assign the order to a group identifier
|
||||
@param symbol: the name of the symbol i.e 'tBTCUSD
|
||||
@param price: the price you want to buy/sell at (must be positive)
|
||||
@param amount: order size: how much you want to buy/sell,
|
||||
@@ -113,12 +111,13 @@ class OrderManager:
|
||||
that if one order is executed fully or partially, then the other is automatically canceled
|
||||
|
||||
@param time_in_force: datetime for automatic order cancellation ie. 2020-01-01 10:45:23
|
||||
@param leverage: the amount of leverage to apply to the order as an integer
|
||||
@param onConfirm: function called when the bitfinex websocket receives signal that the order
|
||||
was confirmed
|
||||
@param onClose: function called when the bitfinex websocket receives signal that the order
|
||||
was closed due to being filled or cancelled
|
||||
"""
|
||||
cid = self._gen_unqiue_cid()
|
||||
cid = self._gen_unique_cid()
|
||||
# create base payload with required data
|
||||
payload = {
|
||||
"cid": cid,
|
||||
@@ -127,20 +126,22 @@ class OrderManager:
|
||||
"amount": str(amount),
|
||||
"price": str(price),
|
||||
}
|
||||
# caclulate and add flags
|
||||
flags = self._calculate_flags(hidden, close, reduce_only, post_only, oco)
|
||||
# calculate and add flags
|
||||
flags = calculate_order_flags(hidden, close, reduce_only, post_only, oco)
|
||||
payload['flags'] = flags
|
||||
# add extra parameters
|
||||
if (price_trailing):
|
||||
if price_trailing is not None:
|
||||
payload['price_trailing'] = price_trailing
|
||||
if (price_aux_limit):
|
||||
if price_aux_limit is not None:
|
||||
payload['price_aux_limit'] = price_aux_limit
|
||||
if (oco_stop_price):
|
||||
if oco_stop_price is not None:
|
||||
payload['price_oco_stop'] = str(oco_stop_price)
|
||||
if (time_in_force):
|
||||
if time_in_force is not None:
|
||||
payload['tif'] = time_in_force
|
||||
if (gid):
|
||||
if gid is not None:
|
||||
payload['gid'] = gid
|
||||
if leverage is not None:
|
||||
payload['lev'] = str(leverage)
|
||||
# submit the order
|
||||
self.pending_orders[cid] = payload
|
||||
self._create_callback(cid, onConfirm, self.pending_order_confirm_callbacks)
|
||||
@@ -151,7 +152,7 @@ class OrderManager:
|
||||
|
||||
async def update_order(self, orderId, price=None, amount=None, delta=None, price_aux_limit=None,
|
||||
price_trailing=None, hidden=False, close=False, reduce_only=False,
|
||||
post_only=False, time_in_force=None, onConfirm=None):
|
||||
post_only=False, time_in_force=None, leverage=None, onConfirm=None):
|
||||
"""
|
||||
Update an existing order
|
||||
|
||||
@@ -167,7 +168,8 @@ class OrderManager:
|
||||
@param reduce_only: if True, ensures that the executed order does not flip the opened position
|
||||
@param post_only: if True, ensures the limit order will be added to the order book and not
|
||||
match with a pre-existing order
|
||||
@param time_in_force: datetime for automatic order cancellation ie. 2020-01-01 10:45:23
|
||||
@param time_in_force: datetime for automatic order cancellation ie. 2020-01-01 10:45:23
|
||||
@param leverage: the amount of leverage to apply to the order as an integer
|
||||
@param onConfirm: function called when the bitfinex websocket receives signal that the order
|
||||
was confirmed
|
||||
@param onClose: function called when the bitfinex websocket receives signal that the order
|
||||
@@ -187,7 +189,9 @@ class OrderManager:
|
||||
payload['price_trailing'] = str(price_trailing)
|
||||
if time_in_force is not None:
|
||||
payload['time_in_force'] = str(time_in_force)
|
||||
flags = self._calculate_flags(
|
||||
if leverage is not None:
|
||||
payload['lev'] = str(leverage)
|
||||
flags = calculate_order_flags(
|
||||
hidden, close, reduce_only, post_only, False)
|
||||
payload['flags'] = flags
|
||||
await self.bfxapi._send_auth_command('ou', payload)
|
||||
@@ -261,11 +265,5 @@ class OrderManager:
|
||||
del callback_storage[key]
|
||||
await asyncio.gather(*tasks)
|
||||
|
||||
def _calculate_flags(self, hidden, close, reduce_only, post_only, oco):
|
||||
flags = 0
|
||||
flags = flags + Order.Flags.HIDDEN if hidden else flags
|
||||
flags = flags + Order.Flags.CLOSE if close else flags
|
||||
flags = flags + Order.Flags.REDUUCE_ONLY if reduce_only else flags
|
||||
flags = flags + Order.Flags.POST_ONLY if post_only else flags
|
||||
flags = flags + Order.Flags.OCO if oco else flags
|
||||
return flags
|
||||
def _gen_unique_cid(self):
|
||||
return gen_unique_cid()
|
||||
|
||||
@@ -2,7 +2,7 @@ eventemitter==0.2.0
|
||||
asyncio==3.4.3
|
||||
websockets==7.0
|
||||
pylint==2.3.0
|
||||
pytest-asyncio==0.9.0
|
||||
pytest-asyncio==0.10.0
|
||||
six==1.12.0
|
||||
pyee==5.0.0
|
||||
aiohttp==3.4.4
|
||||
|
||||
2
setup.py
2
setup.py
@@ -20,7 +20,7 @@ here = path.abspath(path.dirname(__file__))
|
||||
|
||||
setup(
|
||||
name='bitfinex-api-py',
|
||||
version='1.0.1', # Required
|
||||
version='1.1.0', # Required
|
||||
description='Official Bitfinex API', # Optional
|
||||
long_description='This is an official python library that is used to connect interact with the Bitfinex api.', # Optional
|
||||
long_description_content_type='text/markdown', # Optional
|
||||
|
||||
Reference in New Issue
Block a user