ig_markets 0.3 → 0.4
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 +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
|