#complete #api #set #api-key #nightly

nightly stockfighter

StockFighter 完整 API

3 个不稳定版本

使用旧的 Rust 2015

0.2.1 2016年6月17日
0.2.0 2016年4月29日
0.1.1 2016年4月18日
0.1.0 2016年4月14日

金融类别中排名第215位

MIT 许可证

40KB
433

StockFighter

StockFighter 的完整 Rust API

在此处找到它:https://crates.io/crates/stockfighter

使用最新的 nightly:multirust run nightly cargo build

请确保设置 $STOCKFIGHTER_API_KEY.

简介

易于开始

extern crate stockfighter;

use stockfighter::*;

fn main() {
    let sf = StockFighter::new();
    println!("{:#?}",sf.venue_heartbeat(Venue("TESTEX".to_string())));
}

完全异步和非阻塞示例,使用 WS 和 carboxyl FRP 库!

#[macro_use] extern crate stockfighter;
             extern crate serde_json;
             extern crate ws;
             extern crate carboxyl;

use std::io::prelude::*;
use std::fs::{File,OpenOptions};
use std::thread;
use std::sync::mpsc::channel;
use std::sync::mpsc::Sender as MPSCSender;
use ws::{connect,CloseCode,Handler,Message,Handshake,Result,Error,ErrorKind};
use carboxyl::{Sink,Stream};

use stockfighter::*;

enum SFTTEvent { Connect(Stream<QuoteM>), Disconnect }

struct SFTT { tt_sender: MPSCSender<SFTTEvent>, tt_sink: Sink<QuoteM>, f: File }

impl Handler for SFTT {
  fn on_open(&mut self, _: Handshake) -> Result<()> {
    println!("{}","SFTT connected!");
    self.tt_sender.send(SFTTEvent::Connect(self.tt_sink.stream())).map_err(|err| Error::new(
      ErrorKind::Internal, format!("Unable to communicate between threads: {:?}.", err))) }

  fn on_message(&mut self, msg: Message) -> Result<()> {
    if let Err(e) = self.f.write(&msg.clone().into_data()) { println!("{}", e); }
    match serde_json::from_str::<QuoteWS>(&msg.into_text().unwrap()) {
      Ok(o) => { Ok(self.tt_sink.send_async(quote_ws_to_quote_m(o))) },
      Err(e) => { Err(Error::new(ErrorKind::Internal, format!("SFTT on_message: {:?}.", e))) }}}

  fn on_close(&mut self, code: CloseCode, reason: &str) { }

  fn on_error(&mut self, err: Error) {  }}

fn main() {
  let sf = StockFighter::new();
  let acc   = "";
  let venue = "";
  let stock = "";

  let tt_url = format!("wss://api.stockfighter.io/ob/api/ws/{}/venues/{}/tickertape/stocks/{}",acc,venue,stock);

  let (tt_tx, tt_rx) = channel();

  let _ = thread::Builder::new().name("sf_tt".to_owned()).spawn(move || {
    connect(tt_url, |_| { SFTT { tt_sender: tt_tx.clone(),
                                 tt_sink: Sink::new(),
                                 f: OpenOptions::new().write(true).append(true).open("data/orders.txt").unwrap()
    }}).unwrap(); });

  let tt_stream = match tt_rx.recv() { Ok(SFTTEvent::Connect(stream)) => stream, _ => panic!("tt_sink") };

  let _ = thread::Builder::new().name("trade".to_owned()).spawn(move || {
    for event in tt_stream.events() {
      if let Ok(SFTTEvent::Disconnect) = tt_rx.try_recv() { break }
      /* trade! */ }}).unwrap(); }

函数、类型和接口

// Internal Structs and Funcs

pub struct HyperResult<T>(pub Result<Result<T,hyper::status::StatusCode>,hyper::error::Error>);

impl<T> HyperResult<T> {

  pub fn all_ok(self) -> T {..} }


pub struct StockFighter { api_key: String, client: Client }

impl StockFighter {

  pub fn new() -> StockFighter {..}

  pub fn api_heartbeat(&self) -> HyperResult<ApiHeartbeat> {..}

  pub fn venue_heartbeat(&self, venue: Venue) -> HyperResult<VenueHeartbeat> {..}

  pub fn stocks_on_venue(&self, venue: Venue) -> HyperResult<StocksOnVenue> {..}

  pub fn orderbook(&self, venue: Venue, stock: Symbol) -> HyperResult<OrderbookForAStock> {..}

  pub fn new_order(&self, acc: Account, venue: Venue, stock: Symbol,
                   price: Price, qty: Qty, dir: Direction, order_type: OrderType)
                   -> HyperResult<NewOrderForAStock> {..}

  pub fn quote(&self, venue: Venue, stock: Symbol) -> HyperResult<QuoteForAStock> {..}

  pub fn status_for_existing_order(&self, id: OrderId, venue: Venue, stock: Symbol)
                                   -> HyperResult<StatusForAnExistingOrder> {..}

  pub fn cancel_order(&self, venue: Venue, stock: Symbol, order: OrderId)
                      -> HyperResult<CancelAnOrder> {..}

  pub fn status_for_all_orders(&self, venue: Venue, acc: Account)
                              -> HyperResult<StatusForAllOrders> {..}

  pub fn status_for_all_orders_in_a_stock(&self, venue: Venue, acc: Account, stock: Symbol)
                                          -> HyperResult<StatusForAllOrdersInAStock> {..} }

pub fn quote_to_quote_m(q: Quote) -> QuoteM {..}

pub fn quote_ws_to_quote_m(q: QuoteWS) -> QuoteM {..}


// Enums

pub enum VenueHeartbeat { R200(VenueOk), R500(ErrMsg), R404(ErrMsg) }

pub enum StocksOnVenue              { R200(Stocks),    R404(ErrMsg) }
pub enum OrderbookForAStock         { R200(Orderbook), R404(ErrMsg) }
pub enum NewOrderForAStock          { R200(Order),     R404(ErrMsg), R200Err(ErrMsg) }
pub enum QuoteForAStock             { R200(QuoteM),     R404(ErrMsg) }

pub enum StatusForAnExistingOrder   { R200(Order),     R401(ErrMsg) }
pub enum CancelAnOrder              { R200(Order),     R401(ErrMsg) }
pub enum StatusForAllOrders         { R200(Status),    R401(ErrMsg) }
pub enum StatusForAllOrdersInAStock { R200(Status),    R401(ErrMsg) }

pub enum Direction { Buy, Sell }

pub enum OrderType { Limit, Market, FillOrKill, ImmediateOrCancel }


// API Structs

pub struct ApiHeartbeat(pub ErrMsg);

pub struct ErrMsg { pub ok: bool, pub error: String }

pub struct VenueOk { ok: bool, venue: Venue }


pub struct   Qty(pub usize);
pub struct Price(pub usize);

pub struct   Venue(pub String);
pub struct  Symbol(pub String);
pub struct Account(pub String);

pub struct DTUTC(pub DateTime<UTC>);


pub struct Stocks { pub ok: bool, pub symbols: Vec<SymbolName> }

pub struct SymbolName { pub name: String, pub symbol: Symbol }


pub struct Orderbook {
  pub ok:     bool,
  pub venue:  Venue,
  pub symbol: Symbol,
  pub bids:   Bids,
  pub asks:   Asks,
  pub ts:     DTUTC }

pub struct Bids(pub Vec<Position>);
pub struct Asks(pub Vec<Position>);

pub struct Position {
  pub price:  Price,
  pub qty:    Qty,
  pub is_buy: IsBuy }

pub struct IsBuy(pub bool);


pub struct Order {
  pub ok:           bool,
  pub symbol:       Symbol,
  pub venue:        Venue,
  pub direction:    Direction,
  pub original_qty: OriginalQty,
  pub qty:          Qty,
  pub price:        Price,
  pub order_type:   OrderType,
  pub id:           OrderId,
  pub account:      Account,
  pub ts:           DTUTC,
  pub fills:        Vec<Fill>,
  pub total_filled: TotalFilled,
  pub open:         OrderOpen }

pub struct OriginalQty(pub usize);
pub struct     OrderId(pub usize);
pub struct TotalFilled(pub usize);

pub struct OrderOpen(pub bool);

pub struct Fill { pub price: Price, pub qty: Qty, pub ts: DTUTC }


pub struct NewOrder {
  pub account:    Account,
  pub venue:      Venue,
  pub stock:      Symbol,
  pub qty:        Qty,
  pub price:      Price,
  pub direction:  Direction,
  pub order_type: OrderType }


pub struct Quote {
  pub ok:         Option<bool>,
  pub symbol:     Symbol,
  pub venue:      Venue,
  pub bid:        Option<Bid>,
  pub ask:        Option<Ask>,
  pub bid_size:   Option<BidSize>,
  pub ask_size:   Option<AskSize>,
  pub bid_depth:  Option<BidDepth>,
  pub ask_depth:  Option<AskDepth>,
  pub last_size:  Option<LastSize>,
  pub last_trade: Option<DTUTC>,
  pub quote_time: Option<DTUTC> }

pub struct QuoteM {
  pub symbol:       Symbol,
  pub venue:        Venue,
  pub these_quotes: TheseQuotes,
  pub last:         Last,
  pub last_size:    LastSize,
  pub last_trade:   DTUTC,
  pub quote_time:   DTUTC }

pub enum TheseQuotes { ThisBid(BidStruct), ThatAsk(AskStruct), TheseQuotes(BidStruct,AskStruct), Empty }

pub struct BidStruct { bid: Bid, bid_size: BidSize, bid_depth: BidDepth }

pub struct AskStruct { ask: Ask, ask_size: AskSize, ask_depth: AskDepth }


pub struct      Bid(pub usize);
pub struct      Ask(pub usize);
pub struct  BidSize(pub usize);
pub struct  AskSize(pub usize);
pub struct BidDepth(pub usize);
pub struct AskDepth(pub usize);
pub struct     Last(pub usize);
pub struct LastSize(pub usize);


pub struct Status {
  pub ok:     bool,
  pub venue:  Venue,
  pub orders: Vec<Order> }


pub struct QuoteWS { pub ok: bool, pub quote: Quote }

pub struct FillsWS {
  pub ok:                bool,
  pub account:           Account,
  pub venue:             Venue,
  pub symbol:            Symbol,
  pub order:             Order,
  pub standing_id:       StandingId,
  pub incoming_id:       IncomingId,
  pub price:             Price,
  pub filled:            Filled,
  pub filled_at:         DTUTC,
  pub standing_complete: StandingComplete,
  pub incoming_complete: IncomingComplete }

pub struct StandingId(pub usize);
pub struct IncomingId(pub usize);

pub struct Filled(pub usize);

pub struct StandingComplete(pub bool);
pub struct IncomingComplete(pub bool);

新类型

所有具有类似底层表示但语义上不同的类型都被封装在新类型中。

新类型在编译时被擦除,仅用于防止库用户意外传递错误的参数,例如将 OrderId 传递给 Price 参数。

所有新类型也实现了 DerefDerefMutFromInto

新类型 2

它们还可以防止在非相似类型之间进行操作,例如将价格和数量相乘。

如果您确定您想要这样做,您可以使用元组语法简单地访问底层数据。

例如

let price_times_qty = price.0 * qty.0;

新类型 3

所有新类型也实现了在适用的情况下重载操作符,因此您不需要解包和重新包装新类型来对其底层值进行操作。

例如

let multiplied_prices = Price(3241) * Price(1748);

响应类型

所有请求都返回一个 HyperRequest(如果一切顺利),该请求由两个 Ok 构成,该类型定义如下

pub type HyperResult<T> = Result<Result<T,hyper::status::StatusCode>,hyper::error::Error>;

使用这种 Ok(Ok(T)) 类型的原因是第一层是用于请求本身,如果请求本身出现问题并且返回一个 Err(hyper::error::Error),则。

如果请求顺利进行,但API返回的状态不是预期的,那么它将返回意外的状态代码:Ok(Err(hyper::status::StatusCode))

大多数情况下,这两者都会顺利进行,并将返回Ok(Ok(RX0X(T))),其中RX0X是某些状态代码,通常为成功时的R200,或者在某些错误情况下的R401R404R500。如果你的程序期望每次都能正常工作,你可以简单地使用.all_ok()来展开两个Ok

响应类型2

返回的主要响应类型有VenueOkErrMsgStocksOrderbookOrderQuoteStatus.

WebSocket响应类型为QuoteWSFillsWS

下面是一个完整的响应示例

Ok(
    Ok(
        R200(
            Order {
                ok: true,
                symbol: Symbol(
                    "CWI"
                ),
                venue: Venue(
                    "CSJBEX"
                ),
                direction: Sell,
                original_qty: OriginalQty(
                    10
                ),
                qty: Qty(
                    0
                ),
                price: Price(
                    6000
                ),
                order_type: Limit,
                id: OrderId(
                    1834
                ),
                account: Account(
                    "BFB42332882"
                ),
                ts: DTUTC(
                    "2016-04-14T14:18:28.579888777Z"
                ),
                fills: [
                    Fill {
                        price: Price(
                            6120
                        ),
                        qty: Qty(
                            10
                        ),
                        ts: DTUTC(
                            "2016-04-14T14:18:28.579891467Z"
                        )
                    }
                ],
                total_filled: TotalFilled(
                    10
                ),
                open: OrderOpen(
                    false
                )
            }
        )
    )
)

响应类型3

原始报价结构体(无论是Quote还是QuoteWS)进一步解析为QuoteM。这个结构体使用了一种类似These的结构。

如果你不熟悉These,原始的Haskell库及其定义在此:https://hackage.haskell.org/package/these-0.6.2.1/docs/Data-These.html

为了简单起见,我在下面复制了QuoteM的定义

pub struct QuoteM {
  pub symbol:       Symbol,
  pub venue:        Venue,
  pub these_quotes: TheseQuotes,
  pub last:         Last,
  pub last_size:    LastSize,
  pub last_trade:   DTUTC,
  pub quote_time:   DTUTC }

pub enum TheseQuotes { ThisBid(BidStruct), ThatAsk(AskStruct), TheseQuotes(BidStruct,AskStruct), Empty }

pub struct BidStruct { bid: Bid, bid_size: BidSize, bid_depth: BidDepth }

pub struct AskStruct { ask: Ask, ask_size: AskSize, ask_depth: AskDepth }

你可能已经注意到,TheseQuotes并不完全像These,事实上,有一个Empty情况,用于处理当Orderbook为空时的情况。换句话说,TheseQuotes模拟了Orderbook可能存在的四种状态,即Empty,有某些Bids,有某些Asks,或者同时有BidsAsks

依赖关系

~5–6.5MB
~117K SLoC