ib-ruby 0.7.8 → 0.7.9

Sign up to get free protection for your applications and to get access to all the features.
data/HISTORY CHANGED
@@ -169,3 +169,7 @@
169
169
  == 0.7.8 / 2012-04-23
170
170
 
171
171
  * Models are now fully DB-backed
172
+
173
+ == 0.7.9 / 2012-04-24
174
+
175
+ * Order and OrderState API extended
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.7.8
1
+ 0.7.9
@@ -27,11 +27,20 @@ module IB
27
27
  # Comparison support
28
28
  def content_attributes
29
29
  HashWithIndifferentAccess[attributes.reject do |(attr, _)|
30
- attr.to_s =~ /(_id|_count)$/ ||
31
- [:created_at, :updated_at, :type, :id].include?(attr.to_sym)
30
+ attr.to_s =~ /(_count)$/ ||
31
+ [:created_at, :updated_at, :type,
32
+ :id, :order_id, :contract_id].include?(attr.to_sym)
32
33
  end]
33
34
  end
34
35
 
36
+ # Update nil attributes from given Hash or model
37
+ def update_missing attrs
38
+ attrs = attrs.content_attributes unless attrs.kind_of?(Hash)
39
+
40
+ attrs.each { |attr, val| send "#{attr}=", val if send(attr).blank? }
41
+ self # for chaining
42
+ end
43
+
35
44
  # Default Model comparison
36
45
  def == other
37
46
  content_attributes.inject(true) { |res, (attr, value)| res && other.send(attr) == value } &&
@@ -73,58 +82,58 @@ module IB
73
82
  def self.define_property_methods name, body={}
74
83
  #p name, body
75
84
  case body
76
- when '' # default getter and setter
77
- define_property_methods name
78
-
79
- when Array # [setter, getter, validators]
80
- define_property_methods name,
81
- :get => body[0],
82
- :set => body[1],
83
- :validate => body[2]
84
-
85
- when Hash # recursion base case
86
- getter = case # Define getter
87
- when body[:get].respond_to?(:call)
88
- body[:get]
89
- when body[:get]
90
- proc { self[name].send "to_#{body[:get]}" }
91
- when VALUES[name] # property is encoded
92
- proc { VALUES[name][self[name]] }
93
- #when respond_to?(:column_names) && column_names.include?(name.to_s)
94
- # # noop, ActiveRecord will take care of it...
95
- # p "#{name} => get noop"
96
- # p respond_to?(:column_names) && column_names
97
- else
98
- proc { self[name] }
99
- end
100
- define_method name, &getter if getter
101
-
102
- setter = case # Define setter
103
- when body[:set].respond_to?(:call)
104
- body[:set]
105
- when body[:set]
106
- proc { |value| self[name] = value.send "to_#{body[:set]}" }
107
- when CODES[name] # property is encoded
108
- proc { |value| self[name] = CODES[name][value] || value }
109
- else
110
- proc { |value| self[name] = value } # p name, value;
111
- end
112
- define_method "#{name}=", &setter if setter
113
-
114
- # Define validator(s)
115
- [body[:validate]].flatten.compact.each do |validator|
116
- case validator
117
- when Proc
118
- validates_each name, &validator
119
- when Hash
120
- validates name, validator.dup
121
- end
85
+ when '' # default getter and setter
86
+ define_property_methods name
87
+
88
+ when Array # [setter, getter, validators]
89
+ define_property_methods name,
90
+ :get => body[0],
91
+ :set => body[1],
92
+ :validate => body[2]
93
+
94
+ when Hash # recursion base case
95
+ getter = case # Define getter
96
+ when body[:get].respond_to?(:call)
97
+ body[:get]
98
+ when body[:get]
99
+ proc { self[name].send "to_#{body[:get]}" }
100
+ when VALUES[name] # property is encoded
101
+ proc { VALUES[name][self[name]] }
102
+ #when respond_to?(:column_names) && column_names.include?(name.to_s)
103
+ # # noop, ActiveRecord will take care of it...
104
+ # p "#{name} => get noop"
105
+ # p respond_to?(:column_names) && column_names
106
+ else
107
+ proc { self[name] }
108
+ end
109
+ define_method name, &getter if getter
110
+
111
+ setter = case # Define setter
112
+ when body[:set].respond_to?(:call)
113
+ body[:set]
114
+ when body[:set]
115
+ proc { |value| self[name] = value.send "to_#{body[:set]}" }
116
+ when CODES[name] # property is encoded
117
+ proc { |value| self[name] = CODES[name][value] || value }
118
+ else
119
+ proc { |value| self[name] = value } # p name, value;
120
+ end
121
+ define_method "#{name}=", &setter if setter
122
+
123
+ # Define validator(s)
124
+ [body[:validate]].flatten.compact.each do |validator|
125
+ case validator
126
+ when Proc
127
+ validates_each name, &validator
128
+ when Hash
129
+ validates name, validator.dup
122
130
  end
131
+ end
123
132
 
124
133
  # TODO define self[:name] accessors for :virtual and :flag properties
125
134
 
126
- else # setter given
127
- define_property_methods name, :set => body, :get => body
135
+ else # setter given
136
+ define_property_methods name, :set => body, :get => body
128
137
  end
129
138
  end
130
139
 
@@ -264,7 +264,13 @@ module IB
264
264
  :last_fill_price, # double
265
265
  :average_price, # double
266
266
  :average_fill_price, # double
