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.
- checksums.yaml +7 -0
- data/.codeclimate.yml +15 -0
- data/.gitignore +9 -0
- data/.rspec +2 -0
- data/.rubocop.yml +2 -0
- data/.travis.yml +10 -0
- data/.yardopts +4 -0
- data/Gemfile +2 -0
- data/LICENSE.md +25 -0
- data/README.md +134 -0
- data/ig_markets.gemspec +28 -0
- data/lib/ig_markets.rb +42 -0
- data/lib/ig_markets/account.rb +23 -0
- data/lib/ig_markets/account_activity.rb +24 -0
- data/lib/ig_markets/account_transaction.rb +49 -0
- data/lib/ig_markets/api_versions.rb +10 -0
- data/lib/ig_markets/application.rb +22 -0
- data/lib/ig_markets/boolean.rb +5 -0
- data/lib/ig_markets/client_sentiment.rb +16 -0
- data/lib/ig_markets/deal_confirmation.rb +41 -0
- data/lib/ig_markets/dealing_platform.rb +105 -0
- data/lib/ig_markets/dealing_platform/account_methods.rb +92 -0
- data/lib/ig_markets/dealing_platform/client_sentiment_methods.rb +26 -0
- data/lib/ig_markets/dealing_platform/market_methods.rb +59 -0
- data/lib/ig_markets/dealing_platform/position_methods.rb +164 -0
- data/lib/ig_markets/dealing_platform/sprint_market_position_methods.rb +46 -0
- data/lib/ig_markets/dealing_platform/watchlist_methods.rb +42 -0
- data/lib/ig_markets/dealing_platform/working_order_methods.rb +115 -0
- data/lib/ig_markets/historical_price_result.rb +33 -0
- data/lib/ig_markets/instrument.rb +89 -0
- data/lib/ig_markets/market.rb +99 -0
- data/lib/ig_markets/market_hierarchy_result.rb +13 -0
- data/lib/ig_markets/market_overview.rb +24 -0
- data/lib/ig_markets/model.rb +185 -0
- data/lib/ig_markets/password_encryptor.rb +31 -0
- data/lib/ig_markets/payload_formatter.rb +38 -0
- data/lib/ig_markets/position.rb +191 -0
- data/lib/ig_markets/regex.rb +10 -0
- data/lib/ig_markets/request_failed_error.rb +21 -0
- data/lib/ig_markets/response_parser.rb +35 -0
- data/lib/ig_markets/session.rb +186 -0
- data/lib/ig_markets/sprint_market_position.rb +17 -0
- data/lib/ig_markets/version.rb +4 -0
- data/lib/ig_markets/watchlist.rb +37 -0
- data/lib/ig_markets/working_order.rb +68 -0
- data/spec/factories/ig_markets/account.rb +14 -0
- data/spec/factories/ig_markets/account_activity.rb +21 -0
- data/spec/factories/ig_markets/account_balance.rb +8 -0
- data/spec/factories/ig_markets/account_transaction.rb +15 -0
- data/spec/factories/ig_markets/application.rb +21 -0
- data/spec/factories/ig_markets/client_sentiment.rb +7 -0
- data/spec/factories/ig_markets/deal_confirmation.rb +20 -0
- data/spec/factories/ig_markets/historical_price_result.rb +7 -0
- data/spec/factories/ig_markets/historical_price_result_data_allowance.rb +7 -0
- data/spec/factories/ig_markets/historical_price_result_price.rb +7 -0
- data/spec/factories/ig_markets/historical_price_result_snapshot.rb +10 -0
- data/spec/factories/ig_markets/instrument.rb +32 -0
- data/spec/factories/ig_markets/instrument_currency.rb +9 -0
- data/spec/factories/ig_markets/instrument_expiry_details.rb +6 -0
- data/spec/factories/ig_markets/instrument_margin_deposit_band.rb +8 -0
- data/spec/factories/ig_markets/instrument_opening_hours.rb +6 -0
- data/spec/factories/ig_markets/instrument_rollover_details.rb +6 -0
- data/spec/factories/ig_markets/instrument_slippage_factor.rb +6 -0
- data/spec/factories/ig_markets/market.rb +7 -0
- data/spec/factories/ig_markets/market_dealing_rules.rb +11 -0
- data/spec/factories/ig_markets/market_dealing_rules_rule_details.rb +6 -0
- data/spec/factories/ig_markets/market_hierarchy_result.rb +6 -0
- data/spec/factories/ig_markets/market_hierarchy_result_hierarchy_node.rb +6 -0
- data/spec/factories/ig_markets/market_overview.rb +22 -0
- data/spec/factories/ig_markets/market_snapshot.rb +17 -0
- data/spec/factories/ig_markets/position.rb +19 -0
- data/spec/factories/ig_markets/sprint_market_position.rb +16 -0
- data/spec/factories/ig_markets/watchlist.rb +9 -0
- data/spec/factories/ig_markets/working_order.rb +21 -0
- data/spec/ig_markets/account_transaction_spec.rb +30 -0
- data/spec/ig_markets/dealing_platform/account_methods_spec.rb +58 -0
- data/spec/ig_markets/dealing_platform/client_sentiment_methods_spec.rb +29 -0
- data/spec/ig_markets/dealing_platform/market_methods_spec.rb +80 -0
- data/spec/ig_markets/dealing_platform/position_methods_spec.rb +137 -0
- data/spec/ig_markets/dealing_platform/sprint_market_position_methods_spec.rb +39 -0
- data/spec/ig_markets/dealing_platform/watchlist_methods_spec.rb +89 -0
- data/spec/ig_markets/dealing_platform/working_order_methods_spec.rb +120 -0
- data/spec/ig_markets/dealing_platform_spec.rb +40 -0
- data/spec/ig_markets/model_spec.rb +127 -0
- data/spec/ig_markets/password_encryptor_spec.rb +23 -0
- data/spec/ig_markets/payload_formatter_spec.rb +19 -0
- data/spec/ig_markets/position_spec.rb +37 -0
- data/spec/ig_markets/response_parser_spec.rb +13 -0
- data/spec/ig_markets/session_spec.rb +134 -0
- data/spec/spec_helper.rb +14 -0
- data/spec/support/factory_girl.rb +7 -0
- data/spec/support/random_test_order.rb +3 -0
- 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,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,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,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,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,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
|