System for Electronic Disclosure by Insiders (SEDI) – Insider Reporting – Data Retrieval

SEDI “is Canada’s on-line, browser-based service for the filing and viewing of insider reports as required by various provincial securities rules and regulations.”

The Canadian requirement for insiders to report transactions and holdings in publicly traded companies is governed by REGULATION 55-104 RESPECTING INSIDER REPORTING REQUIREMENTS AND EXEMPTIONS.

Experimenting with the SEDI site and attempting to extract a complete listing of “reporting insiders” for select Canadian Financial Institutions

, I encountered the following difficulty when selecting  “A” through “Z” for a given issuer:

Screen shot 2014-01-02 at 9.00.45 PM

It seems that it is necessary to restrict queries (“narrow you search”) to each letter of the alphabet in order to draw reports one-by-one. This would be a slow and tedious process to get at the data in aggregate!

The solution (again!) is to apply a combination of Watir and Nokogiri through the following Ruby script. WATIR drives the browser and Nokogiri for parsing (lightening fast!!) the data on the pages for creating the  the following select “insider” lists:

Now the analytics can begin!

require 'rubygems'
require 'watir-webdriver'
require 'nokogiri'

ary_of_members = Array.new
rows = Array.new

### Defines Array Class for HTML Table output ###
class Array
def to_cells(tag)
 self.map { |c| "<#{tag}>#{c}</#{tag}>" }.join
 end
end
file = File.open('./SEDI_Insiders.html' 

antibiotici-acquista.com

, "w") browser = Watir::Browser.new :chrome ('A'..'Z').each do |letter| browser.goto 'https://www.sedi.ca/sedi/SVTReportsAccessController?menukey=15.03.00&locale=en_CA' browser.radio(:value => 'SVTIIBIselectIssuer').set browser.input(:name=>'Next').click browser.text_field(:name=>'ISSUER_SEARCH_VALUE').set "Bank of Montreal" browser.select_list(:name=>'ALPHA_RANGE_FROM').option(:text=>letter).select browser.select_list(:name=>'ALPHA_RANGE_TO').option(:text=>letter).select browser.input(:name=>'Search').click if browser.text.include? "Error: The system found no results matching the selected search criteria combination." else browser.table(:xpath, '/html/body/table[1]/tbody/tr[3]/td/table/tbody/tr/td/table[9]')[0][0].link.click doc = Nokogiri::HTML.parse(browser.html) i = 0 t = 0 doc.xpath("//table").each do |table| if doc.at_xpath("//table[#{i}]//tr//td[1]").to_s =~ /Insider Name/ insider_name = doc.at_xpath("//table[#{i}]//tr//td[2]").text.strip #Insider Name ceased_to_b_insider = doc.at_xpath("//table[#{i+2}]//tr//td[2]").text.strip #Ceased to be Insider? ceased_to_b_insider.gsub!(/Not Applicable/,'') until doc.at_xpath("//table[#{i+4+t}]//tr/td[2]").to_s !~ /\d{4}-\d{2}-\d{2}/ date = doc.at_xpath("//table[#{i+4+t}]//tr/td[2]").text.strip share_class = doc.at_xpath("//table[#{i+4+t}]//tr/td[3]").text.strip #Share Class reg_holder = doc.at_xpath("//table[#{i+4+t}]//tr/td[4]").text.strip #Reg. Holder nbr_shares = doc.at_xpath("//table[#{i+4+t}]//tr/td[5]").text.strip #Nbr or Shares #'cleans' HTML if reg_holder !~ /\w+/ reg_holder = () end rows << {"Insider Name" => insider_name, "Ceased Insider?" => ceased_to_b_insider, "Date" => date, "Share Class" => share_class, "Registered Holder" => reg_holder, "Nbr of Shares" => nbr_shares} #Insider Name & Ceased to be Insider - just once insider_name = () ceased_to_b_insider = () t+=2 end t = 0 end i+=1 end end end ### Rolls HTML Table output ### headers = "<tr>#{rows[0].keys.to_cells('th')}</tr>" cells = rows.map do |row| "<tr>#{row.values.to_cells('td')}</tr>" end.join("\n ") table = "<table border=\"1\"> #{headers} #{cells} </table>" file.puts table

 

 

 

 

 

 

Leave a Reply

Your email address will not be published. Required fields are marked *