Another unofficial Rust Library for the Bitfinex API V2.
Add the lib as a project dependency in you Cargo.toml
.
[dependencies]
bitfinex-api = { git = "https://github.com/xenoliss/bitfinex-api" }
The library provides the necessary building blocks to interact with the Bitfinex API V2. It mostly exposes three main traits that you can implement on your types to build logic that fits your exact needs:
-
The
Client
/AsyncClient
traits can be implemented on tour types to turn them into working instance that can communcicate with the API. DefaultBitfinex
/AsyncBitfinex
clients are already implemented. -
The
Endpoint
trait can be implemented on your types to turn them into actual endpoints that your application needs to interact with. Not all the endpoints are currently implemented but it's really easy to add new ones or adapt existing ones to fit your exact needs. -
The
Query
/AsyncQuery
traits are implemented on all types that implementEndpoint
and expose thequery
/query_async
methods in which theClient
/AsyncClient
are injected to perform the requests.
Here is an example of querying the Ticker endpoint using the default implementations provided by the lib:
#[tokio::main]
async fn main() {
// 1. Instanciate an `AsyncClient`.
let client = AsyncBitfinex::default();
// 2. Build the endpoint using the builder pattern.
// NOTE: The builder pattern allows to easily add required/optional parameters to each endpoint.
let endpoint = PlatformStatus::builder().build().unwrap();
// 3. Perform the query against the endpoint.
// NOTE: The returned type needs to be explicitly set by the caller. This is intended as it allows
// for a greater flexibility for the lib user. Default returned types (like here with the `PlatformStatusResp`)
// can be used when they are implemented.
let r: PlatformStatusResp = endpoint.query_async(&client).await.unwrap();
}
Here is another example that queries the Submit Funding Offer endpoint:
#[tokio::main]
async fn main() {
// 1. Instanciate an `AsyncClient`, this time providing credentials as we want to query an authenticated endpoint.
let client = AsyncBitfinex::new_auth(dotenv!("API_KEY"), dotenv!("SECRET_KEY"));
// 2. Build the endpoint using the builder pattern.
let endpoint = SubmitFundingOffer::builder()
.ty(FundingOrderType::Limit)
.symbol("fUSD")
.amount(150.)
.rate(0.009)
.period(2)
.build()
.unwrap();
// 3. Perform the query against the endpoint.
let r: SubmitFundingOfferResp = endpoint.query_async(&client).await.unwrap();
}
That's it ! That's the same pattern for all the endpoints that are implemented in the lib. Check out the examples directory for more info.
You might want to implement your own endpoints and your own return type for them (PRs are welcomed!).
Let's see how we can simply create a new Endpoint
from scratch. We're going to implement the Liquidations endpoint as an example.
- First we need to create the endpoint type:
// Create the endpoint struct which gather all the query / body params that are needed to perform
// the query. The optional parameters should be wrapped in `Option` types.
// NOTE: For convenience the `derive_builder` crate is used to easily build such types.
#[derive(Debug, Clone, Copy, Builder)]
#[builder(setter(strip_option))]
pub struct Liquidations {
#[builder(default)]
sort: Option<Sort>,
#[builder(default)]
start: Option<u64>,
#[builder(default)]
end: Option<u64>,
#[builder(default)]
limit: Option<u64>,
}
impl Liquidations {
pub fn builder() -> LiquidationsBuilder {
LiquidationsBuilder::default()
}
}
- Then we need to implement the
Endpoint
trait:
// Implement the `Endpoint` trait on our type.
impl Endpoint for Liquidations {
// The endpoint is a GET.
fn method(&self) -> Method {
Method::GET
}
// Give the endpoint path.
fn endpoint(&self) -> String {
String::from("v2/liquidations/hist")
}
// Provide the query parameters associated with this endpoint.
fn parameters(&self) -> QueryParams {
let mut params = QueryParams::default();
params
.push_opt("sort", self.sort.map(|sort| sort as i8))
.push_opt("start", self.start)
.push_opt("end", self.end)
.push_opt("limit", self.limit);
params
}
}
That's it ! We created a new endpoint that can now be used in our application to retrieve the liquidations.
In addition to creating endpoints you might want to create the return type that fits your own needs. Let's see how we can create our own LiquidationsResp
that only contains the fields we are interested in. For this example let's say we only need the POS_ID
, SYMBOL
and AMOUNT
fields from each liquidation item:
- Start by declaring the return type with the needed fields:
#[derive(Debug)]
pub struct LiquidationResp {
pub pos_id: u64,
pub symbol: String,
pub amount: f64,
}
- Then due to how Bitfinex API returns the repsonse we need to manually implement the
serde::Deserialize
trait:
impl<'de> Deserialize<'de> for LiquidationResp {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
// 1. Define the raw payload that is returned by the API.
// NOTE: This is a tuple struct! We need this because Bitfinex API responses are arrays
// of values instead of clean JSON objects.
#[derive(Debug, Deserialize)]
struct LiquidationRawResp(
String,
u64,
u64,
Option<()>,
String,
f64,
f64,
Option<()>,
u8,
u8,
Option<()>,
Option<f64>,
);
// 2. Implement the `From` trait to convert the raw type (`LiquidationRawResp` here)
// into the targeted one (`LiquidationResp` here).
impl From<LiquidationRawResp> for LiquidationResp {
fn from(value: LiquidationRawResp) -> Self {
// .1 Extract the desired fields.
let LiquidationRawResp(
_,
pos_id,
_,
_,
symbol,
amount,
_,
_,
_,
_,
_,
_,
) = value;
// .2 Build our response type.
Self {
pos_id,
symbol,
amount,
}
}
}
// 3. Deserialize the JSON payload into our `LiquidationRawResp`.
// NOTE: Due to the shape of the returned JSON in reality, this isn't exactly what's done
// if you look at the source code, but that's not important for the example.
let raw = LiquidationRawResp::deserialize(deserializer)?;
// 4. Finally convert the `LiquidationRawResp` into a `LiquidationResp`.
Ok(raw.into())
}
}
- Finally for convenience we can create a wrapper type like so:
pub type LiquidationsResp = Vec<LiquidationResp>;
- We can now use our endpoint allong with our newly created returned type:
#[tokio::main]
async fn main() {
// 1. Instanciate an `AsyncClient`.
let client = AsyncBitfinex::default();
// 2. Build the endpoint using the builder pattern.
let endpoint = Liquidations::builder()
.ty(FundingOrderType::Limit)
.symbol("fUSD")
.amount(150.)
.rate(0.009)
.period(2)
.build()
.unwrap();
// 3. Perform the query against the endpoint.
let r: LiquidationsResp = endpoint.query_async(&client).await.unwrap();
}
Feel free to dig in the individual endpoints source code (in the api/public
and api/authenticated
directories) to see how the implementations vary depending on the endpoint path, query and body parameters.
-
- Endpoint
PlatformStatus
- Return
PlatformStatus
- Endpoint
-
✅ Ticker
- Endpoint
Ticker
- Return
TickerResp
- Endpoint
-
✅ Tickers
- Endpoint
Tickers
- Return
TickersResp
- Endpoint
-
- Endpoint
TickersHistory
- Return
TickersHistoryResp
- Endpoint
-
✅ Trades
- Endpoint
Trades
- Return
TradesResp
- Endpoint
-
✅ Book
- Endpoint
Book
/RawBook
- Return
BookResp
/RawBookResp
- Endpoint
-
✅ Stats
- Endpoint
Stats
- Return
LastStatsResp
orHistStatsResp
- Endpoint
-
✅ Candles
- Endpoint
Candles
- Return
LastCandlesResp
orHistCandlesResp
- Endpoint
-
- Endpoint
DerivativeStatus
- Return
DerivativeStatusResp
- Endpoint
-
- Endpoint
DerivativesStatusHistory
- Return
DerivativesStatusHistoryResp
- Endpoint
-
- Endpoint
Liquidations
- Return
LiquidationsResp
- Endpoint
-
- Endpoint
Leaderboards
- Return
LastLeaderBoardResp
orHistLeaderBoardsResp
- Endpoint
-
- Endpoint
FundingStatistics
- Return
FundingStatisticsResp
- Endpoint
-
🔲 Configs
-
✅ Wallets
- Endpoint
Wallets
- Return
WalletsResp
- Endpoint
-
- Endpoint
RetrieveOrders
- Return
RetrieveOrdersResp
- Endpoint
-
- Endpoint
RetrieveOrdersBySymbol
- Return
RetrieveOrdersBySymbolResp
- Endpoint
-
- Endpoint
SubmitOrder
- Return
SubmitOrderResp
- Endpoint
-
- Endpoint
CancelOrder
- Return
CancelOrderResp
- Endpoint
-
- Endpoint
CancelOrders
- Return
CancelOrdersResp
- Endpoint
-
- Endpoint
OrdersHistory
- Return
OrdersHistoryResp
- Endpoint
-
✅ Trades
- Endpoint
Trades
- Return
TradesResp
- Endpoint
-
🔲 Ledgers
-
- Endpoint
ActiveFundingOffers
- Return
ActiveFundingOffersResp
- Endpoint
-
- Endpoint
SubmitFundingOffer
- Return
SubmitFundingOfferResp
- Endpoint
-
- Endpoint
CancelFundingOffer
- Return
CancelFundingOfferResp
- Endpoint
-
- Endpoint
CancelAllFundingOffers
- Return
CancelAllFundingOffersResp
- Endpoint
-
- Endpoint
FundingLoans
- Return
FundingLoansResp
- Endpoint
-
- Endpoint
FundingCredits
- Return
FundingCreditsResp
- Endpoint
-
- Endpoint
FundingInfo
- Return
FundingInfoResp
- Endpoint
-
🔲 Summary
-
✅ Balance Available for Orders/Offers
- Endpoint
BalanceAvailable
- Return
BalanceAvailableResp
- Endpoint