class Qc::CommandRunner
Constants
- BACKTEST_DELAY_IN_SECONDS
- COMPILE_POLLING_DELAY_IN_SECONDS
- DEFAULT_FILE_EXTENSIONS
- DEFAULT_IGNORED_FILES
- SUPPORTED_COMMANDS
Attributes
options[R]
project_settings[RW]
quant_connect_proxy[R]
Public Class Methods
new(quant_connect_proxy, options = OpenStruct.new)
click to toggle source
# File lib/qc/command_runner.rb, line 15 def initialize(quant_connect_proxy, options = OpenStruct.new) @quant_connect_proxy = quant_connect_proxy @project_settings = read_project_settings @options = options end
Public Instance Methods
run(command)
click to toggle source
# File lib/qc/command_runner.rb, line 21 def run(command) if command == :login do_run(command) else require_login do do_run(command) end end end
run_default()
click to toggle source
# File lib/qc/command_runner.rb, line 31 def run_default run(:default) end
Private Instance Methods
ask_for_extensions()
click to toggle source
# File lib/qc/command_runner.rb, line 274 def ask_for_extensions file_extensions = ask_for_value "Introduce the file extensions you want to send to QuantConnect as a comma separated list. ENTER to default '#{DEFAULT_FILE_EXTENSIONS}'" file_extensions = DEFAULT_FILE_EXTENSIONS if file_extensions.empty? file_extensions end
ask_for_project()
click to toggle source
# File lib/qc/command_runner.rb, line 257 def ask_for_project puts "Fetching projets from Quantconnect..." projects = quant_connect_proxy.list_projects puts "Select the project you want to associate with this directory" projects.each.with_index do |project, index| puts "[#{index + 1}] - #{project.name}" end index = ask_for_value "Project number?" index = index.to_i if index >= 1 && index < projects.length + 1 projects[index - 1] else puts "Invalid value (please type a number between #{1} and #{projects.length})" ask_for_project end end
ask_for_value(question)
click to toggle source
# File lib/qc/command_runner.rb, line 252 def ask_for_value(question) puts question STDIN.gets.chomp end
changed_files()
click to toggle source
# File lib/qc/command_runner.rb, line 293 def changed_files all_files = fetch_all_files return all_files unless project_settings.last_sync_at changed_files = all_files.find_all do |file| ::File.mtime(file) > project_settings.last_sync_at end changed_files end
create_project_settings()
click to toggle source
# File lib/qc/command_runner.rb, line 53 def create_project_settings Qc::ProjectSettings.new.tap do |project_settings| project_settings.execution_count = 1 project_settings.ignored_files = DEFAULT_IGNORED_FILES end end
credentials()
click to toggle source
# File lib/qc/command_runner.rb, line 37 def credentials quant_connect_proxy&.credentials end
credentials=(new_credentials)
click to toggle source
# File lib/qc/command_runner.rb, line 41 def credentials=(new_credentials) quant_connect_proxy.credentials = new_credentials end
current_backtest_label()
click to toggle source
# File lib/qc/command_runner.rb, line 226 def current_backtest_label @current_backtest_label ||= "#{project_name}-#{project_settings.execution_count}" end
do_run(command)
click to toggle source
# File lib/qc/command_runner.rb, line 73 def do_run(command) case command when :default do_run_default when *SUPPORTED_COMMANDS send "run_#{command}" else raise "Unknonw command '#{command}'. Supported commands: #{SUPPORTED_COMMANDS.collect(&:to_s).join(', ')}" end end
do_run_backtest()
click to toggle source
# File lib/qc/command_runner.rb, line 191 def do_run_backtest backtest = quant_connect_proxy.create_backtest project_settings.project_id, project_settings.last_compile_id, current_backtest_label puts "Backtest '#{current_backtest_label}' for compile #{project_settings.last_compile_id} sent to the queue with id #{backtest.id}" open_results_in_quant_connect if options.open_results puts "Waiting for backtest to start..." last_completed_percentage = nil begin if last_completed_percentage != backtest.progress puts "Completed: #{backtest.progress}%..." end last_completed_percentage = backtest.progress backtest = quant_connect_proxy.read_backtest project_settings.project_id, backtest.id sleep BACKTEST_DELAY_IN_SECONDS unless backtest.completed? end while !backtest.completed? show_backtest_results backtest update_project_settings_after_running_backtest(backtest) import_backtest_results_into_tradervue(backtest) if options.import_into_tradervue backtest.success? end
do_run_default()
click to toggle source
# File lib/qc/command_runner.rb, line 174 def do_run_default return false unless validate_initialized_project! failed = %i(push compile backtest).find do |command| !run(command) end !failed end
fetch_all_files()
click to toggle source
# File lib/qc/command_runner.rb, line 305 def fetch_all_files Dir["**/*.{#{project_settings.file_extensions}}"].reject {|file| ignore_file?(file)} end
ignore_file?(file)
click to toggle source
# File lib/qc/command_runner.rb, line 309 def ignore_file?(file) ignored_files.find do |ignored_file| file =~ /#{ignored_file}/ end end
ignored_files()
click to toggle source
# File lib/qc/command_runner.rb, line 315 def ignored_files project_settings.ignored_files || DEFAULT_IGNORED_FILES end
import_backtest_results_into_tradervue(backtest)
click to toggle source
# File lib/qc/command_runner.rb, line 343 def import_backtest_results_into_tradervue(backtest) show_title 'Importing results into Tradervue' raise "You need to set TRADERVUE_LOGIN and TRADERVUE_PASSWORD" unless tradervue_login && tradervue_password orders = backtest.result['Orders'].values orders_as_tradervue_executions = orders.collect do |order| { "datetime" => in_est_timezone(order), "symbol" => order['Symbol']['Value'], "quantity" => order['Quantity'], "price" => order['Price'], "option" => '', "commission" => '', "transfee" => 0, "ecnfee" => 0 } end result = tradervue_importer.import_data(orders_as_tradervue_executions, account_tag: current_backtest_label) puts result puts "#{orders_as_tradervue_executions.length} orders imported successfully" open_results_in_tradervue(backtest) end
in_est_timezone(order)
click to toggle source
# File lib/qc/command_runner.rb, line 367 def in_est_timezone(order) time = DateTime.parse order['Time'] time.to_time.utc.localtime("-05:00") end
increase_execution_count()
click to toggle source
# File lib/qc/command_runner.rb, line 221 def increase_execution_count project_settings.execution_count ||= 0 project_settings.execution_count += 1 end
initialized_project?()
click to toggle source
# File lib/qc/command_runner.rb, line 339 def initialized_project? project_settings.project_id end
logged_in?()
click to toggle source
# File lib/qc/command_runner.rb, line 60 def logged_in? !!credentials end
macos?()
click to toggle source
# File lib/qc/command_runner.rb, line 334 def macos? host_os = RbConfig::CONFIG['host_os'] host_os =~ /darwin|mac os/ end
open_results_in_quant_connect()
click to toggle source
# File lib/qc/command_runner.rb, line 164 def open_results_in_quant_connect return false unless validate_initialized_project! return false unless validate_on_mac! open_workflow_file = ::File.expand_path ::File.join(__dir__, '..', '..', 'automator', 'open-qc-results.workflow') open_command = "automator -i #{project_settings.project_id} #{open_workflow_file}" puts "Opening backtest results for project #{project_settings.project_id}" system open_command end
open_results_in_tradervue(backtest)
click to toggle source
# File lib/qc/command_runner.rb, line 372 def open_results_in_tradervue(backtest) return false unless validate_on_mac! url = "https://www.tradervue.com/trades?tag=#{current_backtest_label}" puts "Opening results in tradervue: #{url}" system "open #{url}" end
project_name()
click to toggle source
# File lib/qc/command_runner.rb, line 230 def project_name @project_name ||= ::File.basename(::File.expand_path(::File.join(Util.project_dir, '..'))) end
project_settings_file()
click to toggle source
# File lib/qc/command_runner.rb, line 248 def project_settings_file ::File.join(Qc::Util.project_dir, 'settings.yml') end
read_project_settings()
click to toggle source
# File lib/qc/command_runner.rb, line 45 def read_project_settings if ::File.exist?(project_settings_file) YAML.load(::File.open(project_settings_file)) else create_project_settings end end
require_login() { || ... }
click to toggle source
# File lib/qc/command_runner.rb, line 64 def require_login if credentials yield else puts "Please sign in by executing 'qc login' first" false end end
run_backtest()
click to toggle source
# File lib/qc/command_runner.rb, line 147 def run_backtest show_title 'Run backtest' return false unless validate_initialized_project! unless project_settings.last_compile_id puts "Project not compiled. Please run 'qc compile'" return false end do_run_backtest end
run_compile()
click to toggle source
# File lib/qc/command_runner.rb, line 125 def run_compile show_title 'Compile' return false unless validate_initialized_project! compile = quant_connect_proxy.create_compile project_settings.project_id puts "Compile request sent to the queue with id #{compile.id}" begin puts "Waiting for compilation result..." compile = quant_connect_proxy.read_compile project_settings.project_id, compile.id sleep COMPILE_POLLING_DELAY_IN_SECONDS if compile.in_queue? end while compile.in_queue? puts "Compile success" if compile.success? puts "Compile failed" if compile.error? project_settings.last_compile_id = compile.id save_project_settings compile.success? end
run_init()
click to toggle source
# File lib/qc/command_runner.rb, line 100 def run_init FileUtils.mkdir_p(Qc::Util.project_dir) project = ask_for_project self.project_settings.project_id = project.id self.project_settings.file_extensions = ask_for_extensions save_project_settings true end
run_login()
click to toggle source
# File lib/qc/command_runner.rb, line 84 def run_login puts "Please introduce your QuantConnect API credentials. You can find them in your preferences in https://www.quantconnect.com/account." user_id = ask_for_value 'User id:' access_token = ask_for_value 'Access token:' self.credentials = Qc::Credentials.new(user_id, access_token) if valid_login? credentials.save_to_home true else puts "Invalid credentials" false end end
run_logout()
click to toggle source
# File lib/qc/command_runner.rb, line 109 def run_logout credentials.destroy puts "Logged out successfully" true end
run_open()
click to toggle source
# File lib/qc/command_runner.rb, line 159 def run_open show_title 'Open backtest results' return open_results_in_quant_connect end
run_push()
click to toggle source
# File lib/qc/command_runner.rb, line 115 def run_push show_title 'Push files' return false unless validate_initialized_project! sync_changed_files save_current_timestamp true end
save_current_timestamp()
click to toggle source
# File lib/qc/command_runner.rb, line 319 def save_current_timestamp project_settings.last_sync_at = Time.now save_project_settings end
save_project_settings()
click to toggle source
# File lib/qc/command_runner.rb, line 244 def save_project_settings ::File.open(project_settings_file, 'w') {|file| file.write self.project_settings.to_yaml} end
show_backtest_results(backtest)
click to toggle source
# File lib/qc/command_runner.rb, line 234 def show_backtest_results(backtest) puts "Backtest finished" if backtest.success? puts "Backtest failed" if backtest.error? puts backtest.to_s end
show_title(title)
click to toggle source
# File lib/qc/command_runner.rb, line 184 def show_title(title) separator = '-' * title.length puts "\n#{separator}" puts title puts "#{separator}\n" end
sync_changed_files()
click to toggle source
# File lib/qc/command_runner.rb, line 281 def sync_changed_files if changed_files.empty? puts "No changes detected" end changed_files.each do |file| puts "Uploading #{file}..." content = ::File.read(file).strip quant_connect_proxy.put_file project_settings.project_id, ::File.basename(file), content end end
tradervue_importer()
click to toggle source
# File lib/qc/command_runner.rb, line 380 def tradervue_importer @tradervue_importer ||= TradervueImporter.new(tradervue_login, tradervue_password) end
tradervue_login()
click to toggle source
# File lib/qc/command_runner.rb, line 388 def tradervue_login ENV['TRADERVUE_LOGIN'] end
tradervue_password()
click to toggle source
# File lib/qc/command_runner.rb, line 384 def tradervue_password ENV['TRADERVUE_PASSWORD'] end
update_project_settings_after_running_backtest(backtest)
click to toggle source
# File lib/qc/command_runner.rb, line 215 def update_project_settings_after_running_backtest(backtest) project_settings.last_backtest_id = backtest.id increase_execution_count save_project_settings end
valid_login?()
click to toggle source
# File lib/qc/command_runner.rb, line 240 def valid_login? quant_connect_proxy.valid_login? end
validate_initialized_project!()
click to toggle source
# File lib/qc/command_runner.rb, line 324 def validate_initialized_project! puts "Please run 'qc init' to initialize your project" unless initialized_project? initialized_project? end
validate_on_mac!()
click to toggle source
# File lib/qc/command_runner.rb, line 329 def validate_on_mac! puts "This command is only supported in macos" unless macos? macos? end