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类中实现。方法执行顺序:

  1. 先以传入的ExchangeSpecification参数为基础,补充getDefaultExchangeSpecification方法得到的属性,得到一个完整的ExchangeSpecification。
  2. 调用自定义json文件,或者调用默认的类路径json文件。
  3. 初始化三个服务类。
  4. 执行remoteInit,获取远程MetaData数据,remoteInit的实现在各个交易所模块内实现。

remoteInit方法用来使用远程元数据初始化实例。大多数交易所要求这个方法在使用getExchangeMetaData()方法之前调用。一些交易所在使用某些服务之前需要先调用它。remoteInit实现的思路就是远程读取交易所元数据,然后整理成ExchangeMetadata对象,主要就是整理货币交易对、货币、公开费率限制、私有费率限制、是否共享费率等。

ExchangeMetaData

​ Exchange Metadata包括交易对、最大轮询速率、缩放系数、费用、最低金额等。其加载并存储在Exchange层,而不是Service层。信息在创建Exchange时加载,并存储在ExchangeMetaData对象中。一种方便方法List<CurrencyPair> getExchangeSymbols(),被用来访问那些CurrencyPairexchange.getExchangeMetaData()可以被调用来获取所有元数据。

​ 由于不同的exchange可以通过API调用不同数量的(从零到全部个)元数据(可以全部位于一个 API 终结点或多个 API 终结点的组合中),因此XChange以以下方式处理此数据:

  1. Exchange创建期间,从类路径加载JSON文件,该文件是包含Exchange元数据的硬编码JSON结构。这通常针对不能通过API Endpoint提供元数据或仅提供有限数据的Exchange

  2. 在创建Exchange期间,可以指定 JSON 文件的路径以覆盖XChange附带的默认JSON文件。关于提供自己的元数据文件,您可能有以下几个原因:

    a) 默认的JSON文件已过时

    b) 您想要出于各种原因调整数据

    c) 默认的JSON文件不完整

  3. 在创建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;

两个数据类和三个服务接口。