Commits

Oliver Gu  committed 57a1e8e

Delayed pickler/unpickler construction

  • Participants
  • Parent commits dd13ad7

Comments (0)

Files changed (13)

File lib/account_code.ml

 let t_of_tws = of_string
 let val_type = Val_type.create tws_of_t t_of_tws
 
-let unpickler =
+let unpickler = lazy (
   Unpickler.create ~name:"Account_code"
     Unpickler.Spec.(value (required val_type) ~name:"account_code")
-    Fn.id
+    Fn.id)
 
 module Query_id = struct
   include Unique_id.Int63 (struct end)
+  let default = of_int_exn (-1)
   let increase t num = of_int_exn (to_int_exn t + num)
   let val_type = Val_type.create to_string of_string
-  let default = of_int_exn (-1)
 end
 
 module Header = struct
     | Error err -> Error (Ibx_error.to_error err)
 end
 
-let to_tws p x = Pickler.run p x
-let of_tws u x = Ibx_result.try_with_unpickle (fun () -> Unpickler.run_exn u x)
+let to_tws p x = Pickler.run (Lazy.force p) x
+let of_tws u x = Ibx_result.try_with_unpickle (fun () ->
+  Unpickler.run_exn (Lazy.force u) x)
 
 module Client_header = struct
   type t =
       client_id      : Client_id.t;
     } with fields, sexp
 
-  let pickler =
+  let pickler = lazy (
     Pickler.create ~name:"Ib.Client_header"
       Pickler.Spec.(
         wrap (
             ~client_version:(fields_value (required int))
             ~client_id:(fields_value (required Client_id.val_type)))
           (fun { client_version; client_id } ->
-            `Args $ client_version $ client_id))
+            `Args $ client_version $ client_id)))
 end
 
 module Server_header = struct
       connection_time : Time.t;
     } with fields, sexp
 
-  let unpickler =
+  let unpickler = lazy (
     Unpickler.create ~name:"Ib.Server_header"
       Unpickler.Spec.(
         Fields.fold
           ~server_version:(fields_value (required int))
           ~connection_time:(fields_value (required time)))
       (fun server_version connection_time ->
-        { server_version; connection_time })
+        { server_version; connection_time }))
 end
 
 module Query = struct
       data    : string;
     } with fields, sexp
 
-  let pickler =
+  let pickler = lazy (
     Pickler.create ~name:"Ib.Query"
       Pickler.Spec.(
         wrap (
             ~id:(fields_value (skipped_if_none Query_id.val_type))
             ~data:(fields_value tws_data))
           (fun { tag; version; id; data } ->
-            `Args $ tag $ version $ id $ data))
+            `Args $ tag $ version $ id $ data)))
 end
 
 module Response_data = struct
         let msg = to_tws Query.pickler query in
         Log.Global.debug ">> %s" (tr_null msg)
       | `Recv response ->
-        let msg = to_tws (Lazy.force Response.pickler) response in
+        let msg = to_tws Response.pickler response in
         Log.Global.debug "<< %s" (tr_null msg)
     in
     let t =
         | Ok x -> Ok (`Ok x)
       end
 
+  module Version_id = struct
+    let unpickler = lazy (
+      Unpickler.create ~name:"Ib.Version_id"
+        Unpickler.Spec.(
+          value (required int) ~name:"version"
+          ++ value (required Query_id.val_type) ~name:"id"
+        )
+        (fun version id -> (version, Some id)))
+  end
+
+  module Version = struct
+    let unpickler = lazy (
+      Unpickler.create ~name:"Ib.Version"
+        Unpickler.Spec.(
+          value (required int) ~name:"version"
+        )
+        (fun version -> (version, None)))
+  end
+
   let read_version_and_optional_id reader tag =