267
- :why_held # String: comma-separated list of reasons for order to be held.
267
+ :why_held, # String: comma-separated list of reasons for order to be held.
268
+ # Testing Order state:
269
+ :new?,
270
+ :pending?,
271
+ :active?,
272
+ :inactive?,
273
+ :complete_fill?,
268
274
  ].each { |property| define_method(property) { order_state.send(property) } }
269
275
 
270
276
  # Order is not valid without correct :local_id (:order_id)
@@ -63,6 +63,31 @@ module IB
63
63
  validates_numericality_of :local_id, :perm_id, :client_id, :parent_id, :filled,
64
64
  :remaining, :only_integer => true, :allow_nil => true
65
65
 
66
+ ## Testing Order state:
67
+
68
+ def new?
69
+ status.empty? || status == 'New'
70
+ end
71
+
72
+ # Order is in a valid, working state on TWS side
73
+ def pending?
74
+ status == 'PendingSubmit' || status == 'PreSubmitted' || status == 'Submitted'
75
+ end
76
+
77
+ # Order is in invalid state
78
+ def active?
79
+ new? || pending?
80
+ end
81
+
82
+ # Order is in invalid state
83
+ def inactive?
84
+ !active? # status == 'Inactive'
85
+ end
86
+
87
+ def complete_fill?
88
+ status == 'Filled' && remaining == 0 # filled >= total_quantity # Manually corrected
89
+ end
90
+
66
91
  # Comparison
67
92
  def == other
68
93
  other && other.is_a?(OrderState) &&
@@ -117,7 +117,30 @@ describe IB::Models::Order do
117
117
 
118
118
  it 'has extra accessors to OrderState properties' do
119
119
  subject.order_state.should_not be_nil
120
+
120
121
  subject.status.should == 'New'
122
+ subject.commission.should be_nil
123
+ subject.commission_currency.should be_nil
124
+ subject.min_commission.should be_nil
125
+ subject.max_commission.should be_nil
126
+ subject.warning_text.should be_nil
127
+ subject.init_margin.should be_nil
128
+ subject.maint_margin.should be_nil
129
+ subject.equity_with_loan.should be_nil
130
+ # Properties arriving via OrderStatus messagesubject.
131
+ subject.filled.should be_nil
132
+ subject.remaining.should be_nil
133
+ subject.price.should be_nil
134
+ subject.last_fill_price.should be_nil
135
+ subject.average_price.should be_nil
136
+ subject.average_fill_price.should be_nil
137
+ subject.why_held.should be_nil
138
+ # Testing Order statesubject.
139
+ subject.should be_new
140
+ subject.should_not be_pending
141
+ subject.should be_active
142
+ subject.should_not be_inactive
143
+ subject.should_not be_complete_fill
121
144
  end
122
145
 
123
146
  context 'update Order state by ' do
@@ -38,7 +38,7 @@ describe IB::Models::OrderState do
38
38
  let(:assigns) do
39
39
  {[:status] =>
40
40
  {[nil, ''] => /must not be empty/,
41
- ['Zorro', :Zorro] => 'Zorro' }
41
+ ['Zorro', :Zorro] => 'Zorro'}
42
42
  }
43
43
  end
44
44
 
@@ -52,4 +52,64 @@ describe IB::Models::OrderState do
52
52
  it_behaves_like 'Model'
53
53
  it_behaves_like 'Self-equal Model'
54
54
 
55
+ context '#update_missing' do
56
+ context 'updating with Hash' do
57
+
58
+ subject { IB::OrderState.new.update_missing(props) }
59
+
60
+ it_behaves_like 'Model instantiated with properties'
61
+
62
+ end
63
+
64
+ context 'updating with Model' do
65
+
66
+ subject { IB::OrderState.new.update_missing(IB::OrderState.new(props)) }
67
+
68
+ it_behaves_like 'Model instantiated with properties'
69
+
70
+ end
71
+
72
+ end
73
+
74
+ it 'has extra test methods' do
75
+ empty_state = IB::OrderState.new
76
+ empty_state.should be_new
77
+ empty_state.should be_active
78
+ empty_state.should_not be_inactive
79
+ empty_state.should_not be_complete_fill
80
+
81
+ state = IB::OrderState.new(props)
82
+ ['PendingSubmit', 'PreSubmitted', 'Submitted'].each do |status|
83
+ state.status = status
84
+ state.should_not be_new
85
+ state.should be_active
86
+ state.should_not be_inactive
87
+ state.should_not be_complete_fill
88
+ state.should be_pending
89
+ end
90
+
91
+ ['PendingCancel', 'Cancelled', 'ApiCancelled', 'Inactive'].each do |status|
92
+ state.status = status
93
+ state.should_not be_new
94
+ state.should_not be_active
95
+ state.should be_inactive
96
+ state.should_not be_complete_fill
97
+ state.should_not be_pending
98
+ end
99
+
100
+ state.status = 'Filled'
101
+ state.should_not be_new
102
+ state.should_not be_active
103
+ state.should be_inactive
104
+ state.should_not be_complete_fill
105
+ state.should_not be_pending
106
+
107
+ state.remaining = 0
108
+ state.should_not be_new
109
+ state.should_not be_active
110
+ state.should be_inactive
111
+ state.should be_complete_fill
112
+ state.should_not be_pending
113
+ end
114
+
55
115
  end # describe IB::Order
metadata CHANGED
@@ -2,7 +2,7 @@
2
2
  name: ib-ruby
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 0.7.8
5
+ version: 0.7.9
6
6
  platform: ruby
7
7
  authors:
8
8
  - Paul Legato
@@ -11,7 +11,7 @@ autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
13
 
14
- date: 2012-04-23 00:00:00 Z
14
+ date: 2012-04-24 00:00:00 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: bundler