ig_markets 0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (93) hide show
  1. checksums.yaml +7 -0
  2. data/.codeclimate.yml +15 -0
  3. data/.gitignore +9 -0
  4. data/.rspec +2 -0
  5. data/.rubocop.yml +2 -0
  6. data/.travis.yml +10 -0
  7. data/.yardopts +4 -0
  8. data/Gemfile +2 -0
  9. data/LICENSE.md +25 -0
  10. data/README.md +134 -0
  11. data/ig_markets.gemspec +28 -0
  12. data/lib/ig_markets.rb +42 -0
  13. data/lib/ig_markets/account.rb +23 -0
  14. data/lib/ig_markets/account_activity.rb +24 -0
  15. data/lib/ig_markets/account_transaction.rb +49 -0
  16. data/lib/ig_markets/api_versions.rb +10 -0
  17. data/lib/ig_markets/application.rb +22 -0
  18. data/lib/ig_markets/boolean.rb +5 -0
  19. data/lib/ig_markets/client_sentiment.rb +16 -0
  20. data/lib/ig_markets/deal_confirmation.rb +41 -0
  21. data/lib/ig_markets/dealing_platform.rb +105 -0
  22. data/lib/ig_markets/dealing_platform/account_methods.rb +92 -0
  23. data/lib/ig_markets/dealing_platform/client_sentiment_methods.rb +26 -0
  24. data/lib/ig_markets/dealing_platform/market_methods.rb +59 -0
  25. data/lib/ig_markets/dealing_platform/position_methods.rb +164 -0
  26. data/lib/ig_markets/dealing_platform/sprint_market_position_methods.rb +46 -0
  27. data/lib/ig_markets/dealing_platform/watchlist_methods.rb +42 -0
  28. data/lib/ig_markets/dealing_platform/working_order_methods.rb +115 -0
  29. data/lib/ig_markets/historical_price_result.rb +33 -0
  30. data/lib/ig_markets/instrument.rb +89 -0
  31. data/lib/ig_markets/market.rb +99 -0
  32. data/lib/ig_markets/market_hierarchy_result.rb +13 -0
  33. data/lib/ig_markets/market_overview.rb +24 -0
  34. data/lib/ig_markets/model.rb +185 -0
  35. data/lib/ig_markets/password_encryptor.rb +31 -0
  36. data/lib/ig_markets/payload_formatter.rb +38 -0
  37. data/lib/ig_markets/position.rb +191 -0
  38. data/lib/ig_markets/regex.rb +10 -0
  39. data/lib/ig_markets/request_failed_error.rb +21 -0
  40. data/lib/ig_markets/response_parser.rb +35 -0
  41. data/lib/ig_markets/session.rb +186 -0
  42. data/lib/ig_markets/sprint_market_position.rb +17 -0
  43. data/lib/ig_markets/version.rb +4 -0
  44. data/lib/ig_markets/watchlist.rb +37 -0
  45. data/lib/ig_markets/working_order.rb +68 -0
  46. data/spec/factories/ig_markets/account.rb +14 -0
  47. data/spec/factories/ig_markets/account_activity.rb +21 -0
  48. data/spec/factories/ig_markets/account_balance.rb +8 -0
  49. data/spec/factories/ig_markets/account_transaction.rb +15 -0
  50. data/spec/factories/ig_markets/application.rb +21 -0
  51. data/spec/factories/ig_markets/client_sentiment.rb +7 -0
  52. data/spec/factories/ig_markets/deal_confirmation.rb +20 -0
  53. data/spec/factories/ig_markets/historical_price_result.rb +7 -0
  54. data/spec/factories/ig_markets/historical_price_result_data_allowance.rb +7 -0
  55. data/spec/factories/ig_markets/historical_price_result_price.rb +7 -0
  56. data/spec/factories/ig_markets/historical_price_result_snapshot.rb +10 -0
  57. data/spec/factories/ig_markets/instrument.rb +32 -0
  58. data/spec/factories/ig_markets/instrument_currency.rb +9 -0
  59. data/spec/factories/ig_markets/instrument_expiry_details.rb +6 -0
  60. data/spec/factories/ig_markets/instrument_margin_deposit_band.rb +8 -0
  61. data/spec/factories/ig_markets/instrument_opening_hours.rb +6 -0
  62. data/spec/factories/ig_markets/instrument_rollover_details.rb +6 -0
  63. data/spec/factories/ig_markets/instrument_slippage_factor.rb +6 -0
  64. data/spec/factories/ig_markets/market.rb +7 -0
  65. data/spec/factories/ig_markets/market_dealing_rules.rb +11 -0
  66. data/spec/factories/ig_markets/market_dealing_rules_rule_details.rb +6 -0
  67. data/spec/factories/ig_markets/market_hierarchy_result.rb +6 -0
  68. data/spec/factories/ig_markets/market_hierarchy_result_hierarchy_node.rb +6 -0
  69. data/spec/factories/ig_markets/market_overview.rb +22 -0
  70. data/spec/factories/ig_markets/market_snapshot.rb +17 -0
  71. data/spec/factories/ig_markets/position.rb +19 -0
  72. data/spec/factories/ig_markets/sprint_market_position.rb +16 -0
  73. data/spec/factories/ig_markets/watchlist.rb +9 -0
  74. data/spec/factories/ig_markets/working_order.rb +21 -0
  75. data/spec/ig_markets/account_transaction_spec.rb +30 -0
  76. data/spec/ig_markets/dealing_platform/account_methods_spec.rb +58 -0
  77. data/spec/ig_markets/dealing_platform/client_sentiment_methods_spec.rb +29 -0
  78. data/spec/ig_markets/dealing_platform/market_methods_spec.rb +80 -0
  79. data/spec/ig_markets/dealing_platform/position_methods_spec.rb +137 -0
  80. data/spec/ig_markets/dealing_platform/sprint_market_position_methods_spec.rb +39 -0
  81. data/spec/ig_markets/dealing_platform/watchlist_methods_spec.rb +89 -0
  82. data/spec/ig_markets/dealing_platform/working_order_methods_spec.rb +120 -0
  83. data/spec/ig_markets/dealing_platform_spec.rb +40 -0
  84. data/spec/ig_markets/model_spec.rb +127 -0
  85. data/spec/ig_markets/password_encryptor_spec.rb +23 -0
  86. data/spec/ig_markets/payload_formatter_spec.rb +19 -0
  87. data/spec/ig_markets/position_spec.rb +37 -0
  88. data/spec/ig_markets/response_parser_spec.rb +13 -0
  89. data/spec/ig_markets/session_spec.rb +134 -0
  90. data/spec/spec_helper.rb +14 -0
  91. data/spec/support/factory_girl.rb +7 -0
  92. data/spec/support/random_test_order.rb +3 -0
  93. metadata +261 -0
@@ -0,0 +1,10 @@
1
+ module IGMarkets
2
+ # Contains regex's for validating specific types of strings.
3
+ module Regex
4
+ # Regex used to validate an ISO currency code.
5
+ CURRENCY = /\A[A-Z]{3}\Z/
6
+
7
+ # Regex used to validate an EPIC.
8
+ EPIC = /\A[A-Z,a-z,0-9,.,_]{6,30}\Z/
9
+ end
10
+ end
@@ -0,0 +1,21 @@
1
+ module IGMarkets
2
+ # This error class is raised by {Session} when a request to the IG Markets API fails.
3
+ class RequestFailedError < StandardError
4
+ # @return [String] A description of the error that occurred when the request was attempted.
5
+ attr_reader :error
6
+
7
+ # @return [Fixnum] The HTTP code that was returned, or `nil` if unknown.
8
+ attr_reader :http_code
9
+
10
+ # Initializes this request failure error with a message and an HTTP code.
11
+ #
12
+ # @param [String] error The error description.
13
+ # @param [Integer] http_code The HTTP code for the request failure, if known.
14
+ def initialize(error, http_code = nil)
15
+ @error = error.to_s
16
+ @http_code = http_code ? http_code.to_i : nil
17
+
18
+ super "#<#{self.class.name} error: @error#{http_code ? ", http_code: #{http_code}" : ''}"
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,35 @@
1
+ module IGMarkets
2
+ # Contains methods for parsing responses received from the IG Markets API.
3
+ module ResponseParser
4
+ module_function
5
+
6
+ # Parses the specified value that was returned from a call to the IG Markets API.
7
+ #
8
+ # @param [Hash, Array, Object] response The response or part of a reponse that should be parsed. If this is of type
9
+ # `Hash` then all hash keys will converted from camel case into snake case and their values each to parsed
10
+ # individually by a recursive call. If this is of type `Array` then each item will be parsed indidiaully by a
11
+ # recursive call. All other types are passed through unchanged.
12
+ #
13
+ # @return [Hash, Array, Object] The parsed object, the type depends on the type of the `response` parameter.
14
+ def parse(response)
15
+ if response.is_a? Hash
16
+ response.each_with_object({}) do |(key, value), new_hash|
17
+ new_hash[camel_case_to_snake_case(key).downcase.to_sym] = parse(value)
18
+ end
19
+ elsif response.is_a? Array
20
+ response.map { |item| parse item }
21
+ else
22
+ response
23
+ end
24
+ end
25
+
26
+ # Converts a camel case string to a snake case string.
27
+ #
28
+ # @param [String, Symbol] camel_case The camel case `String` or `Symbol` to convert to snake case.
29
+ #
30
+ # @return [String]
31
+ def camel_case_to_snake_case(camel_case)
32
+ camel_case.to_s.gsub(/([a-z])([A-Z])/, '\1_\2').gsub(/([A-Z])([A-Z])([a-z])/, '\1_\2\3')
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,186 @@
1
+ module IGMarkets
2
+ # Manages a session with the IG Markets REST API, including signing in, signing out, and the sending of requests.
3
+ # In order to sign in, {#username}, {#password}, {#api_key} and {#platform} must be set. {#platform} must be
4
+ # either `:demo` or `:production` depending on which platform is being targeted.
5
+ class Session
6
+ # @return [String] The username to use to authenticate this session.
7
+ attr_accessor :username
8
+
9
+ # @return [String] The password to use to authenticate this session.
10
+ attr_accessor :password
11
+
12
+ # @return [String] The API key to use to authenticate this session.
13
+ attr_accessor :api_key
14
+
15
+ # @return [:demo, :production] The platform variant to log into for this session.
16
+ attr_accessor :platform
17
+
18
+ # @return [String] The CST for the currently logged in session, or nil if there is no active session.
19
+ attr_reader :cst
20
+
21
+ # @return [String] The security token for the currently logged in session, or nil if there is no active session.
22
+ attr_reader :x_security_token
23
+
24
+ # Signs in to IG Markets using the values of {#username}, {#password}, {#api_key} and {#platform}. If an error
25
+ # occurs then {RequestFailedError} will be raised.
26
+ def sign_in
27
+ validate_authentication
28
+
29
+ payload = { identifier: username, password: password_encryptor.encrypt(password), encryptedPassword: true }
30
+
31
+ sign_in_result = request method: :post, url: 'session', payload: payload, api_version: API_V1
32
+
33
+ headers = sign_in_result.fetch(:response).headers
34
+ @cst = headers.fetch :cst
35
+ @x_security_token = headers.fetch :x_security_token
36
+
37
+ nil
38
+ end
39
+
40
+ # Signs out of IG Markets, ending the current session (if any). If an error occurs then {RequestFailedError} will be
41
+ # raised.
42
+ def sign_out
43
+ delete 'session', nil, API_V1 if alive?
44
+
45
+ @cst = @x_security_token = nil
46
+ end
47
+
48
+ # Returns whether this session is currently alive and successfully signed in.
49
+ #
50
+ # @return [Boolean]
51
+ def alive?
52
+ !cst.nil? && !x_security_token.nil?
53
+ end
54
+
55
+ # Sends a POST request to the IG Markets API. If an error occurs then {RequestFailedError} will be raised.
56
+ #
57
+ # @param [String] url The URL to send the POST request to.
58
+ # @param [nil, String, Hash] payload The payload to include with the POST request, this will be encoded as JSON.
59
+ # @param [Fixnum] api_version The API version to target.
60
+ #
61
+ # @return [Hash] The response from the IG Markets API.
62
+ def post(url, payload, api_version)
63
+ request(method: :post, url: url, payload: payload, api_version: api_version).fetch :result
64
+ end
65
+
66
+ # Sends a GET request to the IG Markets API. If an error occurs then {RequestFailedError} will be raised.
67
+ #
68
+ # @param [String] url The URL to send the GET request to.
69
+ # @param [Fixnum] api_version The API version to target.
70
+ #
71
+ # @return [Hash] The response from the IG Markets API.
72
+ def get(url, api_version)
73
+ request(method: :get, url: url, api_version: api_version).fetch :result
74
+ end
75
+
76
+ # Sends a PUT request to the IG Markets API. If an error occurs then {RequestFailedError} will be raised.
77
+ #
78
+ # @param [String] url The URL to send the PUT request to.
79
+ # @param [nil, String, Hash] payload The payload to include with the PUT request, this will be encoded as JSON.
80
+ # @param [Fixnum] api_version The API version to target.
81
+ #
82
+ # @return [Hash] The response from the IG Markets API.
83
+ def put(url, payload, api_version)
84
+ request(method: :put, url: url, payload: payload, api_version: api_version).fetch :result
85
+ end
86
+
87
+ # Sends a DELETE request to the IG Markets API. If an error occurs then {RequestFailedError} will be raised.
88
+ #
89
+ # @param [String] url The URL to send the DELETE request to.
90
+ # @param [nil, String, Hash] payload The payload to include with the DELETE request, this will be encoded as JSON.
91
+ # @param [Fixnum] api_version The API version to target.
92
+ #
93
+ # @return [Hash] The response from the IG Markets API.
94
+ def delete(url, payload, api_version)
95
+ request(method: :delete, url: url, payload: payload, api_version: api_version).fetch :result
96
+ end
97
+
98
+ # Returns a human-readable string containing this session's details.
99
+ #
100
+ # @return [String]
101
+ def inspect
102
+ "#<#{self.class.name} #{cst}, #{x_security_token}>"
103
+ end
104
+
105
+ private
106
+
107
+ HOST_URLS = {
108
+ demo: 'https://demo-api.ig.com/gateway/deal/',
109
+ production: 'https://api.ig.com/gateway/deal/'
110
+ }.freeze
111
+
112
+ def validate_authentication
113
+ %i(username password api_key).each do |attribute|
114
+ raise ArgumentError, "#{attribute} is not set" if send(attribute).to_s.empty?
115
+ end
116
+
117
+ raise ArgumentError, 'platform is invalid' unless HOST_URLS.key? platform
118
+ end
119
+
120
+ def password_encryptor
121
+ result = get 'session/encryptionKey', API_V1
122
+
123
+ PasswordEncryptor.new.tap do |encryptor|
124
+ encryptor.encoded_public_key = result.fetch :encryption_key
125
+ encryptor.time_stamp = result.fetch :time_stamp
126
+ end
127
+ end
128
+
129
+ def request(options)
130
+ options[:url] = "#{HOST_URLS.fetch(platform)}#{URI.escape(options[:url])}"
131
+ options[:headers] = request_headers(options)
132
+ options[:payload] = options[:payload] && options[:payload].to_json
133
+
134
+ response = execute_request options
135
+ result = process_response response
136
+
137
+ { response: response, result: result }
138
+ end
139
+
140
+ def request_headers(options)
141
+ headers = {}
142
+
143
+ headers[:content_type] = headers[:accept] = 'application/json; charset=UTF-8'
144
+ headers[:'X-IG-API-KEY'] = api_key
145
+ headers[:version] = options.delete :api_version
146
+
147
+ headers[:cst] = cst if cst
148
+ headers[:x_security_token] = x_security_token if x_security_token
149
+
150
+ headers
151
+ end
152
+
153
+ def use_post_for_delete_with_payload(options)
154
+ if options[:method] == :delete && options[:payload]
155
+ options[:headers]['_method'] = :delete
156
+ options[:method] = :post
157
+ end
158
+ end
159
+
160
+ def execute_request(options)
161
+ use_post_for_delete_with_payload options
162
+
163
+ RestClient::Request.execute options
164
+ rescue RestClient::Exception => exception
165
+ return exception.response if exception.response
166
+
167
+ raise RequestFailedError, exception.message
168
+ rescue SocketError => socket_error
169
+ raise RequestFailedError, socket_error
170
+ end
171
+
172
+ def process_response(response)
173
+ result = begin
174
+ ResponseParser.parse JSON.parse(response.body, symbolize_names: true)
175
+ rescue JSON::ParserError
176
+ {}
177
+ end
178
+
179
+ unless response.code >= 200 && response.code < 300
180
+ raise RequestFailedError.new(result[:error_code], response.code)
181
+ end
182
+
183
+ result
184
+ end
185
+ end
186
+ end
@@ -0,0 +1,17 @@
1
+ module IGMarkets
2
+ # Contains details on a sprint market position. Returned by {DealingPlatform::SprintMarketPositionMethods#all}.
3
+ class SprintMarketPosition < Model
4
+ attribute :created_date, DateTime, format: '%Y/%m/%d %H:%M:%S:%L'
5
+ attribute :currency, String, regex: Regex::CURRENCY
6
+ attribute :deal_id
7
+ attribute :description
8
+ attribute :direction, Symbol, allowed_values: [:buy, :sell]
9
+ attribute :epic, String, regex: Regex::EPIC
10
+ attribute :expiry_time, DateTime, format: '%Y/%m/%d %H:%M:%S:%L'
11
+ attribute :instrument_name
12
+ attribute :market_status, Symbol, allowed_values: Market::Snapshot.allowed_values(:market_status)
13
+ attribute :payout_amount, Float
14
+ attribute :size, Fixnum
15
+ attribute :strike_level, Float
16
+ end
17
+ end
@@ -0,0 +1,4 @@
1
+ module IGMarkets
2
+ # The version of this gem.
3
+ VERSION = '0.1'.freeze
4
+ end
@@ -0,0 +1,37 @@
1
+ module IGMarkets
2
+ # Contains details on a watchlist. Returned by {DealingPlatform::WatchlistMethods#all} and
3
+ # {DealingPlatform::WatchlistMethods#[]}.
4
+ class Watchlist < Model
5
+ attribute :default_system_watchlist, Boolean
6
+ attribute :deleteable, Boolean
7
+ attribute :editable, Boolean
8
+ attribute :id
9
+ attribute :name
10
+
11
+ # Returns the markets for this watchlist.
12
+ #
13
+ # @return [Array<Market>]
14
+ def markets
15
+ @dealing_platform.gather "watchlists/#{id}", :markets, MarketOverview
16
+ end
17
+
18
+ # Deletes this watchlist.
19
+ def delete
20
+ @dealing_platform.session.delete "watchlists/#{id}", nil, API_V1
21
+ end
22
+
23
+ # Adds a market to this watchlist.
24
+ #
25
+ # @param [String] epic The EPIC of the market to add to this watchlist.
26
+ def add_market(epic)
27
+ @dealing_platform.session.put "watchlists/#{id}", { epic: epic }, API_V1
28
+ end
29
+
30
+ # Removes a market from this watchlist.
31
+ #
32
+ # @param [String] epic The EPIC of the market to remove from this watchlist.
33
+ def remove_market(epic)
34
+ @dealing_platform.session.delete "watchlists/#{id}/#{epic}", nil, API_V1
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,68 @@
1
+ module IGMarkets
2
+ # Contains details on a working order. Returned by {DealingPlatform::WorkingOrderMethods#all} and
3
+ # {DealingPlatform::WorkingOrderMethods#[]}.
4
+ class WorkingOrder < Model
5
+ attribute :created_date, DateTime, format: '%Y/%m/%d %H:%M:%S:%L'
6
+ attribute :created_date_utc, DateTime, format: '%Y-%m-%dT%H:%M:%S'
7
+ attribute :currency_code, String, regex: Regex::CURRENCY
8
+ attribute :deal_id
9
+ attribute :direction, Symbol, allowed_values: [:buy, :sell]
10
+ attribute :dma, Boolean
11
+ attribute :epic, String, regex: Regex::EPIC
12
+ attribute :good_till_date, DateTime, format: '%Y/%m/%d %H:%M'
13
+ attribute :good_till_date_iso, DateTime, format: '%Y-%m-%dT%H:%M'
14
+ attribute :guaranteed_stop, Boolean
15
+ attribute :limit_distance, Fixnum
16
+ attribute :order_level, Float
17
+ attribute :order_size, Float
18
+ attribute :order_type, Symbol, allowed_values: [:limit, :stop]
19
+ attribute :stop_distance, Fixnum
20
+ attribute :time_in_force, Symbol, allowed_values: [:good_till_cancelled, :good_till_date]
21
+
22
+ attribute :market, MarketOverview
23
+
24
+ # Deletes this working order.
25
+ #
26
+ # @return [String] The deal reference of the deletion operation. Use {DealingPlatform#deal_confirmation} to check
27
+ # the result of the working order deletion.
28
+ def delete
29
+ @dealing_platform.session.delete("workingorders/otc/#{deal_id}", {}, API_V1).fetch(:deal_reference)
30
+ end
31
+
32
+ # Updates this working order. No attributes are mandatory, and any attributes not specified will be kept at the
33
+ # current value.
34
+ #
35
+ # @param [Hash] new_attributes The attributes of this working order to update. See
36
+ # {DealingPlatform::WorkingOrderMethods#create} for a description of the attributes.
37
+ # @option new_attributes [DateTime] :good_till_date
38
+ # @option new_attributes [Float] :level
39
+ # @option new_attributes [Float] :limit_distance
40
+ # @option new_attributes [Float] :stop_distance
41
+ # @option new_attributes [:good_till_cancelled, :good_till_date] :time_in_force
42
+ # @option new_attributes [:limit, :stop] :type
43
+ #
44
+ # @return [String] The deal reference of the update operation. Use {DealingPlatform#deal_confirmation} to check
45
+ # the result of the working order update.
46
+ def update(new_attributes)
47
+ new_attributes = { good_till_date: good_till_date, level: order_level, limit_distance: limit_distance,
48
+ stop_distance: stop_distance, time_in_force: time_in_force, type: order_type
49
+ }.merge new_attributes
50
+
51
+ payload = PayloadFormatter.format WorkingOrderUpdateAttributes.new new_attributes
52
+
53
+ @dealing_platform.session.put("workingorders/otc/#{deal_id}", payload, API_V1).fetch(:deal_reference)
54
+ end
55
+
56
+ # Internal model used by {#update}.
57
+ class WorkingOrderUpdateAttributes < Model
58
+ attribute :good_till_date, DateTime, format: '%Y/%m/%d %H:%M'
59
+ attribute :limit_distance, Float
60
+ attribute :level, Float
61
+ attribute :type, Symbol, allowed_values: [:limit, :stop]
62
+ attribute :stop_distance, Float
63
+ attribute :time_in_force, Symbol, allowed_values: [:good_till_cancelled, :good_till_date]
64
+ end
65
+
66
+ private_constant :WorkingOrderUpdateAttributes
67
+ end
68
+ end
@@ -0,0 +1,14 @@
1
+ FactoryGirl.define do
2
+ factory :account, class: IGMarkets::Account do
3
+ account_alias 'alias'
4
+ account_id 'A1234'
5
+ account_name 'CFD'
6
+ account_type 'CFD'
7
+ balance { build :account_balance }
8
+ can_transfer_from true
9
+ can_transfer_to true
10
+ currency 'USD'
11
+ preferred true
12
+ status 'ENABLED'
13
+ end
14
+ end
@@ -0,0 +1,21 @@
1
+ FactoryGirl.define do
2
+ factory :account_activity, class: IGMarkets::AccountActivity do
3
+ action_status 'ACCEPT'
4
+ activity 'S&L'
5
+ activity_history_id '443487452'
6
+ channel 'Charts'
7
+ currency '$'
8
+ date '20/12/15'
9
+ deal_id 'DIAAAAA4HDKPQEQ'
10
+ epic 'CS.D.NZDUSD.CFD.IP'
11
+ level '0.664'
12
+ limit '0.6649'
13
+ market_name 'Spot FX NZD/USD'
14
+ period '-'
15
+ result 'Result'
16
+ size '+1'
17
+ stop '-'
18
+ stop_type '-'
19
+ time '07:00'
20
+ end
21
+ end
@@ -0,0 +1,8 @@
1
+ FactoryGirl.define do
2
+ factory :account_balance, class: IGMarkets::Account::Balance do
3
+ available 5000.0
4
+ balance 5000.0
5
+ deposit 0.0
6
+ profit_loss 0.0
7
+ end
8
+ end
@@ -0,0 +1,15 @@
1
+ FactoryGirl.define do
2
+ factory :account_transaction, class: IGMarkets::AccountTransaction do
3
+ cash_transaction false
4
+ close_level '0.8'
5
+ currency 'US'
6
+ date '23/06/15'
7
+ instrument_name 'instrument'
8
+ open_level '0.8'
9
+ period '-'
10
+ profit_and_loss '0.0'
11
+ reference 'reference'
12
+ size '+1'
13
+ transaction_type 'DEAL'
14
+ end
15
+ end