9.6 KiB
System
The entire system is called bisq arbitrage system (bas for friends).
bas is composed of several independent daemons, libraries, human-operators, etc. It works in a mostly automated way, with the exception of manual input for fiat bank-related tasks and confirmations.
bas components communicate through a pub-sub broker. This broker also acts as the single point of truth to keep state and data. The entire balances are re-buildable from it, as well as other statistics about the trades.
This documents shows the main components of the system and how they interact with each other.
- bisq daemon
- TheFilter
- TheComposer
- TheTrader
- TheLedger
- TheTeller
Components Summary
bisq daemon
The bisq daemon is the actual bisq client + wallet. It handles the relationship with the network and holds BTC. It exposes itself as a grpc API which the other components of the system leverage to interact with the network and obtain information.
TheFilter
TheFilter is a daemon that is constantly pulling the available and relevant TradeOffers from bisq markets. The high level logic looks roughly like this:
while True:
all_offers = get_all_offers()
relevant_offers = filter_only_relevant_offers(all_offers)
store_offers(relevant_offers)
sleep(5000)
The definition of what is a relevant TradeOffer can be configured.
TheFilter stores the relevant offer snapshot on TheLedger on each iteration in a file, making it accessible to other services.
TheComposer
TheComposer is a daemon that tries to build ArbitrageComboPlans and store them in TheLedger. The high level logic looks roughly like this:
while True:
if not new_offers_available():
sleep(5000)
next
last_offers_snapshot = get_last_offers_snapshot()
juicy_combos = compose_combos_from_offers(last_offers_snapshot)
if juicy_combos:
store_combos(juicy_combos)
TheComposer is tasked with a hard optimization problem. To come up with the combos, it needs three pieces of information: the TradeOffers, the JuicyDefinition and the state of the fiat and BTC balances.
The TradeOffers come from TheFilter.
The JuicyDefinition is a configuration that specifies certain conditions that an ArbitrageComboPlan must meet in order to be considered "juicy" (lucrative) enough to be worth pursuing.
To obtain the state of fiat and BTC balances, TheComposers sends requests to TheTeller.
If a juicy ArbitrageComboPlan is obtained, it is sent to TheLedger. TheComposer itself does not take action to execute it.
TheTrader
TheTrader is a daemon that executes trades. It reads proposed ArbitrageComboPlans from TheLedger and interacts with the bisq deamon to commit the trades.
The high level logic looks roughly like this for commiting trades:
while True:
while not available_combo():
sleep(5000)
next
combo_to_execute = get_combo_to_execute()
if trade_offers_still_available(combo_to_execute):
commit_combo(combo_to_execute)
And like this for confirming fiat payments:
while True:
while not pending_payment_confirmations():
sleep(5000)
next
pending_payment_confirmation = get_pending_payment_confirmation()
confirm_payment(pending_payment_confirmation)
TheTrader acts as the interaction layer with the actual trading in bisq. It is responsible both for initially commiting the TradeOffers, as well as for sending confirming of fiat payments to the trading peers.
TheLedger
The Ledger is a pub/sub message broker that acts both as a communication tool between the different components of bas, as well as the data storage solution. It records all relevant events of the system.
It contains the following topics:
- TradeOffers: where all the available snapshots of the relevant TradeOffers in the market are shared.
- ArbitrageComboPlans: where all the combos composed from different TradeOffers are shared.
- TradeStates
- ComboStates
- EURBalance: where all the events that modify the balance of euros are shared. The final state of the balance can be reconstructed from this.
- BTCBalance: where all the events that modify the balance of (free) bitcoin are shared. The final state of the balance can be reconstructed from this.
- LockedBTCBalance: where all the events that modify the balance of (locked) bitcoin are shared. Locked bitcoin is the amount that gets stuck in escrow while
- BSQBalance: where all the events that modify the balance of BSQ are shared. The final state of the balance can be reconstructed from this.
TheOperator
TheOperator is not a piece of software, but a human being.
In all the arbitrage combos that happen, there will be some fiat payments to make and to receive. These need human intervention: in the case of the fiat payment, someone needs to actually make the payment and confirm this has been done, and someone needs to be monitoring the arrival of the received fiat and confirm once it reaches.
Paying and monitoring received payments is outside of the scope of bas, but the system needs to know about these events to update the state of trades and balances.
To achieve this, TheOperator delivers messages in TheLedger. How this should be done is still not specified, although some kind of CLI seems like the best idea.
TheTeller
TheTeller is a small library that can be used to query the state of balances. Balances need to be built by sequentially running through the relevant events in TheLedger. TheTeller encapsules this behaviour and provides a unified view on how much is there in each balance.
Data flow
Although the system does not have a linear nature, looking at the flow of data in a naive, linear way helps understanding all the moving parts.
All the data flow, from beginning to end, looks like this:
- The bisq daemon is constantly running and interacting with the bisq network.
- TheFilter polls the bisq daemon frequently to obtain all the available TradeOffers. It then sends back to TheLedger the relevant ones.
- TheComposer picks up the relevant TradeOffers from TheLedger and attempts to compose ArbitrageComboPlans. When it succeeds in doing so, it sends the ArbitrageComboPlan details back to TheLedger.
- TheTrader picks any ArbitrageComboPlan that appears in TheLedger ASAP. It publishes the state of the different trades and the combo as a whole in TheLedger. It also updates the BTCBalance, transfering the deposit bitcoin to the LockedBTCBalance.
- TheOperator posts confirmations of the fiat payments, both made and received, to TheLedger.
- TheTrader relays the confirmations to the bisq peers and keeps on updating the states of the trades and balances until the combo is finished.
- TheOperator can use TheTeller at any given time to check the state of the balances. If there is an mismatch between the balances and reality, it can also be used to include corrective entries to reconcile both.
Configuration and decisions to be made
- Available payment accounts: bas can only operate on trades with the passed fiat payment accounts. These accounts are needed to limit the TradeOffers which are relevant.
- Fiat balance starting point: a first entry in TheLedger must define what is the starting balance.
- Prefered trades: a more complex definition which specifies which TradeOffers should be considered relevant and which ones should be ignored. These include:
- Minimum and maximum fiat value.
- Minimum premium %.
- Prefered combos: a series of conditions that an ArbitrageComboPlan must meet to be considered interesting enough to be executed.
- Prefered balance state: a series on restrictions on how should balances look like. This is to avoid the balance to shift completely into a single currency. This definition specifies thresholds that should not be exceeded by a specific currency in the system. For example, that the TotalPortfolioValue in BTC should stay between 25% and 75% percent of the CurrencyPortfolio. If an ArbitrageCombo shifts the balances outside of the allowed ranges, it won't be executed.
Operation
Risks and mitigations
- Trades becoming unavailable
- Combo not being executed atomically
- Failure to perform fiat payment
Glossary
-
TradeOffer: A TradeOffer is a public commitment from a bisq participant (the maker) to engage in a trade with certain conditions. The trade is binding, meaning that once someone takes it (the taker), the maker is forced into executing it. You can picture the maker's offer as a contract with his signature on it. Anyone can sign the taker spot and start the binding transaction. A trade offer contains, at least, the following details:
- A BTC amount.
- A secondary currency amount.
- A price (which is obviously the proportion between the previous two)
- The role for each currency (what is the maker giving away and what is taker giving away)
- A payment method for the secondary currency
- A taker security deposit in BTC, which gets returned after the trade is succesful
- A bisq trading fee, which can be paid in either BSQ or BTC
- A mining fee, which can only be paid in BTC
-
ArbitrageCombo: An ArbritrageCombo is a series of buys and sells in one or several BTC-XXX markets executed with the hope that TotalPortfolioValue is larger at the end of the ArbitrageCombo.
If markets were perfect, it would be impossible to run a profitable ArbitrageCombo. The expected gain of any ArbitrageCombo would be 0 (ignoring fees. If fees are taken into account, it would be negative). Given that we know that markets are definetely not perfect, there should be a certain degree of hope in finding profitable. Whether market imperfection is enough to make a nice amount of money out of it is uncertain.
-
ArbitrageComboPlan: an ArbitrageComboPlan is simply a possible ArbitrageCombo that hasn't been committed yet.