-
Notifications
You must be signed in to change notification settings - Fork 1.9k
Design Notes
The intention to is allow clients to connect to a wide range of exchanges offering trade opportunities. This is not limited to Bitcoin, although the first exchange implementation happens to use the BTC currency due to market demand.
Two approaches were considered: fully self-contained, or extensible. Existing APIs addressing similar problems (such as JDBC for relational databases) demonstrated that the extensible approach is the better choice. This implied that XChange should provide a collection of interfaces that someone will need to implement for their exchange. Clearly, XChange will initially create early versions of these providers, but eventually it is hoped that exchange owners themselves will contribute them. This is actively encouraged.
The following are the main components that developers will interact with, typically in the order presented below. These classes are all in xchange-core
in the com.xeiam.xchange
package.
This provides all the configuration for the Exchange including the implementor class name, authentication credentials, API secret keys and so on. Passing this to the ExchangeFactory will result in a suitable configured Exchange to work with.
Is responsible for creating Exchange implementations based on details provided in the ExchangeSpecification.
The main point of interaction. This interface provided to consuming applications, which will use this to access the various services supported by the exchange by calling one of the supporting getters. Exchanges may implement this interface by extending BaseExchange
.
Exchange metadata such as currency pairs, max polling rates, scaling factors, fees, minimum amounts etc. is loaded and stored at the Exchange
level as opposed to the Service
level. The information is loaded at the time of the creation of the exchange, and is stored in a ExchangeMetaData
object. A convenience method List<CurrencyPair> getExchangeSymbols()
is provided to just access the CurrencyPair
s. ExchangeMetaData getExchangeMetaData()
can be called to get all the meta data.
Since different exchange provide different amounts of meta data via an API call ranging from none to everything (can be all in one API endpoint or a combination of several API endpoints), XChange handles this in the following way:
- During creation of the
Exchange
, a JSON file is loaded from the classpath, which is a hardcoded JSON structure containing the exchange's meta data. This is usually provided for exchanges that don't provide meta data via an API endpoint or they provide just limited data. - During creation of the
Exchange
, a path to a JSON file can be given to override the default JSON file shipped with XChange. You may want to provide your own metadata file for several reasons including a) the shipped JSON file is outdated, b) you want to tweak the data for various reasons or c) the shipped JSON file is incomplete. - During creation of the
Exchange
,remoteInit()
is called. The exact implementation of this method can vary between exchanges, but the main idea is to load the meta data via remote API calls, to build theExchangeMetaData
. The implementations are encouraged to override the data loaded via the hard-coded JSON file and supplement data from the JSON file when/if it is missing from the API endpoint calls.
Code that needs the meta data should call the access methods on the Exchange
object.
-
BasePollingService
PollingMarketDataService
PollingTradeService
PollingAccountService
StreamingExchangeService
Interfaces which are the entry point to an exchange service (e.g. listing market prices against a particular symbol etc), could be synchronous (blocking) or asynchronous (non-blocking) depending on the requirement.
Implementations of these service extend provided core base classes:
-
BaseExchangeService
BasePollingExchangeService
BaseWebSocketExchangeService
A service is encouraged to have two implementations, one which provides the raw data from the exchange, and one which coerces this data into standard DTOs and implements one of the Service interfaces.
Standard DTOs for encoding a message to and from the exchange. Treated as immutable. Note that null timestamps are common and not a bug. Timestamps in DTOs represent a timestamp given from the server's JSON response, and if it's not given, the DTO contains a null timestamp.
The REST client that XChange uses is ResCU, which was originally integrated directly into XChange, but later split off into it's own separate library. One nice feature that was later integrated into ResCU is nonce handling, required by many exchanges. The nonce factory used to create a nonce value. Allows services to accept a placeholder that is replaced with generated value just before message is serialized and sent. If a method of a rest accepts ValueFactory as a parameter, it's evaluated, the message is serialized and sent in a single synchronized block.
If required by the exchange, the XChange implementation should preferably use SynchronizedValueFactory
. This requires two steps:
- In the exchange's
BaseExchange
implementation (seeANXExchange
for example) thegetNonceFactory()
should be implemented and a concreteSynchronizedValueFactory<T>
instance should be returned. There are manySynchronizedValueFactory<T>
implementations to chose from incom.xeiam.xchange.utils.nonce
. - In the REST interface class (see
ANXV2
for example) theSynchronizedValueFactory<T>
implementation should be passed as a parameter.
Each BaseExchange
implementation hard-codes a SynchronizedValueFactory<T>
instance. If you want to change the SynchronizedValueFactory<T>
instance used, you'll need to create your own subclass of BaseExchange
and provide your preferred SynchronizedValueFactory<T>
instance by overriding the getNonceFactory()
method to your liking, using a different nonce factory provided in com.xeiam.xchange.utils.nonce
or one of your own implementations.
div
{
color: white;
background-color: 009900;
margin: 2px;
font-size: 25px;
}
span
{
color: black;
background-color: gray;
margin: 5px;
font-size: 25px;
}
</style>
<div> div tag </div>
<div> div tag </div>
<div> div tag </div>
<div> div tag </div>
<span>span-tag</span>
<span>span-tag</span>
<span>span-tag</span>
<span>span-tag</span>