XChange代码阅读
Exchange接口
Exchange是XChange APIs的入口点。Exchange定义的方法用来获取基础数据和服务层。基础数据方面,包括获取ExchangeSpecification和特定交易所的默认ExchangeSpecification,交易所元数据ExchangeMetaData,交易对列表CurrencyPair。服务层包括:MarketDataService,TradeService,AccountService。
Exchange接口定义了10个方法:
public interface Exchange {
ExchangeSpecification getExchangeSpecification();
ExchangeSpecification getDefaultExchangeSpecification();
void applySpecification(ExchangeSpecification exchangeSpecification);
ExchangeMetaData getExchangeMetaData();
List<CurrencyPair> getExchangeSymbols();
SynchronizedValueFactory<Long> getNonceFactory();
MarketDataService getMarketDataService();
TradeService getTradeService();
AccountService getAccountService();
void remoteInit() throws IOException, ExchangeException;
}
getExchangeSpecification方法返回交易所正在使用的ExchangeSpecification对象,getExchangeSpecification方法的实现在抽象类BaseExchange中,只是一个简单的公开BaseExchange中的exchangeSpecification属性的操作。
getDefaultExchangeSpecification和getExchangeSpecification一样都是返回一个ExchangeSpecification对象,但是,getDefaultExchangeSpecification的实现是在各个交易所模块里面,比如:BinanceExchange。在这个方法里面,首先创建一个默认的ExchangeSpecification对象,然后还可以修改交易所的某些特定属性。例如:
@Override
public ExchangeSpecification getDefaultExchangeSpecification() {
ExchangeSpecification spec = new ExchangeSpecification(this.getClass().getCanonicalName());
spec.setSslUri("https://api.binance.com");
spec.setHost("www.binance.com");
spec.setPort(80);
spec.setExchangeName("Binance");
spec.setExchangeDescription("Binance Exchange.");
AuthUtils.setApiAndSecretKey(spec, "binance");
return spec;
}
applySpecification方法在BaseExchange类中实现。方法执行顺序:
- 先以传入的ExchangeSpecification参数为基础,补充getDefaultExchangeSpecification方法得到的属性,得到一个完整的ExchangeSpecification。
- 调用自定义json文件,或者调用默认的类路径json文件。
- 初始化三个服务类。
- 执行remoteInit,获取远程MetaData数据,remoteInit的实现在各个交易所模块内实现。
remoteInit方法用来使用远程元数据初始化实例。大多数交易所要求这个方法在使用getExchangeMetaData()方法之前调用。一些交易所在使用某些服务之前需要先调用它。remoteInit实现的思路就是远程读取交易所元数据,然后整理成ExchangeMetadata对象,主要就是整理货币交易对、货币、公开费率限制、私有费率限制、是否共享费率等。
ExchangeMetaData
Exchange Metadata包括交易对、最大轮询速率、缩放系数、费用、最低金额等。其加载并存储在Exchange
层,而不是Service
层。信息在创建Exchange时加载,并存储在ExchangeMetaData
对象中。一种方便方法List<CurrencyPair> getExchangeSymbols()
,被用来访问那些CurrencyPair
。exchange.getExchangeMetaData()
可以被调用来获取所有元数据。
由于不同的exchange可以通过API调用不同数量的(从零到全部个)元数据(可以全部位于一个 API 终结点或多个 API 终结点的组合中),因此XChange以以下方式处理此数据:
-
在
Exchange
创建期间,从类路径加载JSON文件,该文件是包含Exchange元数据的硬编码JSON结构。这通常针对不能通过API Endpoint提供元数据或仅提供有限数据的Exchange
。 -
在创建
Exchange
期间,可以指定 JSON 文件的路径以覆盖XChange附带的默认JSON文件。关于提供自己的元数据文件,您可能有以下几个原因:a) 默认的JSON文件已过时
b) 您想要出于各种原因调整数据
c) 默认的JSON文件不完整
-
在创建
Exchange
期间,remoteInit()
被调用 。此方法的实现可能因Exchange而异,但主要想法是通过远程API调用加载元数据,以生成ExchangeMetaData
。鼓励实现加载通过硬编码的JSON文件来覆盖数据,特别是当API EndPoint调用中缺少JSON文件时。
需要元数据的代码应调用Exchange
对象上的访问方法。
ExchangeMetaData中包括五个属性,货币交易对、货币、公开费率限制、私有费率限制、是否共享费率
public class ExchangeMetaData implements Serializable {
@JsonProperty("currency_pairs")
private Map<CurrencyPair, CurrencyPairMetaData> currencyPairs;
@JsonProperty("currencies")
private Map<Currency, CurrencyMetaData> currencies;
@JsonProperty("public_rate_limits")
private RateLimit[] publicRateLimits;
@JsonProperty("private_rate_limits")
private RateLimit[] privateRateLimits;
/**
* If true, both public and private calls use single rate limit policy, which is described in
* {@link #privateRateLimits}.
*/
@JsonProperty("share_rate_limits")
private boolean shareRateLimits = true;
...
}
Currency
大致模仿java.util.Currency货币类的一个虚拟货币类。每个对象都用这个类来获取coin code。比如
getInstance.("BTC").getCurrencyCode()
得到代码“BTC”。
CurrencyPair
CurrencyPair是虚拟货币交易对类。其提供主要的货币符号对,比如EUR/USD, GBP/USD。
里面有两个参数case和counter。case是你想买卖的种类。counter是你想买或者卖case的时候的用来支付的货币种类。
Ticker
封装实体类。封装“Ticker”包含的信息的类。某些字段如果交易所没有提供,可以为空。
private final CurrencyPair currencyPair; //交易对
private final BigDecimal open; //
private final BigDecimal last;//最近价格
private final BigDecimal bid;//买价
private final BigDecimal ask;//卖价
private final BigDecimal high;//最高价格
private final BigDecimal low;//最低价格
private final BigDecimal vwap;//成交平均价格-以base计算
private final BigDecimal volume;//24小时成交量
private final BigDecimal quoteVolume;//24小时成交量-以counter计算
/** the timestamp of the ticker according to the exchange's server, null if not provided */
private final Date timestamp;//时间戳-根据交易所服务器的返回,如果没有返回则为null
private final BigDecimal bidSize;//
private final BigDecimal askSize;//
Order
Order类是一个类,表示一个订单,订单可分为三类:限价单(Limit Order)、市价单(Market Order)、止损单(Stop Order)。
/** Order type i.e. bid or ask 订单类型:卖出订单、买入订单*/
private final OrderType type;
/** Amount to be ordered / amount that was ordered 订单初始挂出的数量*/
private final BigDecimal originalAmount;
/** The instrument could be a currency pair of derivative 金融工具-比如金融衍生品*/
private final Instrument instrument;
/** An identifier set by the exchange that uniquely identifies the order 交易所设置的订单的唯一标识*/
private final String id;
/** An identifier provided by the user on placement that uniquely identifies the order 用户创建订单时,设置的私有唯一标识 */
private final String userReference;
/** The timestamp on the order according to the exchange's server, null if not provided 订单的时间戳(时间戳是交易所服务器设置)*/
private final Date timestamp;
/** Any applicable order flags 其他订单标识 IOrderFlags是Order内部类*/
private final Set<IOrderFlags> orderFlags = new HashSet<>();
/** Status of order during it lifecycle 订单状态*/
private OrderStatus status;
/** Amount to be ordered / amount that has been matched against order on the order book/filled 已经成交(匹配)的数量*/
private BigDecimal cumulativeAmount;
/** Weighted Average price of the fills in the order 以成交部分的平均价格*/
private BigDecimal averagePrice;
/** The total of the fees incurred for all transactions related to this order 交易费用总额*/
private BigDecimal fee;
/** The leverage to use for margin related to this order 杠杆保证金*/
private String leverage = null;
订单状态: OrderStatus 是Order类的一个内部枚举。如下:
/** Initial order when instantiated */
PENDING_NEW,
/** Initial order when placed on the order book at exchange */
NEW,
/** Partially match against opposite order on order book at exchange */
PARTIALLY_FILLED,
/** Fully match against opposite order on order book at exchange */
FILLED,
/** Waiting to be removed from order book at exchange */
PENDING_CANCEL,
/** Order was partially canceled at exchange */
PARTIALLY_CANCELED,
/** Removed from order book at exchange */
CANCELED,
/** Waiting to be replaced by another order on order book at exchange */
PENDING_REPLACE,
/** Order has been replace by another order on order book at exchange */
REPLACED,
/** Order has been triggered at stop price */
STOPPED,
/** Order has been rejected by exchange and not place on order book */
REJECTED,
/** Order has expired it's time to live or trading session and been removed from order book */
EXPIRED,
/**
* The exchange returned a state which is not in the exchange's API documentation. The state of
* the order cannot be confirmed.
*/
UNKNOWN;
LimitOrder
LimitOrder继承Order类。有一个保护属性limitPrice。
ExchangeSpecification
ExchangeSpecification是一个POJO类。它向ExchangeFactory提供各种规范。其中有一个属性exchangeSpecificParameters,被定义为Map<String, Object>。当创建一个Exchange的时候,exchangeSpecificParameters是必须提供的。附加配置的时候,exchangeSpecificParameters是可选的。
其他属性还包括:
private final String exchangeClassName;
private String exchangeName;
private String exchangeDescription;
private String userName;
private String password;
private String secretKey;
private String apiKey;
private String sslUri;
private String plainTextUri;
private String host;
private int port = 80;
private String proxyHost;
private Integer proxyPort;
private int httpConnTimeout = 0; // default rescu configuration will be used if value not changed
private int httpReadTimeout = 0; // default rescu configuration will be used if value not changed
private String metaDataJsonFileOverride = null;
private boolean shouldLoadRemoteMetaData = true; // default value
/** arbitrary exchange params that can be set for unique cases */
private Map<String, Object> exchangeSpecificParameters = new HashMap<>();
一般的用法如下:
ExchangeSpecification exSpec = new BitstampExchange().getDefaultExchangeSpecification();
exSpec.setUserName("34387");
exSpec.setApiKey("a4SDmpl9s6xWJS5fkKRT6yn41vXuY0AM");
exSpec.setSecretKey("sisJixU6Xd0d1yr6w02EHCb9UwYzTNuj");
Exchange bitstamp = ExchangeFactory.INSTANCE.createExchange(exSpec);
// Get the account information
AccountService accountService = bitstamp.getAccountService();
AccountInfo accountInfo = accountService.getAccountInfo();
System.out.println(accountInfo.toString());
BaseExchange
抽象类BaseExchange实现了Exchange接口。其定义的保护类型的属性如下:
protected ExchangeSpecification exchangeSpecification;
protected ExchangeMetaData exchangeMetaData;
protected MarketDataService marketDataService;
protected TradeService tradeService;
protected AccountService accountService;
两个数据类和三个服务接口。