Skip to content

xenoliss/bitfinex-api

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

48 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

bitfinex-api

Another unofficial Rust Library for the Bitfinex API V2.

Installation

Add the lib as a project dependency in you Cargo.toml.

[dependencies]
bitfinex-api = { git = "https://github.com/xenoliss/bitfinex-api" }

Basic Usage

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. Default Bitfinex/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 implement Endpoint and expose the query / query_async methods in which the Client / 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.

Advanced Usage

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.

Implemented Endpoints

Public Endpoints

  • Platform Status

    • Endpoint PlatformStatus
    • Return PlatformStatus
  • Ticker

    • Endpoint Ticker
    • Return TickerResp
  • Tickers

    • Endpoint Tickers
    • Return TickersResp
  • Tickers History

    • Endpoint TickersHistory
    • Return TickersHistoryResp
  • Trades

    • Endpoint Trades
    • Return TradesResp
  • Book

    • Endpoint Book / RawBook
    • Return BookResp / RawBookResp
  • Stats

    • Endpoint Stats
    • Return LastStatsResp or HistStatsResp
  • Candles

    • Endpoint Candles
    • Return LastCandlesResp or HistCandlesResp
  • Derivatives Status

    • Endpoint DerivativeStatus
    • Return DerivativeStatusResp
  • Derivatives Status History

    • Endpoint DerivativesStatusHistory
    • Return DerivativesStatusHistoryResp
  • Liquidations

    • Endpoint Liquidations
    • Return LiquidationsResp
  • Leaderboards

    • Endpoint Leaderboards
    • Return LastLeaderBoardResp or HistLeaderBoardsResp
  • Funding Statistics

    • Endpoint FundingStatistics
    • Return FundingStatisticsResp
  • 🔲 Configs

Authenticated Endpoints

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages