CoinAPI
Bitfinex Crypto Price Data
Introduction
The Bitfinex Crypto Price Data by CoinAPI is for Cryptocurrency price and volume data points. The data covers 383 Cryptocurrency pairs, starts in January 2013, and is delivered on any frequency from tick to daily. This dataset is created by monitoring the trading activity on Bitfinex.
For more information about the Bitfinex Crypto Price Data dataset, including CLI commands and pricing, see the dataset listing.
About the Provider
CoinAPI was founded by Artur Pietrzyk in 2016 with the goal of providing real-time and historical cryptocurrency market data, collected from hundreds of exchanges. CoinAPI provides access to Cryptocurrencies for traders, market makers, and developers building third-party applications.
Getting Started
The following snippet demonstrates how to request data from the Bitfinex Crypto Price dataset:
# Bitfinex accepts both Cash and Margin type account. self.set_brokerage_model(BrokerageName.BITFINEX, AccountType.CASH) self.set_brokerage_model(BrokerageName.BITFINEX, AccountType.MARGIN) self.btcusd = self.add_crypto("BTCUSD", Resolution.MINUTE, Market.BITFINEX).symbol self._universe = self.add_universe(CryptoUniverse.bitfinex(self.universe_selection_filter))
// Bitfinex accepts both Cash and Margin type account. SetBrokerageModel(BrokerageName.Bitfinex, AccountType.Cash); SetBrokerageModel(BrokerageName.Bitfinex, AccountType.Margin); _symbol = AddCrypto("BTCUSD", Resolution.Minute, Market.Bitfinex).Symbol; _universe = AddUniverse(CryptoUniverse.Bitfinex(UniverseSelectionFilter));
Data Summary
The following table describes the dataset properties:
Property | Value |
---|---|
Start Date | January 2013 |
Asset Coverage | 383 Currency Pairs |
Data Density | Dense |
Resolution | Tick, Second, Minute, Hourly, & Daily |
Timezone | UTC |
Market Hours | Always Open |
Requesting Data
To add Bitfinex Crypto Price data to your algorithm, call the AddCrypto
add_crypto
method. Save a reference to the Crypto Symbol
so you can access the data later in your algorithm.
class CoinAPIDataAlgorithm(QCAlgorithm): def initialize(self) -> None: self.set_start_date(2020, 6, 1) self.set_end_date(2021, 6, 1) self.set_cash(100000) # Bitfinex accepts both Cash and Margin type account. self.set_brokerage_model(BrokerageName.BITFINEX, AccountType.MARGIN) self.btcusd = self.add_crypto("BTCUSD", Resolution.MINUTE, Market.BITFINEX).symbol
namespace QuantConnect { public class CoinAPIDataAlgorithm : QCAlgorithm { private Symbol _symbol; public override void Initialize() { SetStartDate(2020, 6, 1); SetEndDate(2021, 6, 1); SetCash(100000); // Bitfinex accepts both Cash and Margin type account. SetBrokerageModel(BrokerageName.Bitfinex, AccountType.Margin); _symbol = AddCrypto("BTCUSD", Resolution.Minute, Market.Bitfinex).Symbol; } } }
For more information about creating Crypto subscriptions, see Requesting Data.
Accessing Data
To get the current Bitfinex Crypto Price data, index the Bars
bars
, QuoteBars
quote_bars
, or Ticks
ticks
properties of the current Slice
with the Crypto Symbol
. Slice
objects deliver unique events to your algorithm as they happen, but the Slice
may not contain data for your security at every time step. To avoid issues, check if the Slice
contains the data you want before you index it.
def on_data(self, slice: Slice) -> None: if self.btcusd in slice.bars: trade_bar = slice.bars[self.btcusd] self.log(f"{self.btcusd} close at {slice.time}: {trade_bar.close}") if self.btcusd in slice.quote_bars: quote_bar = slice.quote_bars[self.btcusd] self.log(f"{self.btcusd} bid at {slice.time}: {quote_bar.bid.close}") if self.btcusd in slice.ticks: ticks = slice.ticks[self.btcusd] for tick in ticks: self.log(f"{self.btcusd} price at {slice.time}: {tick.price}")
public override void OnData(Slice slice) { if (slice.Bars.ContainsKey(_symbol)) { var tradeBar = slice.Bars[_symbol]; Log($"{_symbol} price at {slice.Time}: {tradeBar.Close}"); } if (slice.QuoteBars.ContainsKey(_symbol)) { var quoteBar = slice.QuoteBars[_symbol]; Log($"{_symbol} bid at {slice.Time}: {quoteBar.Bid.Close}"); } if (slice.Ticks.ContainsKey(_symbol)) { var ticks = slice.Ticks[_symbol]; foreach (var tick in ticks) { Log($"{_symbol} price at {slice.Time}: {tick.Price}"); } } }
You can also iterate through all of the data objects in the current Slice
.
def on_data(self, slice: Slice) -> None: for symbol, trade_bar in slice.bars.items(): self.log(f"{symbol} close at {slice.time}: {trade_bar.close}") for symbol, quote_bar in slice.quote_bars.items(): self.log(f"{symbol} bid at {slice.time}: {quote_bar.bid.close}") for symbol, ticks in slice.ticks.items(): for tick in ticks: self.log(f"{symbol} price at {slice.time}: {tick.price}")
public override void OnData(Slice slice) { foreach (var kvp in slice.Bars) { var symbol = kvp.Key; var tradeBar = kvp.Value; Log($"{symbol} price at {slice.Time}: {tradeBar.Close}"); } foreach (var kvp in slice.QuoteBars) { var symbol = kvp.Key; var quoteBar = kvp.Value; Log($"{symbol} bid at {slice.Time}: {quoteBar.Bid.Close}"); } foreach (var kvp in slice.Ticks) { var symbol = kvp.Key; var ticks = kvp.Value; foreach (var tick in ticks) { Log($"{symbol} price at {slice.Time}: {tick.Price}"); } } }
For more information about accessing Crypto data, see Handling Data.
Historical Data
To get historical Bitfinex Crypto Price data, call the History
history
method with the Crypto Symbol
. If there is no data in the period you request, the history result is empty.
# DataFrame history_df = self.history(self.btcusd, 100, Resolution.DAILY) # TradeBar objects history_trade_bars = self.history[TradeBar](self.btcusd, 100, Resolution.MINUTE) # QuoteBar objects history_quote_bars = self.history[QuoteBar](self.btcusd, 100, Resolution.MINUTE) # Tick objects history_ticks = self.history[Tick](self.btcusd, timedelta(seconds=10), Resolution.TICK)
// TradeBar objects var historyTradeBars = History(_symbol, 100, Resolution.Daily); // QuoteBar objects var historyQuoteBars = History<QuoteBar>(_symbol, 100, Resolution.Minute); // Tick objects var historyTicks = History<Tick>(_symbol, TimeSpan.FromSeconds(10), Resolution.Tick);
For more information about historical data, see History Requests.
Universe Selection
To select a dynamic universe of Bitfinex Crypto pairs, call the AddUniverse
add_universe
method with a CryptoUniverse
object. A Crypto universe uses a selection function to select Crypto pairs based on their OHLCV and dollar volume of the previous day as of midnight Coordinated Universal Time (UTC).
def initialize(self) -> None: self.universe_settings.asynchronous = True self.set_brokerage_model(BrokerageName.BITFINEX, AccountType.MARGIN) self._universe = self.add_universe(CryptoUniverse.bitfinex(self.universe_selection_filter)) def universe_selection_filter(self, universe_day): return [c.symbol for c in universe_day if c.volume >= 100 and c.volume_in_usd > 10000]
public override void Initialize() { UniverseSettings.Asynchronous = True; SetBrokerageModel(BrokerageName.Bitfinex, AccountType.Margin); _universe = AddUniverse(CryptoUniverse.Bitfinex(UniverseSelectionFilter)); } private IEnumerable<Symbol> UniverseSelectionFilter(IEnumerable<CryptoUniverse> universeDay) { return from c in universeDay where c.Volume >= 100m && c.VolumeInUsd > 10000m select c.Symbol; }
For more information about universe settings, see Settings.
Universe History
You can get historical universe data in an algorithm and in the Research Environment.
Historical Universe Data in Algorithms
To get historical universe data in an algorithm, call the History
history
method with the Universe
object, and the lookback period. If there is no data in the period you request, the history result is empty.
var history = History(_universe, 30, Resolution.Daily); foreach (var universeDay in history) { foreach (CryptoUniverse universeItem in universeDay) { Log($"{universeItem.Symbol} price at {universeItem.EndTime}: {universeItem.Close}"); } }
# DataFrame example where the columns are the CryptoUniverse attributes: history_df = self.history(self._universe, 30, Resolution.DAILY, flatten=True) # Series example where the values are lists of CryptoUniverse objects: history = self.history(self._universe, 30, Resolution.DAILY) for (univere_symbol, time), universe_day in history.items(): for universe_item in universe_day: self.log(f"{universe_item.symbol} price at {universe_item.end_time}: {universe_item.close}")
Historical Universe Data in Research
To get historical universe data in research, call the UniverseHistory
universe_history
method with the Universe
object, and the lookback period. The UniverseHistory
universe_history
returns the filtered universe. If there is no data in the period you request, the history result is empty.
var universeHistory = qb.UniverseHistory(universe, qb.Time.AddDays(-30), qb.Time); foreach (var universeDay in universeHistory) { foreach (CryptoUniverse universeItem in universeDay) { Console.WriteLine($"{universeItem.Symbol} price at {universeItem.EndTime}: {universeItem.Close}"); } }
# DataFrame example where the columns are the CryptoUniverse attributes: history_df = qb.universe_history(universe, qb.time-timedelta(30), qb.time, flatten=True) # Series example where the values are lists of CryptoUniverse objects: universe_history = qb.universe_history(universe, qb.time-timedelta(30), qb.time) for (univere_symbol, time), universe_day in universe_history.items(): for universe_item in universe_day: print(f"{universe_item.symbol} price at {universe_item.end_time}: {universe_item.close}")
You can call the History
history
method in Research.
Remove Subscriptions
To unsubscribe from a Crypto pair that you added with the AddCrypto
add_crypto
method, call the RemoveSecurity
remove_security
method.
self.remove_security(self.btcusd)
RemoveSecurity(_symbol);
The RemoveSecurity
remove_security
method cancels your open orders for the security and liquidates your holdings in the virtual pair.
Data Points Attributes
The Bitfinex Crypto Price dataset provides TradeBar
, QuoteBar
, Tick
, and CryptoUniverse
objects.
TradeBar Attributes
TradeBar
objects have the following attributes:
QuoteBar Attributes
QuoteBar
objects have the following attributes:
Tick Attributes
Tick
objects have the following attributes:
CryptoUniverse Attributes
CryptoUniverse
objects have the following attributes:
Example Applications
The Bitfinex Crypto Price dataset enables you to accurately design strategies for Cryptocurrencies. Examples include the following strategies:
- Buy and hold
- Trading Cryptocurrency volatility and price action
- Allocating a small portion of your portfolio to Cryptocurrencies to hedge against inflation
Classic Algorithm Example
The following example algorithm buys and holds Bitcoin through the Bitfinex exchange:
from AlgorithmImports import * from QuantConnect.DataSource import * from QuantConnect.Data.UniverseSelection import * class CoinAPIDataAlgorithm(QCAlgorithm): def initialize(self) -> None: self.set_start_date(2020, 6, 1) self.set_end_date(2021, 6, 1) self.set_cash(100000) self.universe_settings.asynchronous = True # Bitfinex accepts both Cash and Margin account types, select the one you need for the best reality modeling. self.set_brokerage_model(BrokerageName.BITFINEX, AccountType.MARGIN) # Warm up the security with the last known price to avoid conversion error self.set_security_initializer(lambda security: security.set_market_price(self.get_last_known_price(security))) # Requesting data, we only trade on BTCUSD in Bitfinex exchange crypto = self.add_crypto("BTCUSD", Resolution.MINUTE, Market.BITFINEX) self.btcusd = crypto.symbol self.minimum_order_size = crypto.symbol_properties.minimum_order_size # Historical data history = self.history(self.btcusd, 30, Resolution.DAILY) self.debug(f"We got {len(history)} items from our history request") # Add Crypto Universe Selection that select crypto pairs in Bitfinex exchange self._universe = self.add_universe(CryptoUniverse.bitfinex(self.universe_selection_filter)) # Historical Universe data universe_history = self.history(self._universe, 30, Resolution.DAILY) self.debug(f"We got {len(universe_history)} items from our universe history request") for (univere_symbool, time), universe_day in universe_history.items(): for universe_item in universe_day: self.debug(f"{universe_item.symbol} price at {universe_item.end_time}: {universe_item.close}") def universe_selection_filter(self, universe_day): # Filter for materially traded crypto pairs with significant size and dollar volume, assuming higher capital flow in for higher return return [universe_item.symbol for universe_item in universe_day if universe_item.volume >= 100 and universe_item.volume_in_usd > 10000] def on_data(self, slice: Slice) -> None: # Speculate-invest all available free cash on BTCUSD, obeying the order quantity restriction to avoid invalid order if self.portfolio.cash_book['BTC'].amount == 0: free_cash = self.portfolio.cash_book['USD'].amount * (1-self.settings.free_portfolio_value_percentage) quantity = free_cash / slice[self.btcusd].price quantity -= quantity % self.minimum_order_size if quantity > 0: self.market_order(self.btcusd, quantity)
using QuantConnect.DataSource; using QuantConnect.Data.UniverseSelection; namespace QuantConnect { public class CoinAPIDataAlgorithm : QCAlgorithm { private Symbol _btcusd; private decimal? _minimumOrderSize; public override void Initialize() { SetStartDate(2020, 6, 1); SetEndDate(2021, 6, 1); SetCash(100000); UniverseSettings.Asynchronous = True; // Bitfinex accepts both Cash and Margin account types, select the one you need for the best reality modeling. SetBrokerageModel(BrokerageName.Bitfinex, AccountType.Margin); // Warm up the security with the last known price to avoid conversion error SetSecurityInitializer(security => security.SetMarketPrice(GetLastKnownPrice(security))); // Requesting data, we only trade on BTCUSD in Bitfinex exchange var crypto = AddCrypto("BTCUSD", Resolution.Minute, Market.Bitfinex); _btcusd = crypto.Symbol; _minimumOrderSize = crypto.SymbolProperties.MinimumOrderSize; // Historical data var history = History(_btcusd, 30, Resolution.Daily); Debug($"We got {history.Count()} items from our history request"); // Add Crypto Universe Selection that select crypto pairs in Bitfinex exchange _universe = AddUniverse(CryptoUniverse.Bitfinex(UniverseSelectionFilter)); // Historical Universe data var universeHistory = History(_universe, 30, Resolution.Daily); Debug($"We got {universeHistory.Count()} items from our history request"); foreach (var universeDay in universeHistory) { foreach (CryptoUniverse universeItem in universeDay) { Debug($"{universeItem.Symbol} price at {universeItem.EndTime}: {universeItem.Close}"); } } } private IEnumerable<Symbol> UniverseSelectionFilter(IEnumerable<CryptoUniverse> universeDay) { // Filter for materially traded crypto pairs with significant size and dollar volume, assuming higher capital flow in for higher return return from universeItem in universeDay where universeItem.Volume >= 100m && universeItem.VolumeInUsd > 10000m select universeItem.Symbol; } public override void OnData(Slice slice) { # Speculate-invest all available free cash on BTCUSD, obeying the order quantity restriction to avoid invalid order if (Portfolio.CashBook["BTC"].Amount == 0) { var freeCash = Portfolio.CashBook["USD"].Amount * (1-Settings.FreePortfolioValuePercentage); var quantity = freeCash / slice[_btcusd].Price; quantity -= quantity % _minimumOrderSize; if (quantity > 0m) { MarketOrder(_btcusd, quantity); } } } } }
Framework Algorithm Example
The following example algorithm creates a dynamic universe of Crypto pairs on the Bitfinex exchange and then forms a equal-weighted portfolio of all the pairs in the universe:
from AlgorithmImports import * from QuantConnect.DataSource import * from QuantConnect.Data.UniverseSelection import * class CoinAPIDataAlgorithm(QCAlgorithm): def initialize(self) -> None: self.set_start_date(2020, 6, 1) self.set_end_date(2021, 6, 1) self.set_cash(100000) # Bitfinex accepts both Cash and Margin account types, select the one you need for the best reality modeling. self.set_brokerage_model(BrokerageName.BITFINEX, AccountType.MARGIN) # Warm up the security with the last known price to avoid conversion error self.set_security_initializer(lambda security: security.set_market_price(self.get_last_known_price(security))) self.universe_settings.asynchronous = True self.universe_settings.resolution = Resolution.MINUTE # Add Crypto Universe Selection that select crypto pairs in Bitfinex exchange self.add_universe(CryptoUniverse.bitfinex(self.universe_selection_filter)) self.add_alpha(ConstantAlphaModel(InsightType.PRICE, InsightDirection.UP, timedelta(minutes = 20), 0.025, None)) # Equally invest to evenly dissipate the capital concentration risk of inidividual crypto pair self.set_portfolio_construction(EqualWeightingPortfolioConstructionModel()) def universe_selection_filter(self, universe_day: List[CryptoUniverse]) -> List[Symbol]: # Filter for materially traded crypto pairs with significant dollar volume, assuming higher capital flow in for higher return return [universe_item.symbol for universe_item in universe_day if universe_item.volume_in_usd > 50000000] def on_securities_changed(self, changes: SecurityChanges) -> None: for security in changes.added_securities: # Historical data history = self.history(security.symbol, 30, Resolution.DAILY) self.debug(f"We got {len(history)} items from our history request")
using QuantConnect.DataSource; using QuantConnect.Data.UniverseSelection; namespace QuantConnect { public class CoinAPIDataAlgorithm : QCAlgorithm { private Symbol _btcusd; public override void Initialize() { SetStartDate(2020, 6, 1); SetEndDate(2021, 6, 1); SetCash(100000); // Bitfinex accepts both Cash and Margin account types, select the one you need for the best reality modeling. SetBrokerageModel(BrokerageName.Bitfinex, AccountType.Margin); // Warm up the security with the last known price to avoid conversion error SetSecurityInitializer(security => security.SetMarketPrice(GetLastKnownPrice(security))); UniverseSettings.Asynchronous = True; UniverseSettings.Resolution = Resolution.Minute; // Add Crypto Universe Selection that select crypto pairs in Bitfinex exchange AddUniverse(CryptoUniverse.Bitfinex(UniverseSelectionFilter)); AddAlpha( new ConstantAlphaModel(InsightType.Price, InsightDirection.Up, TimeSpan.FromMinutes(20), 0.025, None) ); // Equally invest to evenly dissipate the capital concentration risk of inidividual crypto pair SetPortfolioConstruction(new EqualWeightingPortfolioConstructionModel()); } private IEnumerable<Symbol> UniverseSelectionFilter(IEnumerable<CryptoUniverse> universeDay) { // Filter for materially traded crypto pairs with significant dollar volume, assuming higher capital flow in for higher return return from universeItem in universeDay where universeItem.VolumeInUsd > 50000000m select universeItem.Symbol; } public override void OnSecuritiesChanged(SecurityChanges changes) { foreach(var security in changes.AddedSecurities) { // Historical data var history = History(security.Symbol, 30, Resolution.Daily); Debug($"We got {history.Count()} items from our history request"); } } } }
Research Example
The following example lists crypto-currency pairs with the greatest dollar volume in the Bitfinex exchange:
var qb = new QuantBook(); // Add Cryptocurrency pair var symbol = qb.AddCrypto("BTCUSDT", market:Market.Bitfinex).Symbol; // Historical data var history = qb.History(symbol, 30, Resolution.Daily); foreach (var bar in history) { Console.WriteLine($"{bar.EndTime} {bar}"); } // Add Crypto Universe Selection IEnumerable<Symbol> UniverseSelectionFilter(IEnumerable<CryptoUniverse> universeDay) { return universeDay .Where(x => x.VolumeInUsd != None && x.VolumeInUsd > 10000m) .OrderByDescending(x => x.VolumeInUsd) .Take(5) .Select(x => x.Symbol); } var universe = qb.AddUniverse(CryptoUniverse.Bitfinex(UniverseSelectionFilter)); // Historical Universe data var universeHistory = qb.UniverseHistory(universe, qb.Time.AddDays(-30), qb.Time); foreach (var universeDay in universeHistory) { Console.WriteLine($"=== {universeDay.First().EndTime} ==="); foreach (CryptoUniverse universeItem in universeDay.OrderByDescending(x => x.VolumeInUsd)) { Console.WriteLine($"{universeItem.Symbol}: {universeItem.VolumeInUsd}"); } }
qb = QuantBook() # Add Cryptocurrency pair symbol = qb.add_crypto("BTCUSDT", market=Market.BITFINEX).symbol # Historical data history = qb.history(symbol, 30, Resolution.DAILY) for (symbol, time), row in history.iterrows(): print(f'{time} {symbol} {row.close}') # Add Crypto Universe Selection def universe_selection_filter(universe_day): selected = sorted([x for x in universe_day if x.volume_in_usd and x.volume_in_usd > 10000], key=lambda x: x.volume_in_usd, reverse=True)[:5] return [x.symbol for x in selected] universe = qb.add_universe(CryptoUniverse.bitfinex(universe_selection_filter)) # Historical Universe data history = qb.universe_history(universe, qb.time-timedelta(30), qb.time) for (univere_symbol, time), universe_day in history.items(): print(f'=== {time} ===') for universe_item in sorted(universe_day, key=lambda x: x.volume_in_usd, reverse=True): print(f"{universe_item.symbol}: {universe_item.volume_in_usd}")
Data Point Attributes
The Bitfinex Crypto Price dataset provides TradeBar
, QuoteBar
, Tick
, and CryptoUniverse
objects.
TradeBar Attributes
TradeBar
objects have the following attributes:
QuoteBar Attributes
QuoteBar
objects have the following attributes:
Tick Attributes
Tick
objects have the following attributes:
CryptoUniverse Attributes
CryptoUniverse
objects have the following attributes: