2727require_relative '../models/wallet'
2828
2929module Bitfinex
30+ ###
31+ # Implements version 2 of the Bitfinex WebSocket API, taking an evented
32+ # approach. Incoming packets trigger event broadcasts with names relevant to
33+ # the individual packets. Provides order manipulation methods that support
34+ # callback blocks, which are called when the relevant confirmation
35+ # notifications are received
36+ ###
3037 class WSv2
3138 include Emittr ::Events
3239
@@ -40,6 +47,18 @@ class WSv2
4047 FLAG_SEQ_ALL = 65536 , # enable sequencing
4148 FLAG_CHECKSUM = 131072 # enable OB checksums, top 25 levels per side
4249
50+ ###
51+ # Creates a new instance of the class
52+ #
53+ # @param [Hash] params
54+ # @param [string] params.url - connection URL
55+ # @param [string] params.api_key
56+ # @param [string] params.api_secret
57+ # @param [boolean] params.manage_order_books - if true, order books are persisted internally, allowing for automatic checksum verification
58+ # @param [boolean] params.transform - if true, full models are returned in place of array data
59+ # @param [boolean] params.seq_audit - enables automatic seq number verification
60+ # @param [boolean] params.checksum_audit - enables automatic OB checksum verification (requires manage_order_books)
61+ ###
4362 def initialize ( params = { } )
4463 @l = Logger . new ( STDOUT )
4564 @l . progname = 'ws2'
@@ -62,7 +81,7 @@ def initialize (params = {})
6281 @last_auth_seq = nil
6382 end
6483
65- def on_open ( e )
84+ def on_open ( e ) # :nodoc:
6685 @l . info 'client open'
6786 @is_open = true
6887 emit ( :open )
@@ -71,7 +90,7 @@ def on_open (e)
7190 enable_ob_checksums if @checksum_audit
7291 end
7392
74- def on_message ( e )
93+ def on_message ( e ) # :nodoc:
7594 @l . info "recv #{ e . data } "
7695
7796 msg = JSON . parse ( e . data )
@@ -80,12 +99,15 @@ def on_message (e)
8099 emit ( :message , msg )
81100 end
82101
83- def on_close ( e )
102+ def on_close ( e ) # :nodoc:
84103 @l . info 'client closed'
85104 @is_open = false
86105 emit ( :close )
87106 end
88107
108+ ###
109+ # Opens the websocket client inside an eventmachine run block
110+ ###
89111 def open!
90112 if @is_open
91113 raise Exception , 'already open'
@@ -108,11 +130,14 @@ def open!
108130 }
109131 end
110132
133+ ###
134+ # Closes the websocket client
135+ ###
111136 def close!
112137 @ws . close
113138 end
114139
115- def process_message ( msg )
140+ def process_message ( msg ) # :nodoc:
116141 if @seq_audit
117142 validate_message_seq ( msg )
118143 end
@@ -124,7 +149,7 @@ def process_message (msg)
124149 end
125150 end
126151
127- def validate_message_seq ( msg )
152+ def validate_message_seq ( msg ) # :nodoc:
128153 return unless @seq_audit
129154 return unless msg . kind_of? ( Array )
130155 return unless msg . size > 2
@@ -171,7 +196,7 @@ def validate_message_seq (msg)
171196 @last_auth_seq = auth_seq
172197 end
173198
174- def process_channel_message ( msg )
199+ def process_channel_message ( msg ) # :nodoc:
175200 if !@channel_map . include? ( msg [ 0 ] )
176201 @l . error "recv message on unknown channel: #{ msg [ 0 ] } "
177202 return
@@ -202,7 +227,7 @@ def process_channel_message (msg)
202227 end
203228 end
204229
205- def handle_ticker_message ( msg , chan )
230+ def handle_ticker_message ( msg , chan ) # :nodoc:
206231 payload = msg [ 1 ]
207232
208233 if chan [ 'symbol' ] [ 0 ] === 't'
@@ -212,7 +237,7 @@ def handle_ticker_message (msg, chan)
212237 end
213238 end
214239
215- def handle_trades_message ( msg , chan )
240+ def handle_trades_message ( msg , chan ) # :nodoc:
216241 if msg [ 1 ] . kind_of? ( Array )
217242 payload = msg [ 1 ]
218243 emit ( :public_trades , chan [ 'symbol' ] , @transform ? payload . map { |t | Models ::PublicTrade . new ( t ) } : payload )
@@ -230,7 +255,7 @@ def handle_trades_message (msg, chan)
230255 end
231256 end
232257
233- def handle_candles_message ( msg , chan )
258+ def handle_candles_message ( msg , chan ) # :nodoc:
234259 payload = msg [ 1 ]
235260
236261 if payload [ 0 ] . kind_of? ( Array )
@@ -240,7 +265,7 @@ def handle_candles_message (msg, chan)
240265 end
241266 end
242267
243- def handle_order_book_checksum_message ( msg , chan )
268+ def handle_order_book_checksum_message ( msg , chan ) # :nodoc:
244269 key = "#{ chan [ 'symbol' ] } :#{ chan [ 'prec' ] } :#{ chan [ 'len' ] } "
245270 emit ( :checksum , chan [ 'symbol' ] , msg )
246271
@@ -259,7 +284,7 @@ def handle_order_book_checksum_message (msg, chan)
259284 end
260285 end
261286
262- def handle_order_book_message ( msg , chan )
287+ def handle_order_book_message ( msg , chan ) # :nodoc:
263288 ob = msg [ 1 ]
264289
265290 if @manage_obs
@@ -282,7 +307,7 @@ def handle_order_book_message (msg, chan)
282307 end
283308
284309 # Resolves/rejects any pending promise associated with the notification
285- def handle_notification_promises ( n )
310+ def handle_notification_promises ( n ) # :nodoc:
286311 type = n [ 1 ]
287312 payload = n [ 4 ]
288313 status = n [ 6 ]
@@ -331,7 +356,7 @@ def handle_notification_promises (n)
331356 end
332357 end
333358
334- def handle_auth_message ( msg , chan )
359+ def handle_auth_message ( msg , chan ) # :nodoc:
335360 type = msg [ 1 ]
336361 return if type == 'hb'
337362 payload = msg [ 2 ]
@@ -401,6 +426,16 @@ def handle_auth_message (msg, chan)
401426 end
402427 end
403428
429+ ###
430+ # Subscribes to the specified channel; params dictate the channel filter
431+ #
432+ # @param [string] channel - i.e. 'trades', 'candles', etc
433+ # @param [Hash] params
434+ # @param [string?] params.symbol
435+ # @param [string?] params.prec - for order book channels
436+ # @param [string?] params.len - for order book channels
437+ # @param [string?] params.key - for candle channels
438+ ###
404439 def subscribe ( channel , params = { } )
405440 @l . info 'subscribing to channel %s [%s]' % [ channel , params ]
406441 @ws . send ( JSON . generate ( params . merge ( {
@@ -409,18 +444,40 @@ def subscribe (channel, params = {})
409444 } ) ) )
410445 end
411446
447+ ###
448+ # Subscribes to a ticker channel by symbol
449+ #
450+ # @param [string] sym - i.e. tBTCUSD
451+ ###
412452 def subscribe_ticker ( sym )
413453 subscribe ( 'ticker' , { :symbol => sym } )
414454 end
415455
456+ ###
457+ # Subscribes to a trades channel by symbol
458+ #
459+ # @param [string] sym - i.e. tBTCUSD
460+ ###
416461 def subscribe_trades ( sym )
417462 subscribe ( 'trades' , { :symbol => sym } )
418463 end
419464
465+ ###
466+ # Subscribes to a candle channel by key
467+ #
468+ # @param [string] key - i.e. trade:1m:tBTCUSD
469+ ###
420470 def subscribe_candles ( key )
421471 subscribe ( 'candles' , { :key => key } )
422472 end
423473
474+ ###
475+ # Subscribes to an order book channel
476+ #
477+ # @param [string] sym - i.e. tBTCUSD
478+ # @param [string] prec - i.e. R0, P0, etc
479+ # @param [string] len - i.e. 25, 100, etc
480+ ###
424481 def subscribe_order_book ( sym , prec , len )
425482 subscribe ( 'book' , {
426483 :symbol => sym ,
@@ -429,7 +486,7 @@ def subscribe_order_book (sym, prec, len)
429486 } )
430487 end
431488
432- def process_event_message ( msg )
489+ def process_event_message ( msg ) # :nodoc:
433490 case msg [ 'event' ]
434491 when 'auth'
435492 handle_auth_event ( msg )
@@ -446,7 +503,7 @@ def process_event_message (msg)
446503 end
447504 end
448505
449- def handle_auth_event ( msg )
506+ def handle_auth_event ( msg ) # :nodoc:
450507 if msg [ 'status' ] != 'OK'
451508 @l . error "auth failed: #{ msg [ 'message' ] } "
452509 return
@@ -459,7 +516,7 @@ def handle_auth_event (msg)
459516 @l . info 'authenticated'
460517 end
461518
462- def handle_info_event ( msg )
519+ def handle_info_event ( msg ) # :nodoc:
463520 if msg . include? ( 'version' )
464521 if msg [ 'version' ] != 2
465522 close!
@@ -488,11 +545,11 @@ def handle_info_event (msg)
488545 end
489546 end
490547
491- def handle_error_event ( msg )
548+ def handle_error_event ( msg ) # :nodoc:
492549 @l . error msg
493550 end
494551
495- def handle_config_event ( msg )
552+ def handle_config_event ( msg ) # :nodoc:
496553 if msg [ 'status' ] != 'OK'
497554 @l . error "config failed: #{ msg [ 'message' ] } "
498555 else
@@ -501,18 +558,23 @@ def handle_config_event (msg)
501558 end
502559 end
503560
504- def handle_subscribed_event ( msg )
561+ def handle_subscribed_event ( msg ) # :nodoc:
505562 @l . info "subscribed to #{ msg [ 'channel' ] } [#{ msg [ 'chanId' ] } ]"
506563 @channel_map [ msg [ 'chanId' ] ] = msg
507564 emit ( :subscribed , msg [ 'chanId' ] )
508565 end
509566
510- def handle_unsubscribed_event ( msg )
567+ def handle_unsubscribed_event ( msg ) # :nodoc:
511568 @l . info "unsubscribed from #{ msg [ 'chanId' ] } "
512569 @channel_map . delete ( msg [ 'chanId' ] )
513570 emit ( :unsubscribed , msg [ 'chanId' ] )
514571 end
515572
573+ ###
574+ # Enable an individual flag (see FLAG_* constants)
575+ #
576+ # @param [number] flag
577+ ###
516578 def enable_flag ( flag )
517579 return unless @is_open
518580
@@ -522,19 +584,43 @@ def enable_flag (flag)
522584 } ) )
523585 end
524586
587+ ###
588+ # Checks if an individual flag is enabled (see FLAG_* constants)
589+ #
590+ # @param [number] flag
591+ # @return [boolean] enabled
592+ ###
525593 def is_flag_enabled ( flag )
526594 ( @enabled_flags & flag ) == flag
527595 end
528596
597+ ###
598+ # Sets the flag to activate sequence numbers on incoming packets
599+ #
600+ # @param [boolean] audit - if true (default), incoming seq numbers will be checked for consistency
601+ ###
529602 def enable_sequencing ( audit = true )
530603 @seq_audit = audit
531604 enable_flag ( FLAG_SEQ_ALL )
532605 end
533606
534- def enable_ob_checksums
607+ ###
608+ # Sets the flag to activate order book checksums. Managed order books are
609+ # required for automatic checksum audits.
610+ #
611+ # @param [boolean] audit - if true (default), incoming checksums will be compared to local checksums
612+ ###
613+ def enable_ob_checksums ( audit = true )
614+ @checksum_audit = audit
535615 enable_flag ( FLAG_CHECKSUM )
536616 end
537617
618+ ###
619+ # Authenticates the socket connection
620+ #
621+ # @param [number] calc
622+ # @param [number] dms - dead man switch, active 4
623+ ###
538624 def auth! ( calc = 0 , dms = 0 )
539625 if @is_authenticated
540626 raise Exception , 'already authenticated'
@@ -555,18 +641,30 @@ def auth! (calc = 0, dms = 0)
555641 } ) )
556642 end
557643
558- def new_nonce
644+ def new_nonce # :nodoc:
559645 Time . now . to_i . to_s
560646 end
561647
562- def sign ( payload )
648+ def sign ( payload ) # :nodoc:
563649 OpenSSL ::HMAC . hexdigest ( 'sha384' , @api_secret , payload )
564650 end
565651
652+ ###
653+ # Requests a calculation to be performed
654+ # @see https://docs.bitfinex.com/v2/reference#ws-input-calc
655+ #
656+ # @param [Array] prefixes - i.e. ['margin_base']
657+ ###
566658 def request_calc ( prefixes )
567659 @ws . send ( JSON . generate ( [ 0 , 'calc' , nil , prefixes . map { |p | [ p ] } ] ) )
568660 end
569661
662+ ###
663+ # Update an order with a changeset by ID
664+ #
665+ # @param [Hash] changes - must contain ID
666+ # @param [Block] cb - triggered upon receipt of confirmation notification
667+ ###
570668 def update_order ( changes , &cb )
571669 id = changes [ :id ] || changes [ 'id' ]
572670 @ws . send ( JSON . generate ( [ 0 , 'ou' , nil , changes ] ) )
@@ -576,6 +674,12 @@ def update_order (changes, &cb)
576674 end
577675 end
578676
677+ ###
678+ # Cancel an order by ID
679+ #
680+ # @param [Hash|Array|Order|number] order - must contain or be ID
681+ # @param [Block] cb - triggered upon receipt of confirmation notification
682+ ###
579683 def cancel_order ( order , &cb )
580684 return if !@is_authenticated
581685
@@ -598,6 +702,12 @@ def cancel_order (order, &cb)
598702 end
599703 end
600704
705+ ###
706+ # Submit a new order
707+ #
708+ # @param [Hash|Array|Order] order
709+ # @param [Block] cb - triggered upon receipt of confirmation notification
710+ ###
601711 def submit_order ( order , &cb )
602712 return if !@is_authenticated
603713
0 commit comments