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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 790fdd28852c741b152d6ad02e17251b7cd388cf
4
- data.tar.gz: 6addb19b82511550ffdfa99b06feb806dd4ab6ab
3
+ metadata.gz: 724ac2b070ec1f942dc3d1be4417bb82486dd414
4
+ data.tar.gz: f219d63e7c52e427e5813a6369abcfcea838c9c3
5
5
  SHA512:
6
- metadata.gz: 8e79af030e563ea9f8f75a7b5c8f16ec06f03a73687a8bb1b29ae59f6e84fb04caff20e0389237df9c21c0c3431a3d1f5c9be128e1a54f794ca1be3265df8ab0
7
- data.tar.gz: 05a68232d1b4bdc221fca16c3ee07782646a4dbd481915e57c360dd5aa0c8152c6151d3e54cdff632a017dbbc2d137334e9a73a3a398b384db6754b75cb1747d
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 <command> --username=<username> --password=<password> --api-key=<api-key> [--demo]
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 `./".ig_markets"` or `~/".ig_markets"` with the following contents:
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=<username>
45
- --password=<password>
46
- --api-key=<api-key>
47
- # (include if this is a demo account) --demo
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 [--days=3]`
54
- - `ig_markets confirmation --deal-reference=<...>`
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 search --query=<...>`
58
- - `ig_markets sentiment --market=<...> [--related]`
59
- - `ig_markets sprints`
60
- - `ig_markets transactions [--days=3]`
61
- - `ig_markets watchlists`
62
-
63
- Note: at present there is no support in the command-line client for creating/updating/deleting positions, orders, etc...
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 24 * 60 * 60
77
- ig.account.recent_transactions 24 * 60 * 60
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, time_in_force: :good_till_cancelled, type: :limit
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
- # Read arguments from any '.ig_markets' config file
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 recent activities'
5
+ desc 'activities', 'Prints account activities'
6
6
 
7
- option :days, default: 3, type: :numeric, desc: 'The number of days to print recent activities for'
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.account.recent_activities(seconds).each do |activity|
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 seconds
20
- (options[:days].to_f * 60 * 60 * 24).to_i
21
- end
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
- def print_activity(activity)
24
- print <<-END
25
- #{activity.deal_id}: \
26
- #{activity.size} of #{activity.epic}, \
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
- option :deal_reference, aliases: '-r', required: true, desc: 'The deal reference to print the confirmation for.'
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
- def confirmation
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
@@ -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, aliases: '-u', required: true, desc: 'The username for the session'
7
- class_option :password, aliases: '-p', required: true, desc: 'The password for the session'
8
- class_option :api_key, aliases: '-k', required: true, desc: 'The API key for the session'
9
- class_option :demo, aliases: '-d', type: :boolean, desc: 'Use the demo platform (default is production)'
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
- # Intercepts calls to `exit` in the CLI commands, used by the test suite.
18
- def exit(code)
19
- Kernel.exit code
20
- end
11
+ desc 'orders [SUBCOMAND=list ...]', 'Command for working with orders'
12
+ subcommand 'orders', Orders
21
13
 
22
- def dealing_platform
23
- @dealing_platform ||= DealingPlatform.new
24
- end
14
+ desc 'positions [SUBCOMAND=list ...]', 'Command for working with positions'
15
+ subcommand 'positions', Positions
25
16
 
26
- def begin_session
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
- print "ERROR: #{error.error}\n"
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 Main
5
- desc 'orders', 'Prints working orders'
4
+ class Orders < Thor
5
+ desc 'list', 'Prints working orders'
6
6
 
7
- def orders
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 print_working_order(order)
18
- print <<-END
19
- #{order.deal_id}: \
20
- #{order.direction} #{format '%g', order.order_size} of #{order.epic} at #{order.order_level}\
21
- , limit distance: #{order.limit_distance || '-'}\
22
- , stop distance: #{order.stop_distance || '-'}\
23
- #{", good till #{order.good_till_date.utc.strftime '%F %T %z'}" if order.time_in_force == :good_till_date}
24
- END
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