-    if Recv_tag.corresponding_response_has_query_id tag then
-      let unpickler =
-        Unpickler.create ~name:"Ib.Version_and_id"
-          Unpickler.Spec.(
-            value (required int) ~name:"version"
-            ++ value (required Query_id.val_type) ~name:"id"
-          )
-          (fun version id -> (version, Some id))
-      in
-      read_tws reader unpickler ~len:2
-    else
-      let unpickler =
-        Unpickler.create ~name:"Ib.Version"
-          Unpickler.Spec.(
-            value (required int) ~name:"version"
-          )
-          (fun version -> (version, None))
-      in
-      read_tws reader unpickler ~len:1
+    if Recv_tag.corresponding_response_has_query_id tag
+    then read_tws reader Version_id.unpickler ~len:2
+    else read_tws reader Version.unpickler ~len:1
 
   let read_body reader tag =
     let module R = Recv_tag in
   type ('query, 'response) t =
     { send_header  : Send_tag.t Header.t;
       recv_header  : Recv_tag.t Header.t;
-      tws_query    : 'query    Tws_prot.Pickler.t;
-      tws_response : 'response Tws_prot.Unpickler.t;
+      tws_query    : 'query    Tws_prot.Pickler.t Lazy.t;
+      tws_response : 'response Tws_prot.Unpickler.t Lazy.t;
     }
 
   let create ~send_header ~recv_header ~tws_query ~tws_response =
       canc_header  : Send_tag.t Header.t option;
       recv_header  : Recv_tag.t Header.t list;
       skip_header  : Recv_tag.t Header.t list option;
-      tws_query    : 'query    Tws_prot.Pickler.t;
-      tws_response : 'response Tws_prot.Unpickler.t list;
+      tws_query    : 'query    Tws_prot.Pickler.t Lazy.t;
+      tws_response : 'response Tws_prot.Unpickler.t Lazy.t list;
     }
 
   module Id = Query_id
     { send_header  : Send_tag.t Header.t;
       recv_header  : Recv_tag.t Header.t list;
       skip_header  : Recv_tag.t Header.t list option;
-      tws_query    : 'query    Tws_prot.Pickler.t;
-      tws_response : 'response Tws_prot.Unpickler.t list;
+      tws_query    : 'query    Tws_prot.Pickler.t Lazy.t;
+      tws_response : 'response Tws_prot.Unpickler.t Lazy.t list;
     }
 
   let create ?skip_header ~send_header ~recv_header
   val create
     :  send_header:Send_tag.t Header.t
     -> recv_header:Recv_tag.t Header.t
-    -> tws_query    : 'query    Tws_prot.Pickler.t
-    -> tws_response : 'response Tws_prot.Unpickler.t
+    -> tws_query    : 'query    Tws_prot.Pickler.t Lazy.t
+    -> tws_response : 'response Tws_prot.Unpickler.t Lazy.t
     -> ('query, 'response) t
 
   val dispatch
     -> ?skip_header:Recv_tag.t Header.t list
     -> send_header:Send_tag.t Header.t
     -> recv_header:Recv_tag.t Header.t list
-    -> tws_query    : 'query    Tws_prot.Pickler.t
-    -> tws_response : 'response Tws_prot.Unpickler.t list
+    -> tws_query    : 'query    Tws_prot.Pickler.t Lazy.t
+    -> tws_response : 'response Tws_prot.Unpickler.t Lazy.t list
     -> unit
     -> ('query, 'response) t
 
     :  ?skip_header:Recv_tag.t Header.t list
     -> send_header:Send_tag.t Header.t
     -> recv_header:Recv_tag.t Header.t list
-    -> tws_query    : 'query    Tws_prot.Pickler.t
-    -> tws_response : 'response Tws_prot.Unpickler.t list
+    -> tws_query    : 'query    Tws_prot.Pickler.t Lazy.t
+    -> tws_response : 'response Tws_prot.Unpickler.t Lazy.t list
     -> unit
     -> ('query, 'response) t
 

File lib/pickable.ml

 
 module type S = sig
   type t
-  val pickler : t Pickler.t
+  val pickler : t Pickler.t Lazy.t
 end

File lib/query.ml

   type t = unit with sexp
   let create () = ()
   let ( = ) t1 t2 = (t1 = t2)
-  let pickler =
+  let pickler = lazy (
     Pickler.create ~name:Arg.name
-      Pickler.Spec.(value (required unit))
+      Pickler.Spec.(value (required unit)))
   let unpickler = Only_in_test.of_thunk (fun () ->
     Unpickler.create ~name:Arg.name
       Unpickler.Spec.(value (required unit) ~name:"unit")
 
   let ( = ) t1 t2 = (t1 = t2)
 
-  let pickler =
+  let pickler = lazy (
     Pickler.create ~name:"Query.Server_log_level"
-      Pickler.Spec.(value (required Level.val_type))
+      Pickler.Spec.(value (required Level.val_type)))
 
   let unpickler = Only_in_test.of_thunk (fun () ->
     Unpickler.create ~name:"Query.Server_log_level"
       ~tick_generics:(use (=))
       ~snapshot:(use (=))
 
-  let pickler =
+  let pickler = lazy (
     let contract_spec =
       Raw_contract.Pickler_specs.market_data_query ()
     in
             let tick_generics =
               String.concat (List.map tick_generics ~f:Tick_kind.tws_of_t) ~sep:","
             in
-            `Args $ contract $ tick_generics $ snapshot))
+            `Args $ contract $ tick_generics $ snapshot)))
 
   let unpickler = Only_in_test.of_thunk (fun () ->
     let contract_spec =
       ~volatility:(use Float.(=.))
       ~underlying_price:(use Price.(=.))
 
-  let pickler =
+  let pickler = lazy (
     let contract_spec =
       Raw_contract.Pickler_specs.common_option_calc ()
     in
             ~volatility:(fields_value (required float))
             ~underlying_price:(fields_value (required Price.val_type)))
           (fun { contract; volatility; underlying_price } ->
-            `Args $ contract $ volatility $ underlying_price))
+            `Args $ contract $ volatility $ underlying_price)))
 
   let unpickler = Only_in_test.of_thunk (fun () ->
     let contract_spec =
       ~option_price:(use Price.(=.))
       ~underlying_price:(use Price.(=.))
 
-  let pickler =
+  let pickler = lazy (
     let contract_spec =
       Raw_contract.Pickler_specs.common_option_calc ()
     in
             ~option_price:(fields_value (required Price.val_type))
             ~underlying_price:(fields_value (required Price.val_type)))
           (fun { contract; option_price; underlying_price } ->
-            `Args $ contract $ option_price $ underlying_price))
+            `Args $ contract $ option_price $ underlying_price)))
 
   let unpickler = Only_in_test.of_thunk (fun () ->
     let contract_spec =
       ~subscribe:(use (=))
       ~account_code:(use Account_code.(=))
 
-  let pickler =
+  let pickler = lazy (
     Pickler.create ~name:"Query.Account_and_portfolio_updates"
       Pickler.Spec.(
         wrap (
             ~init:(empty ())
             ~subscribe:(fields_value (required bool))
             ~account_code:(fields_value (required Account_code.val_type)))
-      (fun t -> `Args $ t.subscribe $ t.account_code))
+      (fun t -> `Args $ t.subscribe $ t.account_code)))
 
   let unpickler = Only_in_test.of_thunk (fun () ->
     Unpickler.create ~name:"Query.Account_and_portfolio_updates"
       ~exchange:(use (=))
       ~order_action:(use (=))
 
-  let pickler =
+  let pickler = lazy (
     Pickler.create ~name:"Query.Execution_reports"
       Pickler.Spec.(
         wrap (
               $ t.symbol
               $ t.contract_type
               $ t.exchange
-              $ t.order_action))
+              $ t.order_action)))
 
   let unpickler = Only_in_test.of_thunk (fun () ->
     Unpickler.create ~name:"Query.Execution_reports"
   let create ~contract = Contract.to_raw contract
   let ( = ) t1 t2 = Raw_contract.(=) t1 t2
 
-  let pickler =
+  let pickler = lazy (
     Pickler.create ~name:"Query.Contract_specs"
-      (Raw_contract.Pickler_specs.contract_specs_query ())
+      (Raw_contract.Pickler_specs.contract_specs_query ()))
 
   let unpickler = Only_in_test.of_thunk (fun () ->
     Unpickler.create ~name:"Query.Contract_specs"
       ~contract:(use Raw_contract.(=))
       ~num_rows:(use (=))
 
-  let pickler =
+  let pickler = lazy (
     let contract_spec =
       Raw_contract.Pickler_specs.market_depth_query ()
     in
             ~init:(empty ())
             ~contract:(fun specs -> Fn.const (specs ++ contract_spec))
             ~num_rows:(fields_value (required int)))
-          (fun { contract; num_rows } -> `Args $ contract $ num_rows ))
+          (fun { contract; num_rows } -> `Args $ contract $ num_rows )))
 
   let unpickler = Only_in_test.of_thunk (fun () ->
     let contract_spec =
       ~show:(use (=))
       ~date_format:(use (=))
 
-  let pickler =
+  let pickler = lazy (
     let contract_spec =
       Raw_contract.Pickler_specs.historical_data_query ()
     in
               $ t.duration
               $ t.use_rth
               $ t.show
-              $ t.date_format))
+              $ t.date_format)))
 
   let unpickler = Only_in_test.of_thunk (fun () ->
     let contract_spec =
       ~show:(use (=))
       ~use_rth:(use (=))
 
-  let pickler =
+  let pickler = lazy (
     let contract_spec =
       Raw_contract.Pickler_specs.realtime_bars_query ()
     in
             ~show:(fields_value (required Show.val_type))
             ~use_rth:(fields_value (required bool)))
           (fun { contract; bar_size; show; use_rth } ->
-            `Args $ contract $ bar_size $ show $ use_rth ))
+            `Args $ contract $ bar_size $ show $ use_rth )))
 
   let unpickler = Only_in_test.of_thunk (fun () ->
     let contract_spec =

File lib/recv_tag.ml

 
 let val_type = Val_type.create tws_of_t t_of_tws
 
-let unpickler =
+let unpickler = lazy (
   Unpickler.create ~name:"Recv_tag"
     Unpickler.Spec.(value (required val_type) ~name:"recv_tag")
-    Fn.id
+    Fn.id)

File lib/response.ml

 
   let ( = ) t1 t2 = (t1 = t2)
 
-  let unpickler =
+  let unpickler = lazy (
     Unpickler.create ~name:"Response.Tws_error"
       Unpickler.Spec.(
         Fields.fold
           ~init:(step Fn.id)
           ~error_code:(fields_value (required int))
           ~error_msg:(fields_value (required string)))
-      (fun error_code error_msg  -> { error_code; error_msg })
+      (fun error_code error_msg  -> { error_code; error_msg }))
 
   let pickler = Only_in_test.of_thunk (fun () ->
     Pickler.create ~name:"Response.Tws_error"
   let create ~time = time
   let ( = ) t1 t2 = (t1 = t2)
 
-  let unpickler =
+  let unpickler = lazy (
     Unpickler.create ~name:"Response.Server_time"
       Unpickler.Spec.(value (required int64) ~name:"time")
-      (fun long_int -> Time.of_float (Int64.to_float long_int))
+      (fun long_int -> Time.of_float (Int64.to_float long_int)))
 
   let pickler = Only_in_test.of_thunk (fun () ->
     Pickler.create ~name:"Response.Server_time"
       ~size:(use (=))
       ~can_auto_execute:(use (Option.equal (=)))
 
-  let unpickler =
+  let unpickler = lazy (
     Unpickler.create ~name:"Response.Tick_price"
       Unpickler.Spec.(
         Fields.fold
           ~size:(fields_value (required int))
           ~can_auto_execute:(fields_value (optional bool ~none_on_default:"-1")))
       (fun tick_type price size can_auto_execute ->
-        { tick_type; price; size; can_auto_execute })
+        { tick_type; price; size; can_auto_execute }))
 
   let pickler = Only_in_test.of_thunk (fun () ->
     Pickler.create ~name:"Response.Tick_price"
 
   let ( = ) t1 t2 = (t1 = t2)
 
-  let unpickler =
+  let unpickler = lazy (
     Unpickler.create ~name:"Response.Tick_size"
       Unpickler.Spec.(
         Fields.fold
           ~init:(step Fn.id)
           ~tick_type:(fields_value (required Type.val_type))
           ~size:(fields_value (required int)))
-      (fun tick_type size -> { tick_type; size })
+      (fun tick_type size -> { tick_type; size }))
 
   let pickler = Only_in_test.of_thunk (fun () ->
     Pickler.create ~name:"Response.Tick_size"
       ~theta:(use (Option.equal Float.(=.)))
       ~underlying_price:(use (Option.equal Price.(=.)))
 
-  let unpickler =
+  let unpickler = lazy (
     Unpickler.create ~name:"Response.Tick_option"
       Unpickler.Spec.(
         Fields.fold
             theta = if abs theta > 1. then None else Some theta;
             underlying_price = if Price.to_float underlying_price < 0. then None
               else Some underlying_price;
-          })
+          }))
 
   let pickler = Only_in_test.of_thunk (fun () ->
     Pickler.create ~name:"Response.Tick_option"
       ~tick_type:(use (=))
       ~value:(use (=))
 
-  let unpickler =
+  let unpickler = lazy (
     Unpickler.create ~name:"Response.Tick_string"
       Unpickler.Spec.(
         Fields.fold
           ~init:(step Fn.id)
           ~tick_type:(fields_value (required Type.val_type))
           ~value:(fields_value (required string)))
-      (fun tick_type value -> { tick_type; value })
+      (fun tick_type value -> { tick_type; value }))
 
   let pickler = Only_in_test.of_thunk (fun () ->
     Pickler.create ~name:"Response.Tick_string"
   type t = Raw_order.Id.t with sexp
   let create ~order_id = order_id
   let ( = ) t1 t2 = (t1 = t2)
-  let unpickler =
+  let unpickler = lazy (
     Unpickler.create ~name:"Response.Next_order_id"
       Unpickler.Spec.(
         value (required Raw_order.Id.val_type)
           ~name:(Fieldslib.Field.name (Raw_order.Fields.order_id))
-      ) Fn.id
+      ) Fn.id)
 
   let pickler = Only_in_test.of_thunk (fun () ->
     Pickler.create ~name:"Response.Next_order_id"
       ~client_id:(use Client_id.(=))
       ~why_held:(use (=))
 
-  let unpickler =
+  let unpickler = lazy (
     Unpickler.create ~name:"Response.Order_status"
       Unpickler.Spec.(
         Fields.fold
             last_fill_price;
             client_id;
             why_held;
-          })
+          }))
 
   let pickler = Only_in_test.of_thunk (fun () ->
     Pickler.create ~name:"Response.Order_status"
       ~currency:(use (=))
       ~account_code:(use (=))
 
-  let unpickler =
+  let unpickler = lazy (
     Unpickler.create ~name:"Response.Account_update"
       Unpickler.Spec.(
         Fields.fold
           ~currency:(fields_value (optional string))
           ~account_code:(fields_value (required Account_code.val_type)))
       (fun key value currency account_code ->
-        { key; value; currency; account_code })
+        { key; value; currency; account_code }))
 
   let pickler = Only_in_test.of_thunk (fun () ->
     Pickler.create ~name:"Response.Account_update"
       ~realized_pnl:(use Price.(=.))
       ~account_code:(use Account_code.(=))
 
-  let unpickler =
+  let unpickler = lazy (
     let contract_spec =
       Raw_contract.Unpickler_specs.portfolio_update_response ()
     in
             unrealized_pnl;
             realized_pnl;
             account_code;
-          })
+          }))
 
   let pickler = Only_in_test.of_thunk (fun () ->
     let contract_spec =
       ~trading_hours:(use (=))
       ~liquid_hours:(use (=))
 
-  let unpickler =
+  let unpickler = lazy (
     Unpickler.create ~name:"Response.Contract_specs"
       Unpickler.Spec.(
         Fields.fold
             timezone_id;
             trading_hours;
             liquid_hours;
-          })
+          }))
 
   let pickler = Only_in_test.of_thunk (fun () ->
     Pickler.create ~name:"Response.Contract_specs"
       ~average_price:(use Price.(=.))
       ~order_ref:(use (=))
 
-  let unpickler =
+  let unpickler = lazy (
     let contract_spec =
       Raw_contract.Unpickler_specs.execution_report_response ()
     in
             cumulative_quantity;
             average_price;
             order_ref;
-          })
+          }))
 
   let pickler = Only_in_test.of_thunk (fun () ->
     let contract_spec =
       ~yield:(use Float.(=.))
       ~yield_redemption_date:(use (=))
 
-  let unpickler =
+  let unpickler = lazy (
     Unpickler.create ~name:"Response.Commission_report"
       Unpickler.Spec.(
         Fields.fold
             realized_pnl;
             yield;
             yield_redemption_date;
-          })
+          }))
 
   let pickler = Only_in_test.of_thunk (fun () ->
     Pickler.create ~name:"Response.Commission_report"
       ~price:(use Price.(=.))
       ~size:(use (=))
 
-  let unpickler =
+  let unpickler = lazy (
     Unpickler.create ~name:"Response.Book_update"
       Unpickler.Spec.(
         Fields.fold
           ~price:(fields_value (required Price.val_type))
           ~size:(fields_value (required int)))
       (fun position operation side price size ->
-        { position; operation; side; price; size })
+        { position; operation; side; price; size }))
 
   let pickler = Only_in_test.of_thunk (fun () ->
     Pickler.create ~name:"Response.Book_update"
         ~has_gaps:(use (=))
         ~count:(use (=))
 
-    let unpickler =
+    let unpickler = lazy (
       Unpickler.create ~name:"Response.Historical_data.Bar"
         Unpickler.Spec.(
           Fields.fold
             wap;
             has_gaps = Bool.of_string has_gaps;
             count;
-          })
+          }))
 
     let pickler = Only_in_test.of_thunk (fun () ->
       Pickler.create ~name:"Response.Historical_data.Bar"
       ~num_bars:(use (=))
       ~bars:(use (List.for_all2_exn ~f:Bar.(=)))
 
-  let unpickler =
+  let unpickler = lazy (
     Unpickler.create ~name:"Response.Historical_data"
       Unpickler.Spec.(
         Fields.fold
             Array.sub bars_msg ~pos:(num_fields * i) ~len:num_fields
             |> Queue.of_array
           in
-          Unpickler.run_exn Bar.unpickler bar_msg)
+          Unpickler.run_exn (Lazy.force Bar.unpickler) bar_msg)
         in
         { start_time;
           end_time;
           num_bars;
           bars
-        })
+        }))
 
   let pickler = Only_in_test.of_thunk (fun () ->
     Pickler.create ~name:"Response.Historical_data"
       ~wap:(use Price.(=.))
       ~count:(use (=))
 
-  let unpickler =
+  let unpickler = lazy (
     Unpickler.create ~name:"Response.Realtime_bar"
       Unpickler.Spec.(
         Fields.fold
             volume;
             wap;
             count;
-          })
+          }))
 
   let pickler = Only_in_test.of_thunk (fun () ->
     Pickler.create ~name:"Response.Realtime_bar"

File lib/submit_order.ml

     ~algo_strategy:(use (=))
     ~request_pre_trade_information:(use (=))
 
-let pickler =
+let pickler = lazy (
   Pickler.create ~name:"Submit-Order"
     Pickler.Spec.(
       wrap (
             $ t.not_held
             $ t.underlying_combo
             $ t.algo_strategy
-            $ t.request_pre_trade_information))
+            $ t.request_pre_trade_information)))
 
 let unpickler = Only_in_test.of_thunk (fun () ->
   Unpickler.create ~name:"Submit-order"

File lib/tws_prot.ml

         serialize_opt default_on_none val_type.Val_type.tws_of_a a buf);
     }
 
-
-
     let skipped_if_none val_type = {
       value = (fun a_opt buf ->
         match a_opt with

File lib/tws_reqs.ml

 module S = Send_tag
 module R = Recv_tag
 
+let map_u u ~f = lazy (U.map (Lazy.force u) ~f)
+
 (* ==================== Connection and server ===================== *)
 
 let req_server_time = Ib.Request.create
   ]
   ~tws_query:Query.Market_data.pickler
   ~tws_response:[
-    U.map Response.Tick_price.unpickler  ~f:(fun x -> `Tick_price  x);
-    U.map Response.Tick_size.unpickler   ~f:(fun x -> `Tick_size   x);
-    U.map Response.Tick_option.unpickler ~f:(fun x -> `Tick_option x);
-    U.map Response.Tick_string.unpickler ~f:(fun x -> `Tick_string x);
+    map_u Response.Tick_price.unpickler  ~f:(fun x -> `Tick_price  x);
+    map_u Response.Tick_size.unpickler   ~f:(fun x -> `Tick_size   x);
+    map_u Response.Tick_option.unpickler ~f:(fun x -> `Tick_option x);
+    map_u Response.Tick_string.unpickler ~f:(fun x -> `Tick_string x);
   ] ()
 
 let req_option_price = Ib.Streaming_request.create
   ~recv_header:[Ib.Header.create ~tag:R.Tick_option ~version:6]
   ~tws_query:Query.Option_price.pickler
   ~tws_response:[
-    U.map Response.Tick_option.unpickler ~f:Response.Tick_option.option_price;
+    map_u Response.Tick_option.unpickler ~f:Response.Tick_option.option_price;
   ] ()
 
 let req_implied_volatility = Ib.Streaming_request.create
   ~recv_header:[Ib.Header.create ~tag:R.Tick_option ~version:6]
   ~tws_query:Query.Implied_volatility.pickler
   ~tws_response:[
-    U.map Response.Tick_option.unpickler ~f:Response.Tick_option.implied_volatility;
+    map_u Response.Tick_option.unpickler ~f:Response.Tick_option.implied_volatility;
   ] ()
 
 (* ===================== Contract specs ========================= *)
   ~skip_header:[Ib.Header.create ~tag:R.Account_update_time ~version:1]
   ~tws_query:Query.Account_and_portfolio_updates.pickler
   ~tws_response:[
-    U.map Response.Account_update.unpickler ~f:(fun x -> `Account_update x);
-    U.map Response.Portfolio_update.unpickler ~f:(fun x -> `Portfolio_update x);
-    U.map Account_code.unpickler ~f:(fun x -> `Account_update_end x);
+    map_u Response.Account_update.unpickler ~f:(fun x -> `Account_update x);
+    map_u Response.Portfolio_update.unpickler ~f:(fun x -> `Portfolio_update x);
+    map_u Account_code.unpickler ~f:(fun x -> `Account_update_end x);
   ] ()
 
 (* ===================== Execution reports ======================== *)
   ]
   ~tws_query:Query.Execution_reports.pickler
   ~tws_response:[
-    U.map Response.Execution_report.unpickler ~f:(fun x -> `Execution_report x);
-    U.const `Execution_report_end;
+    map_u Response.Execution_report.unpickler ~f:(fun x -> `Execution_report x);
+    lazy (U.const `Execution_report_end);
   ] ()
 
 (* ======================== Market depth ========================== *)
   ]
   ~tws_query:Query.Market_data.pickler
   ~tws_response:[
-    U.map Response.Tick_price.unpickler ~f:(fun x -> `Tick_price x);
-    U.map Response.Tick_size.unpickler  ~f:(fun x -> `Tick_size  x);
+    map_u Response.Tick_price.unpickler ~f:(fun x -> `Tick_price x);
+    map_u Response.Tick_size.unpickler  ~f:(fun x -> `Tick_size  x);
   ] ()
 
 let req_taq_snapshot = Ib.Streaming_request.create

File lib/unpickable.ml

 
 module type S = sig
   type t
-  val unpickler : t Unpickler.t
+  val unpickler : t Unpickler.t Lazy.t
 end

File lib_test/connection_test.ml

 
     "unpickler-mismatch" >:: (fun () ->
       let module U = Tws_prot.Unpickler in
+      let map_u u ~f = lazy (U.map (Lazy.force u) ~f) in
       let buggy_req =
         Ib.Streaming_request.create
           ~send_header:(Ib.Header.create ~tag:Send_tag.Market_data ~version:9)
           ]
           ~tws_query:Query.Market_data.pickler
           ~tws_response:[
-            U.map Response.Tick_price.unpickler ~f:(fun x -> `Tick_price x);
-            U.map Response.Tick_size.unpickler  ~f:(fun x -> `Tick_size  x);
+            map_u Response.Tick_price.unpickler ~f:(fun x -> `Tick_price x);
+            map_u Response.Tick_size.unpickler  ~f:(fun x -> `Tick_size  x);
           ] ()
       in
       unix_pipe ()

File lib_test/pickle_test.ml

 open Ibx.Std
 open Test_lib
 
-let to_tws = Tws_prot.Pickler.run
-let of_tws = Tws_prot.Unpickler.run_exn
+module P = Tws_prot.Pickler
+module U = Tws_prot.Unpickler
+
+let to_tws  p x = P.run (Lazy.force p) x
+let of_tws  u x = U.run_exn (Lazy.force u) x
+
+let to_tws' p x = P.run (Only_in_test.force p) x
+let of_tws' u x = U.run_exn (Only_in_test.force u) x
 
 let input_of_output output =
   let truncate_null s = String.sub s ~pos:0 ~len:(String.length s - 1) in
     let expected = query_g () in
     let module Q = (val query : Query_intf.S with type t = s) in
     let output = to_tws Q.pickler expected in
-    let actual = of_tws (Only_in_test.force Q.unpickler) (input_of_output output) in
+    let actual = of_tws' Q.unpickler (input_of_output output) in
     assert_query_equal query ~expected ~actual;
     Deferred.unit
 
   let gen_test (type s) response response_g =
     let expected = response_g () in
     let module R = (val response : Response_intf.S with type t = s) in
-    let output = to_tws (Only_in_test.force R.pickler) expected in
-    let actual = of_tws R.unpickler (input_of_output output) in
+    let output = to_tws' R.pickler expected in
+    let actual = of_tws  R.unpickler (input_of_output output) in
     assert_response_equal response ~expected ~actual;
     Deferred.unit