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,21 @@
1
+ FactoryGirl.define do
2
+ factory :application, class: IGMarkets::Application do
3
+ id 1234
4
+ client_id '8761232322'
5
+ name 'TestAccount'
6
+ tier 'B2C'
7
+ api_key 'api_key'
8
+ status 'ENABLED'
9
+ allowance_application_overall 60.0
10
+ allowance_account_trading 100.0
11
+ allowance_account_overall 30.0
12
+ allowance_account_historical_data 1000.0
13
+ concurrent_subscriptions_limit 40
14
+ created_date 1_433_116_800_000
15
+ allow_equities false
16
+ allow_quote_orders false
17
+ restricted_to_self true
18
+ terms_accepted_date 1_433_116_800_000
19
+ fast_markets_settlement_price_enabled false
20
+ end
21
+ end
@@ -0,0 +1,7 @@
1
+ FactoryGirl.define do
2
+ factory :client_sentiment, class: IGMarkets::ClientSentiment do
3
+ long_position_percentage 60.0
4
+ market_id 'EURUSD'
5
+ short_position_percentage 40.0
6
+ end
7
+ end
@@ -0,0 +1,20 @@
1
+ FactoryGirl.define do
2
+ factory :deal_confirmation, class: IGMarkets::DealConfirmation do
3
+ affected_deals []
4
+ deal_id 'id'
5
+ deal_reference 'reference'
6
+ deal_status 'ACCEPTED'
7
+ direction 'BUY'
8
+ epic 'CS.D.EURUSD.CFD.IP'
9
+ expiry '20-DEC-40'
10
+ guaranteed_stop false
11
+ level 100.0
12
+ limit_distance 10.0
13
+ limit_level 110.0
14
+ reason 'SUCCESS'
15
+ size 1
16
+ stop_distance 10.0
17
+ stop_level 90.0
18
+ trailing_stop false
19
+ end
20
+ end
@@ -0,0 +1,7 @@
1
+ FactoryGirl.define do
2
+ factory :historical_price_result, class: IGMarkets::HistoricalPriceResult do
3
+ allowance { build :historical_price_result_data_allowance }
4
+ instrument_type :currencies
5
+ prices { [build(:historical_price_result_snapshot)] }
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ FactoryGirl.define do
2
+ factory :historical_price_result_data_allowance, class: IGMarkets::HistoricalPriceResult::DataAllowance do
3
+ allowance_expiry 1000
4
+ remaining_allowance 4990
5
+ total_allowance 5000
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ FactoryGirl.define do
2
+ factory :historical_price_result_price, class: IGMarkets::HistoricalPriceResult::Price do
3
+ ask 101.0
4
+ bid 99.0
5
+ last_traded nil
6
+ end
7
+ end
@@ -0,0 +1,10 @@
1
+ FactoryGirl.define do
2
+ factory :historical_price_result_snapshot, class: IGMarkets::HistoricalPriceResult::Snapshot do
3
+ close_price { build :historical_price_result_price }
4
+ high_price { build :historical_price_result_price }
5
+ last_traded_volume 100
6
+ low_price { build :historical_price_result_price }
7
+ open_price { build :historical_price_result_price }
8
+ snapshot_time '2015/06/16 00:00:00'
9
+ end
10
+ end
@@ -0,0 +1,32 @@
1
+ FactoryGirl.define do
2
+ factory :instrument, class: IGMarkets::Instrument do
3
+ chart_code 'code'
4
+ contract_size '+1'
5
+ controlled_risk_allowed false
6
+ country 'US'
7
+ currencies { [build(:instrument_currency)] }
8
+ epic 'ABCDEF'
9
+ expiry '20-DEC-40'
10
+ expiry_details { build :instrument_expiry_details }
11
+ force_open_allowed false
12
+ lot_size 1000.0
13
+ margin_deposit_bands { [build(:instrument_margin_deposit_band)] }
14
+ margin_factor 0.01
15
+ margin_factor_unit 'PERCENTAGE'
16
+ market_id 'market'
17
+ name 'instrument'
18
+ news_code 'news_code'
19
+ one_pip_means ''
20
+ opening_hours { { market_times: [build(:instrument_opening_hours)] } }
21
+ rollover_details { build :instrument_rollover_details }
22
+ slippage_factor { build :instrument_slippage_factor }
23
+ special_info %w(info_0 info_1)
24
+ sprint_markets_maximum_expiry_time 100.0
25
+ sprint_markets_minimum_expiry_time 10.0
26
+ stops_limits_allowed true
27
+ streaming_prices_available true
28
+ type 'SHARES'
29
+ unit 'SHARES'
30
+ value_of_one_pip 'pip'
31
+ end
32
+ end
@@ -0,0 +1,9 @@
1
+ FactoryGirl.define do
2
+ factory :instrument_currency, class: IGMarkets::Instrument::Currency do
3
+ base_exchange_rate 1.5
4
+ code 'USD'
5
+ exchange_rate '1.5'
6
+ is_default false
7
+ symbol 'USD'
8
+ end
9
+ end
@@ -0,0 +1,6 @@
1
+ FactoryGirl.define do
2
+ factory :instrument_expiry_details, class: IGMarkets::Instrument::ExpiryDetails do
3
+ last_dealing_date '2015/01/20 12:13:14'
4
+ settlement_info 'info'
5
+ end
6
+ end
@@ -0,0 +1,8 @@
1
+ FactoryGirl.define do
2
+ factory :instrument_margin_deposit_band, class: IGMarkets::Instrument::MarginDepositBand do
3
+ currency 'USD'
4
+ margin 0.01
5
+ max 0.01
6
+ min 0.01
7
+ end
8
+ end
@@ -0,0 +1,6 @@
1
+ FactoryGirl.define do
2
+ factory :instrument_opening_hours, class: IGMarkets::Instrument::OpeningHours do
3
+ close_time '5pm'
4
+ open_time '8am'
5
+ end
6
+ end
@@ -0,0 +1,6 @@
1
+ FactoryGirl.define do
2
+ factory :instrument_rollover_details, class: IGMarkets::Instrument::RolloverDetails do
3
+ last_rollover_time ''
4
+ rollover_info ''
5
+ end
6
+ end
@@ -0,0 +1,6 @@
1
+ FactoryGirl.define do
2
+ factory :instrument_slippage_factor, class: IGMarkets::Instrument::SlippageFactor do
3
+ unit 'USD'
4
+ value 1
5
+ end
6
+ end
@@ -0,0 +1,7 @@
1
+ FactoryGirl.define do
2
+ factory :market, class: IGMarkets::Market do
3
+ dealing_rules { build :market_dealing_rules }
4
+ instrument
5
+ snapshot { build :market_snapshot }
6
+ end
7
+ end
@@ -0,0 +1,11 @@
1
+ FactoryGirl.define do
2
+ factory :market_dealing_rules, class: IGMarkets::Market::DealingRules do
3
+ market_order_preference 'AVAILABLE_DEFAULT_ON'
4
+ trailing_stops_preference 'AVAILABLE'
5
+ max_stop_or_limit_distance { build :market_dealing_rules_rule_details }
6
+ min_controlled_risk_stop_distance { build :market_dealing_rules_rule_details }
7
+ min_deal_size { build :market_dealing_rules_rule_details }
8
+ min_normal_stop_or_limit_distance { build :market_dealing_rules_rule_details }
9
+ min_step_distance { build :market_dealing_rules_rule_details }
10
+ end
11
+ end
@@ -0,0 +1,6 @@
1
+ FactoryGirl.define do
2
+ factory :market_dealing_rules_rule_details, class: IGMarkets::Market::DealingRules::RuleDetails do
3
+ unit 'POINTS'
4
+ value 1.0
5
+ end
6
+ end
@@ -0,0 +1,6 @@
1
+ FactoryGirl.define do
2
+ factory :market_hierarchy_result, class: IGMarkets::MarketHierarchyResult do
3
+ markets { [build(:market_overview)] }
4
+ nodes { [build(:market_hierarchy_result_hierarchy_node)] }
5
+ end
6
+ end
@@ -0,0 +1,6 @@
1
+ FactoryGirl.define do
2
+ factory :market_hierarchy_result_hierarchy_node, class: IGMarkets::MarketHierarchyResult::HierarchyNode do
3
+ id '174882'
4
+ name 'Indices'
5
+ end
6
+ end
@@ -0,0 +1,22 @@
1
+ FactoryGirl.define do
2
+ factory :market_overview, class: IGMarkets::MarketOverview do
3
+ bid 100
4
+ delay_time 0.0
5
+ epic 'CS.D.EURUSD.CFD.IP'
6
+ exchange_id nil
7
+ expiry '-'
8
+ high 110.0
9
+ instrument_name 'Spot FX EUR/USD'
10
+ instrument_type 'CURRENCIES'
11
+ lot_size 10.0
12
+ low 90.0
13
+ market_status 'TRADEABLE'
14
+ net_change 5
15
+ offer 99
16
+ percentage_change 5
17
+ scaling_factor 10.0
18
+ streaming_prices_available true
19
+ update_time '01:09:48'
20
+ update_time_utc '04:09:48'
21
+ end
22
+ end
@@ -0,0 +1,17 @@
1
+ FactoryGirl.define do
2
+ factory :market_snapshot, class: IGMarkets::Market::Snapshot do
3
+ bid 100.0
4
+ binary_odds 0.5
5
+ controlled_risk_extra_spread 0.01
6
+ decimal_places_factor 1
7
+ delay_time 1
8
+ high 110.0
9
+ low 90.0
10
+ market_status 'TRADEABLE'
11
+ net_change 10.0
12
+ offer 99.0
13
+ percentage_change 10
14
+ scaling_factor 100
15
+ update_time '22:10:40'
16
+ end
17
+ end
@@ -0,0 +1,19 @@
1
+ FactoryGirl.define do
2
+ factory :position, class: IGMarkets::Position do
3
+ contract_size 1000.0
4
+ controlled_risk false
5
+ created_date '2015/08/17 10:27:28:000'
6
+ created_date_utc '2015-07-24T09:12:37'
7
+ currency 'USD'
8
+ deal_id 'DIAAAAA8JKPFTVA'
9
+ direction 'BUY'
10
+ level 100.0
11
+ limit_level 110.0
12
+ size 1
13
+ stop_level 90.0
14
+ trailing_step nil
15
+ trailing_stop_distance nil
16
+
17
+ market { build :market_overview }
18
+ end
19
+ end
@@ -0,0 +1,16 @@
1
+ FactoryGirl.define do
2
+ factory :sprint_market_position, class: IGMarkets::SprintMarketPosition do
3
+ created_date '2014/10/22 18:30:15:000'
4
+ currency 'USD'
5
+ deal_id 'deal_id'
6
+ description 'description'
7
+ direction 'BUY'
8
+ epic 'UA.D.AAPL.CASH.IP'
9
+ expiry_time '2014/10/22 19:30:14:000'
10
+ instrument_name 'instrument'
11
+ market_status 'TRADEABLE'
12
+ payout_amount 100.0
13
+ size 1
14
+ strike_level 110.0
15
+ end
16
+ end
@@ -0,0 +1,9 @@
1
+ FactoryGirl.define do
2
+ factory :watchlist, class: IGMarkets::Watchlist do
3
+ id '2547731'
4
+ name 'Markets'
5
+ editable false
6
+ deleteable false
7
+ default_system_watchlist false
8
+ end
9
+ end
@@ -0,0 +1,21 @@
1
+ FactoryGirl.define do
2
+ factory :working_order, class: IGMarkets::WorkingOrder do
3
+ created_date '2014/10/20 13:30:03:000'
4
+ currency_code 'USD'
5
+ deal_id 'deal_id'
6
+ direction 'BUY'
7
+ dma false
8
+ epic 'UA.D.AAPL.CASH.IP'
9
+ good_till_date '2015/10/20 10:45:29:000'
10
+ good_till_date_iso '2015-10-30T12:59'
11
+ guaranteed_stop false
12
+ limit_distance 1.0
13
+ order_level 100.0
14
+ order_size 1
15
+ order_type 'LIMIT'
16
+ stop_distance 1.0
17
+ time_in_force 'GOOD_TILL_DATE'
18
+
19
+ market { build :market_overview }
20
+ end
21
+ end
@@ -0,0 +1,30 @@
1
+ describe IGMarkets::DealingPlatform do
2
+ it 'correctly identifies interest payments' do
3
+ {
4
+ { transaction_type: :with, instrument_name: 'interest' } => true,
5
+ { transaction_type: :depo, instrument_name: ',interest' } => true,
6
+ { transaction_type: :with, instrument_name: 'interest,' } => true,
7
+ { transaction_type: :depo, instrument_name: ',interest,' } => true,
8
+ { transaction_type: :with, instrument_name: 'pinterest' } => false,
9
+ { transaction_type: :depo, instrument_name: 'interests' } => false
10
+ }.each do |attributes, result|
11
+ expect(build(:account_transaction, attributes).interest?).to eq(result)
12
+ end
13
+ end
14
+
15
+ it 'reports correct profit/loss amounts' do
16
+ expect(build(:account_transaction, currency: 'USD', profit_and_loss: 'USD10.10').profit_and_loss_amount).to eq(10.1)
17
+ expect(build(:account_transaction, currency: 'USD', profit_and_loss: 'USD-5.50').profit_and_loss_amount).to eq(-5.5)
18
+
19
+ expect { build(:account_transaction, currency: 'USD', profit_and_loss: 'EUR-5.0').profit_and_loss_amount }
20
+ .to raise_error(StandardError)
21
+ end
22
+
23
+ it 'formats transaction types' do
24
+ expect(build(:account_transaction, transaction_type: :deal).formatted_transaction_type).to eq('Deal')
25
+ expect(build(:account_transaction, transaction_type: :depo).formatted_transaction_type).to eq('Deposit')
26
+ expect(build(:account_transaction, transaction_type: :dividend).formatted_transaction_type).to eq('Dividend')
27
+ expect(build(:account_transaction, transaction_type: :exchange).formatted_transaction_type).to eq('Exchange')
28
+ expect(build(:account_transaction, transaction_type: :with).formatted_transaction_type).to eq('Withdrawal')
29
+ end
30
+ end
@@ -0,0 +1,58 @@
1
+ describe IGMarkets::DealingPlatform::AccountMethods do
2
+ let(:session) { IGMarkets::Session.new }
3
+ let(:platform) do
4
+ IGMarkets::DealingPlatform.new.tap do |platform|
5
+ platform.instance_variable_set :@session, session
6
+ end
7
+ end
8
+
9
+ it 'can retrieve accounts' do
10
+ accounts = [build(:account)]
11
+
12
+ expect(session).to receive(:get).with('accounts', IGMarkets::API_V1).and_return(accounts: accounts)
13
+
14
+ expect(platform.account.all).to eq(accounts)
15
+ end
16
+
17
+ it 'can retrieve activities in a date range' do
18
+ activities = [build(:account_activity)]
19
+
20
+ expect(session).to receive(:get)
21
+ .with('history/activity/20-05-2014/27-10-2014', IGMarkets::API_V1)
22
+ .and_return(activities: activities)
23
+
24
+ expect(platform.account.activities_in_date_range(Date.new(2014, 5, 20), Date.new(2014, 10, 27))).to eq(activities)
25
+ end
26
+
27
+ it 'can retrieve activities in recent period' do
28
+ activities = [build(:account_activity)]
29
+
30
+ expect(session).to receive(:get)
31
+ .with('history/activity/1000000', IGMarkets::API_V1)
32
+ .and_return(activities: activities)
33
+
34
+ expect(platform.account.recent_activities(1000)).to eq(activities)
35
+ end
36
+
37
+ it 'can retrieve transactions in a date range' do
38
+ transactions = [build(:account_transaction)]
39
+
40
+ expect(session).to receive(:get)
41
+ .with('history/transactions/ALL/20-05-2014/27-10-2014', IGMarkets::API_V1)
42
+ .and_return(transactions: transactions)
43
+
44
+ result = platform.account.transactions_in_date_range Date.new(2014, 5, 20), Date.new(2014, 10, 27), :all
45
+
46
+ expect(result).to eq(transactions)
47
+ end
48
+
49
+ it 'can retrieve transactions in recent period' do
50
+ transactions = [build(:account_transaction)]
51
+
52
+ expect(session).to receive(:get)
53
+ .with('history/transactions/DEPOSIT/1000000', IGMarkets::API_V1)
54
+ .and_return(transactions: transactions)
55
+
56
+ expect(platform.account.recent_transactions(1000, :deposit)).to eq(transactions)
57
+ end
58
+ end
@@ -0,0 +1,29 @@
1
+ describe IGMarkets::DealingPlatform::ClientSentimentMethods do
2
+ let(:session) { IGMarkets::Session.new }
3
+ let(:platform) do
4
+ IGMarkets::DealingPlatform.new.tap do |platform|
5
+ platform.instance_variable_set :@session, session
6
+ end
7
+ end
8
+
9
+ it 'can retrieve the client sentiment for a market' do
10
+ client_sentiment = build :client_sentiment
11
+
12
+ expect(session).to receive(:get).with('clientsentiment/1', IGMarkets::API_V1).and_return(client_sentiment)
13
+
14
+ expect(platform.client_sentiment['1']).to eq(client_sentiment)
15
+ end
16
+
17
+ it 'can retrieve the related client sentiments for a market' do
18
+ client_sentiment = build :client_sentiment, market_id: '1'
19
+ related_client_sentiments = [build(:client_sentiment), build(:client_sentiment)]
20
+
21
+ expect(session).to receive(:get).with('clientsentiment/1', IGMarkets::API_V1).and_return(client_sentiment)
22
+
23
+ expect(session).to receive(:get)
24
+ .with('clientsentiment/related/1', IGMarkets::API_V1)
25
+ .and_return(client_sentiments: related_client_sentiments)
26
+
27
+ expect(platform.client_sentiment['1'].related_sentiments).to eq(related_client_sentiments)
28
+ end
29
+ end