ig_markets 0.3 → 0.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +15 -0
- data/README.md +28 -19
- data/bin/ig_markets +1 -29
- data/lib/ig_markets/cli/account_command.rb +3 -26
- data/lib/ig_markets/cli/activities_command.rb +13 -15
- data/lib/ig_markets/cli/config_file.rb +37 -0
- data/lib/ig_markets/cli/confirmation_command.rb +5 -21
- data/lib/ig_markets/cli/main.rb +79 -20
- data/lib/ig_markets/cli/orders_command.rb +81 -13
- data/lib/ig_markets/cli/output.rb +115 -0
- data/lib/ig_markets/cli/positions_command.rb +100 -9
- data/lib/ig_markets/cli/search_command.rb +5 -19
- data/lib/ig_markets/cli/sentiment_command.rb +8 -19
- data/lib/ig_markets/cli/sprints_command.rb +42 -14
- data/lib/ig_markets/cli/transactions_command.rb +17 -16
- data/lib/ig_markets/cli/watchlists_command.rb +55 -16
- data/lib/ig_markets/dealing_platform/account_methods.rb +17 -8
- data/lib/ig_markets/dealing_platform/position_methods.rb +17 -9
- data/lib/ig_markets/dealing_platform/working_order_methods.rb +7 -15
- data/lib/ig_markets/model/typecasters.rb +14 -5
- data/lib/ig_markets/model.rb +2 -1
- data/lib/ig_markets/password_encryptor.rb +10 -1
- data/lib/ig_markets/position.rb +2 -2
- data/lib/ig_markets/session.rb +14 -11
- data/lib/ig_markets/version.rb +1 -1
- data/lib/ig_markets/working_order.rb +6 -5
- data/lib/ig_markets.rb +6 -4
- metadata +11 -9
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 724ac2b070ec1f942dc3d1be4417bb82486dd414
|
4
|
+
data.tar.gz: f219d63e7c52e427e5813a6369abcfcea838c9c3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 037f9fe742a849aa0c74a537bafbe276078e7a34d41fd30f5302e5ff9f025de88ba13842438cef017fddb3ed562f9bb4a317735c72e79b6e2679a9054965b9b5
|
7
|
+
data.tar.gz: 89aa2c236ca20d253a5b5be311cbf9f0819c440fa77b2caa0d0c91380ae200287375b8ff60b52ebeca9b5eaa3e18c41374c9379aa61b26c52e5c2c27c7ccbf9e
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,20 @@
|
|
1
1
|
# IG Markets Changelog
|
2
2
|
|
3
|
+
### 0.4 - April 18, 2016
|
4
|
+
|
5
|
+
- Added `create`, `update` and `delete` subcommands to `ig_markets orders`
|
6
|
+
- Added `create`, `update` and `close` subcommands to `ig_markets positions`
|
7
|
+
- Added `create` subcommand to `ig_markets sprints`
|
8
|
+
- Added `create`, `add-markets`, `remove-markets` and `delete` subcommands to `ig_markets watchlists`
|
9
|
+
- `ig_markets confirmation`, `ig_markets search` and `ig_markets sentiment` now take their mandatory argument directly
|
10
|
+
- Added `--start-date` option to the `ig_markets activities` and `ig_markets transactions` commands
|
11
|
+
- Removed the `:time_in_force` option from `IGMarkets::WorkingOrderMethods#create` and `IGMarkets::WorkingOrder#update`,
|
12
|
+
just set `:good_till_date` if it is needed
|
13
|
+
- `IGMarkets::AccountMethods#recent_activities` and `IGMarkets::AccountMethods#recent_transactions` now take a number of
|
14
|
+
days rather than a number of seconds
|
15
|
+
- Fixed errors working with a working order's `#good_till_date` attribute
|
16
|
+
- Automatically reauthenticate if the client security token has expired
|
17
|
+
|
3
18
|
### 0.3 - April 14, 2016
|
4
19
|
|
5
20
|
- Added `--version` and `-v` options to the command-line client
|
data/README.md
CHANGED
@@ -33,34 +33,43 @@ Licensed under the MIT license. You must read and agree to its terms to use this
|
|
33
33
|
```sh
|
34
34
|
$ gem install ig_markets
|
35
35
|
|
36
|
-
Usage: ig_markets
|
36
|
+
Usage: ig_markets COMMAND --username=USERNAME --password=PASSWORD --api-key=API-KEY [--demo]
|
37
37
|
```
|
38
38
|
|
39
39
|
On startup `ig_markets` searches for files named `"./.ig_markets"` and then `"~/.ig_markets"`, and if they are present
|
40
40
|
interprets their contents as command-line arguments. This can be used to avoid having to specify authentication details
|
41
|
-
with every invocation. To do this create a file at
|
41
|
+
with every invocation. To do this create a file at `"./.ig_markets"` or `"~/.ig_markets"` with the following contents:
|
42
42
|
|
43
43
|
```
|
44
|
-
--username
|
45
|
-
--password
|
46
|
-
--api-key
|
47
|
-
#
|
44
|
+
--username=USERNAME
|
45
|
+
--password=PASSWORD
|
46
|
+
--api-key=API-KEY
|
47
|
+
--demo # Include only if this is a demo account
|
48
48
|
```
|
49
49
|
|
50
50
|
Run `ig_markets help` to list details on available commands. The full list of commands is:
|
51
51
|
|
52
52
|
- `ig_markets account`
|
53
|
-
- `ig_markets activities
|
54
|
-
- `ig_markets confirmation
|
55
|
-
- `ig_markets orders`
|
53
|
+
- `ig_markets activities --days=N [--start-date=YYYY-MM-DD]`
|
54
|
+
- `ig_markets confirmation DEAL-REFERENCE`
|
55
|
+
- `ig_markets orders [list]`
|
56
|
+
- `ig_markets orders create ...`
|
57
|
+
- `ig_markets orders update DEAL-ID ...`
|
58
|
+
- `ig_markets orders delete DEAL-ID`
|
56
59
|
- `ig_markets positions`
|
57
|
-
- `ig_markets
|
58
|
-
- `ig_markets
|
59
|
-
- `ig_markets
|
60
|
-
- `ig_markets
|
61
|
-
- `ig_markets
|
62
|
-
|
63
|
-
|
60
|
+
- `ig_markets positions create ...`
|
61
|
+
- `ig_markets positions update DEAL-ID ...`
|
62
|
+
- `ig_markets positions close DEAL-ID ...`
|
63
|
+
- `ig_markets search QUERY`
|
64
|
+
- `ig_markets sentiment MARKET [--related]`
|
65
|
+
- `ig_markets sprints [list]`
|
66
|
+
- `ig_markets sprints create ...`
|
67
|
+
- `ig_markets transactions --days=N [--start-date=YYYY-MM-DD]`
|
68
|
+
- `ig_markets watchlists [list]`
|
69
|
+
- `ig_markets watchlists create NAME [EPIC EPIC ...]`
|
70
|
+
- `ig_markets watchlists add-markets WATCHLIST-ID [EPIC EPIC ...]`
|
71
|
+
- `ig_markets watchlists remove-markets WATCHLIST-ID [EPIC EPIC ...]`
|
72
|
+
- `ig_markets watchlists delete WATCHLIST-ID`
|
64
73
|
|
65
74
|
## Usage — Library
|
66
75
|
|
@@ -73,8 +82,8 @@ ig.sign_out
|
|
73
82
|
|
74
83
|
# Account
|
75
84
|
ig.account.all
|
76
|
-
ig.account.recent_activities
|
77
|
-
ig.account.recent_transactions
|
85
|
+
ig.account.recent_activities 365
|
86
|
+
ig.account.recent_transactions 365
|
78
87
|
ig.account.activities_in_date_range Date.today - 14, Date.today - 7
|
79
88
|
ig.account.transactions_in_date_range Date.today - 14, Date.today - 7
|
80
89
|
|
@@ -97,7 +106,7 @@ ig.sprint_market_positions.create direction: :buy, epic: 'FM.D.EURUSD24.EURUSD24
|
|
97
106
|
# Working orders
|
98
107
|
ig.working_orders.all
|
99
108
|
ig.working_orders.create currency_code: 'USD', direction: :buy, epic: 'CS.D.EURUSD.CFD.IP', level: 0.99,
|
100
|
-
size: 1,
|
109
|
+
size: 1, type: :limit
|
101
110
|
ig.working_orders['deal_id']
|
102
111
|
ig.working_orders['deal_id'].update level: 1.25, limit_distance: 50, stop_distance: 0.02
|
103
112
|
ig.working_orders['deal_id'].delete
|
data/bin/ig_markets
CHANGED
@@ -4,32 +4,4 @@ $LOAD_PATH.unshift File.dirname(File.realpath(__FILE__)) + '/../lib'
|
|
4
4
|
|
5
5
|
require 'ig_markets'
|
6
6
|
|
7
|
-
|
8
|
-
def config_file_arguments
|
9
|
-
config_file = ['.ig_markets', "#{Dir.home}/.ig_markets"].detect { |file| File.exist? file }
|
10
|
-
|
11
|
-
return [] unless config_file
|
12
|
-
|
13
|
-
File.readlines(config_file)
|
14
|
-
.map { |line| line.gsub(/#.*/, '') }
|
15
|
-
.map(&:strip)
|
16
|
-
.join(' ')
|
17
|
-
.split(' ')
|
18
|
-
end
|
19
|
-
|
20
|
-
# Put arguments from the config file into a modified ARGV array
|
21
|
-
def modified_argv
|
22
|
-
insert_index = ARGV.index do |argument|
|
23
|
-
argument[0] == '-'
|
24
|
-
end || ARGV.size
|
25
|
-
|
26
|
-
ARGV.dup.insert insert_index, *config_file_arguments
|
27
|
-
end
|
28
|
-
|
29
|
-
# Implement --version and -v arguments
|
30
|
-
if ARGV.index('--version') || ARGV.index('-v')
|
31
|
-
puts IGMarkets::VERSION
|
32
|
-
exit
|
33
|
-
end
|
34
|
-
|
35
|
-
IGMarkets::CLI::Main.start modified_argv
|
7
|
+
IGMarkets::CLI::Main.bootstrap ARGV
|
@@ -5,36 +5,13 @@ module IGMarkets
|
|
5
5
|
desc 'account', 'Prints account overview and balances'
|
6
6
|
|
7
7
|
def account
|
8
|
-
begin_session do
|
8
|
+
self.class.begin_session(options) do |dealing_platform|
|
9
9
|
dealing_platform.account.all.each do |account|
|
10
|
-
print_account account
|
11
|
-
print_account_balance account
|
10
|
+
Output.print_account account
|
11
|
+
Output.print_account_balance account
|
12
12
|
end
|
13
13
|
end
|
14
14
|
end
|
15
|
-
|
16
|
-
private
|
17
|
-
|
18
|
-
def print_account(account)
|
19
|
-
print <<-END
|
20
|
-
Account '#{account.account_name}':
|
21
|
-
ID: #{account.account_id}
|
22
|
-
Type: #{account.account_type.to_s.upcase}
|
23
|
-
Currency: #{account.currency}
|
24
|
-
Status: #{account.status.to_s.upcase}
|
25
|
-
END
|
26
|
-
end
|
27
|
-
|
28
|
-
def print_account_balance(account)
|
29
|
-
{
|
30
|
-
available: 'Available: ',
|
31
|
-
balance: 'Balance: ',
|
32
|
-
deposit: 'Margin: ',
|
33
|
-
profit_loss: 'Profit/loss:'
|
34
|
-
}.each do |attribute, display_name|
|
35
|
-
print " #{display_name} #{Format.currency account.balance.send(attribute), account.currency}\n"
|
36
|
-
end
|
37
|
-
end
|
38
15
|
end
|
39
16
|
end
|
40
17
|
end
|
@@ -2,31 +2,29 @@ module IGMarkets
|
|
2
2
|
module CLI
|
3
3
|
# Implements the `ig_markets activities` command.
|
4
4
|
class Main
|
5
|
-
desc 'activities', 'Prints
|
5
|
+
desc 'activities', 'Prints account activities'
|
6
6
|
|
7
|
-
option :days,
|
7
|
+
option :days, type: :numeric, required: true, desc: 'The number of days to print account activities for'
|
8
|
+
option :start_date, desc: 'The start date to print account activities from, format: yyyy-mm-dd'
|
8
9
|
|
9
10
|
def activities
|
10
|
-
begin_session do
|
11
|
-
dealing_platform.
|
12
|
-
print_activity activity
|
11
|
+
self.class.begin_session(options) do |dealing_platform|
|
12
|
+
gather_activities(dealing_platform, options[:days], options[:start_date]).sort_by(&:date).each do |activity|
|
13
|
+
Output.print_activity activity
|
13
14
|
end
|
14
15
|
end
|
15
16
|
end
|
16
17
|
|
17
18
|
private
|
18
19
|
|
19
|
-
def
|
20
|
-
|
21
|
-
|
20
|
+
def gather_activities(dealing_platform, days, start_date = nil)
|
21
|
+
if start_date
|
22
|
+
start_date = Date.strptime options[:start_date], '%F'
|
22
23
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
level: #{activity.level}, \
|
28
|
-
result: #{activity.result}
|
29
|
-
END
|
24
|
+
dealing_platform.account.activities_in_date_range start_date, start_date + days.to_i
|
25
|
+
else
|
26
|
+
dealing_platform.account.recent_activities days
|
27
|
+
end
|
30
28
|
end
|
31
29
|
end
|
32
30
|
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module IGMarkets
|
2
|
+
module CLI
|
3
|
+
# Helper class for working with the config files supported by the command-line client.
|
4
|
+
class ConfigFile
|
5
|
+
# Initializes this config file with the contents of the specified config file.
|
6
|
+
def initialize(config_file)
|
7
|
+
@lines = File.readlines config_file
|
8
|
+
end
|
9
|
+
|
10
|
+
# Returns the arguments in this config file as an array.
|
11
|
+
#
|
12
|
+
# @return [Array<String>]
|
13
|
+
def arguments
|
14
|
+
@lines.map { |line| line.gsub(/#.*/, '') }
|
15
|
+
.map(&:strip)
|
16
|
+
.join(' ')
|
17
|
+
.split(' ')
|
18
|
+
end
|
19
|
+
|
20
|
+
# Returns the config file to use, or nil if there is no config file.
|
21
|
+
#
|
22
|
+
# @return [CLI::ConfigFile]
|
23
|
+
def self.find
|
24
|
+
config_file_locations = [
|
25
|
+
"#{Dir.pwd}/.ig_markets",
|
26
|
+
"#{Dir.home}/.ig_markets"
|
27
|
+
]
|
28
|
+
|
29
|
+
config_file = config_file_locations.detect do |filename|
|
30
|
+
File.exist? filename
|
31
|
+
end
|
32
|
+
|
33
|
+
config_file ? new(config_file) : nil
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -2,31 +2,15 @@ module IGMarkets
|
|
2
2
|
module CLI
|
3
3
|
# Implements the `ig_markets confirmation` command.
|
4
4
|
class Main < Thor
|
5
|
-
desc 'confirmation', 'Prints the deal confirmation for the specified deal reference
|
5
|
+
desc 'confirmation <DEAL-REFERENCE>', 'Prints the deal confirmation for the specified deal reference'
|
6
6
|
|
7
|
-
|
7
|
+
def confirmation(deal_reference)
|
8
|
+
self.class.begin_session(options) do |dealing_platform|
|
9
|
+
deal_confirmation = dealing_platform.deal_confirmation deal_reference
|
8
10
|
|
9
|
-
|
10
|
-
begin_session do
|
11
|
-
deal_confirmation = dealing_platform.deal_confirmation options[:deal_reference]
|
12
|
-
|
13
|
-
print_deal_confirmation deal_confirmation
|
11
|
+
Output.print_deal_confirmation deal_confirmation
|
14
12
|
end
|
15
13
|
end
|
16
|
-
|
17
|
-
private
|
18
|
-
|
19
|
-
def print_deal_confirmation(deal_confirmation)
|
20
|
-
print "#{deal_confirmation.deal_id}: #{deal_confirmation.deal_status}, "
|
21
|
-
|
22
|
-
if deal_confirmation.deal_status == :accepted
|
23
|
-
print "affected deals: #{deal_confirmation.affected_deals.map(&:deal_id).join(',')}, "
|
24
|
-
else
|
25
|
-
print "reason: #{deal_confirmation.reason}, "
|
26
|
-
end
|
27
|
-
|
28
|
-
print "epic: #{deal_confirmation.epic}\n"
|
29
|
-
end
|
30
14
|
end
|
31
15
|
end
|
32
16
|
end
|
data/lib/ig_markets/cli/main.rb
CHANGED
@@ -3,36 +3,95 @@ module IGMarkets
|
|
3
3
|
module CLI
|
4
4
|
# Implements the `ig_markets` command-line client.
|
5
5
|
class Main < Thor
|
6
|
-
class_option :username,
|
7
|
-
class_option :password,
|
8
|
-
class_option :api_key,
|
9
|
-
class_option :demo,
|
10
|
-
|
11
|
-
no_commands do
|
12
|
-
# Intercepts calls to `print` in the CLI commands, used by the test suite.
|
13
|
-
def print(string)
|
14
|
-
Kernel.print string
|
15
|
-
end
|
6
|
+
class_option :username, required: true, desc: 'The username for the session'
|
7
|
+
class_option :password, required: true, desc: 'The password for the session'
|
8
|
+
class_option :api_key, required: true, desc: 'The API key for the session'
|
9
|
+
class_option :demo, type: :boolean, desc: 'Use the demo platform (default is production)'
|
16
10
|
|
17
|
-
|
18
|
-
|
19
|
-
Kernel.exit code
|
20
|
-
end
|
11
|
+
desc 'orders [SUBCOMAND=list ...]', 'Command for working with orders'
|
12
|
+
subcommand 'orders', Orders
|
21
13
|
|
22
|
-
|
23
|
-
|
24
|
-
end
|
14
|
+
desc 'positions [SUBCOMAND=list ...]', 'Command for working with positions'
|
15
|
+
subcommand 'positions', Positions
|
25
16
|
|
26
|
-
|
17
|
+
desc 'sprints [SUBCOMAND=list ...]', 'Command for working with sprint market positions'
|
18
|
+
subcommand 'sprints', Sprints
|
19
|
+
|
20
|
+
desc 'watchlists [SUBCOMAND=list ...]', 'Command for working with watchlists'
|
21
|
+
subcommand 'watchlists', Watchlists
|
22
|
+
|
23
|
+
class << self
|
24
|
+
# Signs in to IG Markets and yields back an {DealingPlatform} instance, with common error handling if exceptions
|
25
|
+
# occur. This method is used by all of the CLI commands to authenticate.
|
26
|
+
#
|
27
|
+
# @param [Thor::CoreExt::HashWithIndifferentAccess] options The Thor options hash.
|
28
|
+
#
|
29
|
+
# @return [void]
|
30
|
+
def begin_session(options)
|
27
31
|
platform = options[:demo] ? :demo : :production
|
28
32
|
|
29
33
|
dealing_platform.sign_in options[:username], options[:password], options[:api_key], platform
|
30
34
|
|
31
|
-
yield
|
35
|
+
yield dealing_platform
|
32
36
|
rescue IGMarkets::RequestFailedError => error
|
33
|
-
|
37
|
+
warn "Request failed: #{error.error}"
|
38
|
+
exit 1
|
39
|
+
rescue StandardError => error
|
40
|
+
warn "Error: #{error}"
|
34
41
|
exit 1
|
35
42
|
end
|
43
|
+
|
44
|
+
# The dealing platform instance used by {begin_session}.
|
45
|
+
def dealing_platform
|
46
|
+
@dealing_platform ||= DealingPlatform.new
|
47
|
+
end
|
48
|
+
|
49
|
+
# Parses and validates a Date or Time option received on the command line. Raises `ArgumentError` if the
|
50
|
+
# attribute has been specified in an invalid format.
|
51
|
+
#
|
52
|
+
# @param [Hash] attributes The attributes hash.
|
53
|
+
# @param [Symbol] attribute The name of the date or time attribute to parse and validate.
|
54
|
+
# @param [Date, Time] klass The class to validate with.
|
55
|
+
# @param [String] format The `strptime` format string to parse the attribute with.
|
56
|
+
# @param [String] display_format The human-readable version of `format` to put into an exception if there is
|
57
|
+
# a problem parsing the attribute.
|
58
|
+
#
|
59
|
+
# @return [void]
|
60
|
+
def parse_date_time(attributes, attribute, klass, format, display_format)
|
61
|
+
return unless attributes.key? attribute
|
62
|
+
|
63
|
+
if !['', attribute.to_s].include? attributes[attribute].to_s
|
64
|
+
begin
|
65
|
+
attributes[attribute] = klass.strptime attributes[attribute], format
|
66
|
+
rescue ArgumentError
|
67
|
+
raise "invalid #{attribute}, use format \"#{display_format}\""
|
68
|
+
end
|
69
|
+
else
|
70
|
+
attributes[attribute] = nil
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
# This is the initial entry point for the execution of the command-line client. It is responsible for reading
|
75
|
+
# any config files, implementing the --version/-v options, and then invoking the main application.
|
76
|
+
#
|
77
|
+
# @param [Array<String>] argv The array of command-line arguments.
|
78
|
+
#
|
79
|
+
# @return [void]
|
80
|
+
def bootstrap(argv)
|
81
|
+
if argv.index('--version') || argv.index('-v')
|
82
|
+
puts VERSION
|
83
|
+
exit
|
84
|
+
end
|
85
|
+
|
86
|
+
# Use arguments from a config file if one exists
|
87
|
+
config_file = ConfigFile.find
|
88
|
+
if config_file
|
89
|
+
insert_index = argv.index { |argument| argument[0] == '-' } || -1
|
90
|
+
argv.insert insert_index, *config_file.arguments
|
91
|
+
end
|
92
|
+
|
93
|
+
start argv
|
94
|
+
end
|
36
95
|
end
|
37
96
|
end
|
38
97
|
end
|
@@ -1,27 +1,95 @@
|
|
1
1
|
module IGMarkets
|
2
2
|
module CLI
|
3
3
|
# Implements the `ig_markets orders` command.
|
4
|
-
class
|
5
|
-
desc '
|
4
|
+
class Orders < Thor
|
5
|
+
desc 'list', 'Prints working orders'
|
6
6
|
|
7
|
-
def
|
8
|
-
begin_session do
|
7
|
+
def list
|
8
|
+
Main.begin_session(options) do |dealing_platform|
|
9
9
|
dealing_platform.working_orders.all.each do |order|
|
10
|
-
print_working_order order
|
10
|
+
Output.print_working_order order
|
11
11
|
end
|
12
12
|
end
|
13
13
|
end
|
14
14
|
|
15
|
+
default_task :list
|
16
|
+
|
17
|
+
desc 'create', 'Creates a new working order'
|
18
|
+
|
19
|
+
option :currency_code, required: true, desc: 'The 3 character currency code, must be one of the instrument\'s ' \
|
20
|
+
'currencies'
|
21
|
+
option :direction, required: true, desc: 'The trade direction, must be \'buy\' or \'sell\''
|
22
|
+
option :epic, required: true, desc: 'The EPIC of the market to trade'
|
23
|
+
option :expiry, desc: 'The expiry date of the instrument (if applicable), format: yyyy-mm-dd'
|
24
|
+
option :force_open, type: :boolean, default: false, desc: 'Whether a force open is required, default: false'
|
25
|
+
option :good_till_date, desc: 'The date that the order will live till, if not specified then the order will ' \
|
26
|
+
'remain until it is deleted, format: yyyy-mm-ddThh:mm(+|-)zz:zz'
|
27
|
+
option :guaranteed_stop, type: :boolean, default: false, desc: 'Whether a guaranteed stop is required, ' \
|
28
|
+
'default: false'
|
29
|
+
option :level, type: :numeric, required: true, desc: 'The level at which the order will be triggered'
|
30
|
+
option :limit_distance, type: :numeric, desc: 'The distance away in pips to place the limit'
|
31
|
+
option :size, type: :numeric, required: true, desc: 'The size of the order'
|
32
|
+
option :stop_distance, type: :numeric, desc: 'The distance away in pips to place the stop'
|
33
|
+
option :type, required: true, desc: 'The order type, either \'limit\' or \'stop\''
|
34
|
+
|
35
|
+
def create
|
36
|
+
Main.begin_session(options) do |dealing_platform|
|
37
|
+
deal_reference = dealing_platform.working_orders.create working_order_attributes
|
38
|
+
|
39
|
+
puts "Deal reference: #{deal_reference}"
|
40
|
+
|
41
|
+
Output.print_deal_confirmation dealing_platform.deal_confirmation(deal_reference)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
desc 'update <DEAL-ID>', 'Updates an existing working order'
|
46
|
+
|
47
|
+
option :good_till_date, desc: 'The date that the order will live till, if not specified then the order will ' \
|
48
|
+
'remain until it is deleted, format: yyyy-mm-ddThh:mm(+|-)zz:zz'
|
49
|
+
option :level, type: :numeric, desc: 'The level at which the order will be triggered'
|
50
|
+
option :limit_distance, type: :numeric, desc: 'The distance away in pips to place the limit'
|
51
|
+
option :stop_distance, type: :numeric, desc: 'The distance away in pips to place the stop'
|
52
|
+
option :type, desc: 'The order type, either \'limit\' or \'stop\''
|
53
|
+
|
54
|
+
def update(deal_id)
|
55
|
+
Main.begin_session(options) do |dealing_platform|
|
56
|
+
deal_reference = dealing_platform.working_orders[deal_id].update working_order_attributes
|
57
|
+
|
58
|
+
puts "Deal reference: #{deal_reference}"
|
59
|
+
|
60
|
+
Output.print_deal_confirmation dealing_platform.deal_confirmation(deal_reference)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
desc 'delete <DEAL-ID>', 'Deletes the working order with the specified deal ID'
|
65
|
+
|
66
|
+
def delete(deal_id)
|
67
|
+
Main.begin_session(options) do |dealing_platform|
|
68
|
+
working_order = dealing_platform.working_orders[deal_id]
|
69
|
+
|
70
|
+
raise 'No working order with the specified deal ID' unless working_order
|
71
|
+
|
72
|
+
deal_reference = working_order.delete
|
73
|
+
puts "Deal reference: #{deal_reference}"
|
74
|
+
|
75
|
+
Output.print_deal_confirmation dealing_platform.deal_confirmation(deal_reference)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
15
79
|
private
|
16
80
|
|
17
|
-
def
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
81
|
+
def working_order_attributes
|
82
|
+
attributes = options.each_with_object({}) do |(key, value), new_hash|
|
83
|
+
if [:currency_code, :direction, :epic, :expiry, :force_open, :good_till_date, :guaranteed_stop, :level,
|
84
|
+
:limit_distance, :size, :stop_distance, :type].include? key.to_sym
|
85
|
+
new_hash[key.to_sym] = value
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
Main.parse_date_time attributes, :expiry, Date, '%F', 'yyyy-mm-dd'
|
90
|
+
Main.parse_date_time attributes, :good_till_date, Time, '%FT%R%z', 'yyyy-mm-ddThh:mm(+|-)zz:zz'
|
91
|
+
|
92
|
+
attributes
|
25
93
|
end
|
26
94
|
end
|
27
95
|
end
|
@@ -0,0 +1,115 @@
|
|
1
|
+
module IGMarkets
|
2
|
+
module CLI
|
3
|
+
# Contains methods used by the CLI to print models to stdout.
|
4
|
+
module Output
|
5
|
+
module_function
|
6
|
+
|
7
|
+
def print_account(account)
|
8
|
+
puts <<-END
|
9
|
+
Account '#{account.account_name}':
|
10
|
+
ID: #{account.account_id}
|
11
|
+
Type: #{account.account_type.to_s.upcase}
|
12
|
+
Currency: #{account.currency}
|
13
|
+
Status: #{account.status.to_s.upcase}
|
14
|
+
END
|
15
|
+
end
|
16
|
+
|
17
|
+
def print_account_balance(account)
|
18
|
+
{
|
19
|
+
available: 'Available: ',
|
20
|
+
balance: 'Balance: ',
|
21
|
+
deposit: 'Margin: ',
|
22
|
+
profit_loss: 'Profit/loss:'
|
23
|
+
}.each do |attribute, title|
|
24
|
+
puts " #{title} #{Format.currency account.balance.send(attribute), account.currency}"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def print_activity(activity)
|
29
|
+
puts <<-END
|
30
|
+
#{activity.date.strftime '%F'} #{activity.deal_id}: \
|
31
|
+
#{activity.size} of #{activity.epic}, \
|
32
|
+
level: #{activity.level}, \
|
33
|
+
result: #{activity.result}
|
34
|
+
END
|
35
|
+
end
|
36
|
+
|
37
|
+
def print_client_sentiment(client_sentiment)
|
38
|
+
puts <<-END
|
39
|
+
#{client_sentiment.market_id}: \
|
40
|
+
longs: #{client_sentiment.long_position_percentage}%, \
|
41
|
+
shorts: #{client_sentiment.short_position_percentage}%
|
42
|
+
END
|
43
|
+
end
|
44
|
+
|
45
|
+
def print_deal_confirmation(deal_confirmation)
|
46
|
+
print "Deal confirmation: #{deal_confirmation.deal_id}, #{deal_confirmation.deal_status}, "
|
47
|
+
|
48
|
+
if deal_confirmation.deal_status == :accepted
|
49
|
+
print "affected deals: #{deal_confirmation.affected_deals.map(&:deal_id).join(',')}, "
|
50
|
+
else
|
51
|
+
print "reason: #{deal_confirmation.reason}, "
|
52
|
+
end
|
53
|
+
|
54
|
+
puts "epic: #{deal_confirmation.epic}"
|
55
|
+
end
|
56
|
+
|
57
|
+
def print_market_overview(market)
|
58
|
+
puts <<-END
|
59
|
+
#{market.epic}: \
|
60
|
+
#{market.instrument_name}, \
|
61
|
+
type: #{market.instrument_type}, \
|
62
|
+
bid: #{market.bid} \
|
63
|
+
offer: #{market.offer}
|
64
|
+
END
|
65
|
+
end
|
66
|
+
|
67
|
+
def print_position(position)
|
68
|
+
puts <<-END
|
69
|
+
#{position.deal_id}: \
|
70
|
+
#{position.formatted_size} of #{position.market.epic} at #{position.level}, \
|
71
|
+
profit/loss: #{Format.currency position.profit_loss, position.currency}
|
72
|
+
END
|
73
|
+
end
|
74
|
+
|
75
|
+
def print_sprint_market_position(sprint)
|
76
|
+
puts <<-END
|
77
|
+
#{sprint.deal_id}: \
|
78
|
+
#{Format.currency sprint.size, sprint.currency} on #{sprint.epic} \
|
79
|
+
to be #{{ buy: 'above', sell: 'below' }.fetch(sprint.direction)} #{sprint.strike_level} \
|
80
|
+
in #{Format.seconds sprint.seconds_till_expiry}, \
|
81
|
+
payout: #{Format.currency sprint.payout_amount, sprint.currency}
|
82
|
+
END
|
83
|
+
end
|
84
|
+
|
85
|
+
def print_transaction(transaction)
|
86
|
+
puts <<-END
|
87
|
+
#{transaction.date.strftime '%F'} #{transaction.reference}: \
|
88
|
+
#{transaction.formatted_transaction_type}, \
|
89
|
+
#{"#{transaction.size} of " if transaction.size}\
|
90
|
+
#{transaction.instrument_name}, \
|
91
|
+
profit/loss: #{Format.currency transaction.profit_and_loss_amount, transaction.currency}
|
92
|
+
END
|
93
|
+
end
|
94
|
+
|
95
|
+
def print_watchlist(watchlist)
|
96
|
+
puts <<-END
|
97
|
+
#{watchlist.id}: #{watchlist.name}, \
|
98
|
+
editable: #{watchlist.editable}, \
|
99
|
+
deleteable: #{watchlist.deleteable}, \
|
100
|
+
default: #{watchlist.default_system_watchlist}
|
101
|
+
END
|
102
|
+
end
|
103
|
+
|
104
|
+
def print_working_order(order)
|
105
|
+
puts <<-END
|
106
|
+
#{order.deal_id}: \
|
107
|
+
#{order.direction} #{format '%g', order.order_size} of #{order.epic} at #{order.order_level}\
|
108
|
+
, limit distance: #{order.limit_distance || '-'}\
|
109
|
+
, stop distance: #{order.stop_distance || '-'}\
|
110
|
+
#{", good till #{order.good_till_date.utc.strftime '%F %R %z'}" if order.time_in_force == :good_till_date}
|
111
|
+
END
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|