diff --git a/CHANGELOG b/CHANGELOG index 3c1f98a..0ce9902 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,8 @@ +2.0.0 +-) Implemented Movement endpoints (REST) +-) Fixed unawaited stop +-) Changed account's trade execution (te) and trade update (tu) handling + 1.3.4 -) Fixed undefined p_sub issue in subscription_manager.py -) Added submit cancel all funding orders endpoint (REST) diff --git a/bfxapi/__init__.py b/bfxapi/__init__.py index f5fbc80..4ad4f80 100644 --- a/bfxapi/__init__.py +++ b/bfxapi/__init__.py @@ -5,7 +5,8 @@ This module is used to interact with the bitfinex api from .version import __version__ from .client import Client from .models import (Order, Trade, OrderBook, Subscription, Wallet, - Position, FundingLoan, FundingOffer, FundingCredit) + Position, FundingLoan, FundingOffer, FundingCredit, + Movement) from .websockets.generic_websocket import GenericWebsocket, Socket from .websockets.bfx_websocket import BfxWebsocket from .utils.decimal import Decimal diff --git a/bfxapi/models/__init__.py b/bfxapi/models/__init__.py index b9b4b17..c7bf7b2 100644 --- a/bfxapi/models/__init__.py +++ b/bfxapi/models/__init__.py @@ -22,5 +22,6 @@ from .ledger import Ledger from .funding_trade import FundingTrade from .margin_info import MarginInfo from .margin_info_base import MarginInfoBase +from .movement import Movement NAME = "models" diff --git a/bfxapi/models/movement.py b/bfxapi/models/movement.py new file mode 100644 index 0000000..d212e72 --- /dev/null +++ b/bfxapi/models/movement.py @@ -0,0 +1,76 @@ +""" +Module used to describe movement data types +""" + +import time +import datetime + +class MovementModel: + """ + Enum used index the different values in a raw movement array + """ + + ID = 0 + CURRENCY = 1 + CURRENCY_NAME = 2 + MTS_STARTED = 5 + MTS_UPDATED = 6 + STATUS = 9 + AMOUNT = 12 + FEES = 13 + DESTINATION_ADDRESS = 16 + TRANSACTION_ID = 20 + +class Movement: + + """ + ID String Movement identifier + CURRENCY String The symbol of the currency (ex. "BTC") + CURRENCY_NAME String The extended name of the currency (ex. "BITCOIN") + MTS_STARTED Date Movement started at + MTS_UPDATED Date Movement last updated at + STATUS String Current status + AMOUNT String Amount of funds moved + FEES String Tx Fees applied + DESTINATION_ADDRESS String Destination address + TRANSACTION_ID String Transaction identifier + """ + + def __init__(self, mid, currency, mts_started, mts_updated, status, amount, fees, dst_address, tx_id): + self.id = mid + self.currency = currency + self.mts_started = mts_started + self.mts_updated = mts_updated + self.status = status + self.amount = amount + self.fees = fees + self.dst_address = dst_address + self.tx_id = tx_id + + self.date = datetime.datetime.fromtimestamp(mts_started/1000.0) + + + @staticmethod + def from_raw_movement(raw_movement): + """ + Parse a raw movement object into a Movement object + @return Movement + """ + + mid = raw_movement[MovementModel.ID] + currency = raw_movement[MovementModel.CURRENCY] + mts_started = raw_movement[MovementModel.MTS_STARTED] + mts_updated = raw_movement[MovementModel.MTS_UPDATED] + status = raw_movement[MovementModel.STATUS] + amount = raw_movement[MovementModel.AMOUNT] + fees = raw_movement[MovementModel.FEES] + dst_address = raw_movement[MovementModel.DESTINATION_ADDRESS] + tx_id = raw_movement[MovementModel.TRANSACTION_ID] + + return Movement(mid, currency, mts_started, mts_updated, status, amount, fees, dst_address, tx_id) + + def __str__(self): + ''' Allow us to print the Movement object in a pretty format ''' + text = "Movement <'{}' amount={} fees={} mts_created={} mts_updated={} status='{}' destination_address={} transaction_id={}>" + return text.format(self.currency, self.amount, self.fees, + self.mts_started, self.mts_updated, self.status, self.dst_address, self.tx_id) \ No newline at end of file diff --git a/bfxapi/rest/bfx_rest.py b/bfxapi/rest/bfx_rest.py index 5cfc97a..e2b0c90 100644 --- a/bfxapi/rest/bfx_rest.py +++ b/bfxapi/rest/bfx_rest.py @@ -11,7 +11,7 @@ import datetime from ..utils.custom_logger import CustomLogger from ..utils.auth import generate_auth_headers, calculate_order_flags, gen_unique_cid from ..models import Wallet, Order, Position, Trade, FundingLoan, FundingOffer, FundingTrade, MarginInfoBase, MarginInfo -from ..models import FundingCredit, Notification, Ledger +from ..models import FundingCredit, Notification, Ledger, Movement class BfxRest: @@ -609,6 +609,22 @@ class BfxRest: raw_ledgers = await self.post(endpoint, params=params) return [Ledger.from_raw_ledger(rl) for rl in raw_ledgers] + async def get_movement_history(self, currency, start="", end="", limit=25): + """ + Get all of the deposits and withdraws between the start and end period associated with API_KEY + - Requires authentication. + # Attributes + @param currency string: pair symbol i.e BTC + @param start int: millisecond start time + @param end int: millisecond end time + @param limit int: max number of items in response + @return Array + """ + endpoint = "auth/r/movements/{}/hist".format(currency) + params = "?start={}&end={}&limit={}".format(start, end, limit) + raw_movements = await self.post(endpoint, params=params) + return [Movement.from_raw_movement(rm) for rm in raw_movements] + async def submit_funding_offer(self, symbol, amount, rate, period, funding_type=FundingOffer.Type.LIMIT, hidden=False): """ diff --git a/bfxapi/version.py b/bfxapi/version.py index bceabe3..b16d0cf 100644 --- a/bfxapi/version.py +++ b/bfxapi/version.py @@ -2,4 +2,4 @@ This module contains the current version of the bfxapi lib """ -__version__ = '1.3.4' +__version__ = '2.0.0' diff --git a/bfxapi/websockets/bfx_websocket.py b/bfxapi/websockets/bfx_websocket.py index ce5660e..41aff69 100644 --- a/bfxapi/websockets/bfx_websocket.py +++ b/bfxapi/websockets/bfx_websocket.py @@ -66,6 +66,37 @@ def _parse_trade(tData, symbol): 'symbol': symbol } +def _parse_account_trade(tData): + return { + 'id': tData[0], + 'symbol': tData[1], + 'mts_create': tData[2], + 'order_id': tData[3], + 'exec_amount': tData[4], + 'exec_price': tData[5], + 'order_type': tData[6], + 'order_price': tData[7], + 'maker': tData[8], + 'cid': tData[11], + } + + +def _parse_account_trade_update(tData): + return { + 'id': tData[0], + 'symbol': tData[1], + 'mts_create': tData[2], + 'order_id': tData[3], + 'exec_amount': tData[4], + 'exec_price': tData[5], + 'order_type': tData[6], + 'order_price': tData[7], + 'maker': tData[8], + 'fee': tData[9], + 'fee_currency': tData[10], + 'cid': tData[11], + } + def _parse_deriv_status_update(sData, symbol): return { 'symbol': symbol, @@ -278,19 +309,15 @@ class BfxWebsocket(GenericWebsocket): async def _trade_update_handler(self, data): tData = data[2] - # [209, 'tu', [312372989, 1542303108930, 0.35, 5688.61834032]] - if self.subscriptionManager.is_subscribed(data[0]): - symbol = self.subscriptionManager.get(data[0]).symbol - tradeObj = _parse_trade(tData, symbol) - self._emit('trade_update', tradeObj) + # [0,"tu",[738045455,"tTESTBTC:TESTUSD",1622169615771,66635385225,0.001,38175,"EXCHANGE LIMIT",39000,-1,-0.000002,"TESTBTC",1622169615685]] + tradeObj = _parse_account_trade_update(tData) + self._emit('trade_update', tradeObj) async def _trade_executed_handler(self, data): tData = data[2] - # [209, 'te', [312372989, 1542303108930, 0.35, 5688.61834032]] - if self.subscriptionManager.is_subscribed(data[0]): - symbol = self.subscriptionManager.get(data[0]).symbol - tradeObj = _parse_trade(tData, symbol) - self._emit('new_trade', tradeObj) + # [0,"te",[738045455,"tTESTBTC:TESTUSD",1622169615771,66635385225,0.001,38175,"EXCHANGE LIMIT",39000,-1,null,null,1622169615685]] + tradeObj = _parse_account_trade(tData) + self._emit('new_trade', tradeObj) async def _wallet_update_handler(self, data): # [0,"wu",["exchange","USD",89134.66933283,0]] @@ -409,12 +436,7 @@ class BfxWebsocket(GenericWebsocket): # connection data.reverse() for t in data: - trade = { - 'mts': t[1], - 'amount': t[2], - 'price': t[3], - 'symbol': symbol - } + trade = _parse_trade(t, symbol) self._emit('seed_trade', trade) async def _candle_handler(self, data): diff --git a/bfxapi/websockets/generic_websocket.py b/bfxapi/websockets/generic_websocket.py index dcb39a8..3530ff4 100644 --- a/bfxapi/websockets/generic_websocket.py +++ b/bfxapi/websockets/generic_websocket.py @@ -208,7 +208,7 @@ class GenericWebsocket: """ This is used by the HF data server. """ - self.stop() + await self.stop() async def on_open(self): """ diff --git a/setup.py b/setup.py index 1d2cfce..1223b29 100644 --- a/setup.py +++ b/setup.py @@ -11,7 +11,7 @@ from os import path here = path.abspath(path.dirname(__file__)) setup( name='bitfinex-api-py', - version='1.3.4', + version='2.0.0', description='Official Bitfinex Python API', long_description='A Python reference implementation of the Bitfinex API for both REST and websocket interaction', long_description_content_type='text/markdown',