xtr is a trading engine. xtr is an experimental development.
At the moment, xtr only supports cash instruments trading, LIMIT orders, and everything is stored in the memory, and not persisted.
Engine is the core of the trading system. Engine is responsible for executing user operations and queries.
Instrument is a tradeable asset. It can be stock or currency.
xtr identifies instruments simply by their codes.
Market is a place where one kind of asset is traded for another. For example, a place where you can trade EUR for CNY or AAPL for USD is a market.
There are two types of markets and they have different schemes of their identifiers.
Currency markets are identified by a currency pair (e.g. BTC/USD, BTC/EUR).
Stock markets are identified by a stock ticker prepended with currency code (e.g. USD:AAPL, EUR:GOOG, BTC:V).
Account is a collection of balances in different instruments. It is
identified by a UUID string returned from engine.account
.
Each balance has available and reserved amounts.
To get started, you would need to instantiate an engine and specify instruments you want it to support. Instruments are broken down by category. At the moment, xtr supports currency, stock, and resource instruments:
engine = Xtr::Engine.new do |c|
c.currency :BTC, :USD
c.stock :AAPL, :TWTR
c.resource :SILVER
end
Engine will then create markets for described instruments. By default, it will create a market for each pair of currencies and a market for each stock in every supported currency.
In this example, the following markets will be generated:
-
currency
- BTC/USD
- BTC/EUR
-
stock
- BTC:AAPL
- USD:AAPL
- BTC:TWTR
- USD:TWTR
- EUR:TWTR
-
resource
- BTC:SILVER
- USD:SILVER
engine.query :MARKETS
# => [
# { name: "BTC/USD", type: :currency },
# { name: "USD:AAPL", type: :stock }
# ]
To get a ticker for a market, simply issue a TICKER query with market code as an argument:
engine.query :TICKER, 'EUR:GOOG'
# => { bid: 499.90, ask: 500.30, last_price: 500.10 }
To create an account, just call:
account = engine.new_account
It will return account ID. You will need it to manage balances and orders.
Crediting and debiting account balances is easy — just pass account ID, instrument name and amount:
# Crediting
engine.execute :DEPOSIT, account, "USD", 100_000.00
engine.query :BALANCE, account, "USD"
# => { currency: USD, available: 100_000.00, reserved: 0.00 }
# Debiting
engine.execute :WITHDRAW, account, "USD", 25_000.00
engine.query :BALANCE, account, "USD"
# => { currency: USD, available: 75_000.00, reserved: 0.00 }
engine.query :BALANCES, account
# => [{
# instrument: 'AAPL',
# available: 10,
# reserved: 5
# }]
To create an order, execute BUY/SELL operation with account ID, market code, price, and quantity as arguments:
(Only LMT orders are supported currently.)
engine.execute :BUY, account, "BTC/USD", 999.99, 10
engine.execute :SELL, account, "EUR:AAPL", 600, 25
When the orders are matched, balance transfers are performed between the accounts.
To cancel an order, execute CANCEL operation, passing account ID and order ID:
engine.execute :CANCEL, account, order
You can query open orders for a particular account this way:
engine.query :OPEN_ORDERS, account
# => [{
# id: 'uuid',
# market: 'BTC/USD',
# direction: :buy,
# price: 999.99,
# quantity: 10,
# remainder: 5,
# status: :partially_filled,
# created_at: Time
# }]
It's possible to have xtr journal every user operation and replay the log when the engine restarts.
By default, xtr does not journal anything. You can configure it to journal to a file:
engine = Xtr::Engine.new do |c|
# instrument descriptions
c.journal :file, "path/to/file.journal"
end
And make sure to replay the log right after initializing the engine:
engine.replay
By default, xtr would generate markets for all currency pairs, and for all stock-currency and resource-currency pairs. You can customize it though.
All you need to do is to pass market generators to the engine initializer.
Market generator is a proc that takes a list of instruments in specific category (currency, stock, resource) and a hash of all instruments and returns an array of instrument pair.
The default generators are like this:
currency_gen = -> list, _ { list.combination(2) } # currency pairs
stock_gen = -> list, inst { list.product(inst[:currency]) } #
stock-currency pairs; resource gen is the same
You can set your own generators:
engine = Xtr::Engine.new do |c|
# instruments...
c.stock_markets { |list, _| list.product([:USD]) }
end
- margin trading
- other order types (market, stop-loss, take-profit, fill-or-kill)
- derivative instruments (CFDs, futures, options)
- event sourcing & persistence
- snapshots