using System; using System.Text; using System.Collections.Generic; using System.IO; using HtmlAgilityPack; using MarketData.Utils; using MarketData.MarketDataModel; using MarketDataLib.Utility; using System.Collections.Concurrent; namespace MarketData.Helper { public class InsiderTransactionsParser { private static ConcurrentDictionary transactionCodes=new ConcurrentDictionary(); private static InsiderTransactionsParser instance=null; private InsiderTransactionsParser() { BuildTransactionCodes(); } public static InsiderTransactionsParser GetInstance() { lock(typeof(InsiderTransactionsParser)) { if(null==instance)instance=new InsiderTransactionsParser(); return instance; } } /// /// Parse the SECFilings. Each SECFiling may contain a list of InsiderTransaction /// /// The SECFilings. public InsiderTransactions Parse(SECFilings secFilings) { try { InsiderTransactions insiderTransactions=new InsiderTransactions(); if(null==secFilings || 0==secFilings.Count)return insiderTransactions; foreach(SECFiling secFiling in secFilings) { InsiderTransactions secFilinginsiderTransactions = Parse(secFiling.FormText, secFiling.Symbol, secFiling.SECAccessionNumber, secFiling.Form, secFiling.FilingDate); if(null!=secFilinginsiderTransactions && secFilinginsiderTransactions.Count>0) insiderTransactions.AddRange(secFilinginsiderTransactions); } return insiderTransactions; } catch(Exception exception) { MDTrace.WriteLine(LogLevel.DEBUG,String.Format("Parse SECFiling got exception {0}",exception.ToString())); return new InsiderTransactions(); } } public InsiderTransactions Parse(String strHtml,String symbol, String secAccessionNumber, String form, DateTime filingDate) { try { InsiderTransactions insiderTransactions = new InsiderTransactions(); if(null==strHtml)return null; List> dictionaryList=new List>(); String insiderName=null; byte[] streamBytes = Encoding.ASCII.GetBytes(strHtml); MemoryStream memoryStream = new MemoryStream(streamBytes); HtmlDocument htmlDocument = new HtmlDocument(); htmlDocument.Load(memoryStream); HtmlNodeCollection tables=htmlDocument.DocumentNode.SelectNodes("//table"); if(null==tables || tables.Count<5)return null; HtmlNode nameAndAddressTable=FindTable(tables,"1. Name and Address of Reporting Person"); if(null==nameAndAddressTable)return null; HtmlNodeCollection nameAndAddressRows = nameAndAddressTable.SelectNodes(".//tr"); if(nameAndAddressRows.Count<2)return null; insiderName=ApplyNameCase(nameAndAddressRows[1].InnerText); for(int index=0;index dictionary=new Dictionary(); dictionary.Add("Title of Security",dataCollection[0].InnerHtml); dictionary.Add("Transaction Date",dataCollection[1].InnerHtml); dictionary.Add("Transaction Code",dataCollection[3].InnerHtml); dictionary.Add("Securities Acquired or Disposed",dataCollection[5].InnerHtml); dictionary.Add("Acquired or Disposed",dataCollection[6].InnerHtml); dictionary.Add("Price",dataCollection[7].InnerHtml); dictionary.Add("Ownership Form",dataCollection[9].InnerHtml); dictionaryList.Add(dictionary); } } } int sequenceNumber=0; foreach(Dictionary dictionary in dictionaryList) { String strItem=null; InsiderTransaction insiderTransaction=new InsiderTransaction(); insiderTransaction.Symbol=symbol; insiderTransaction.SECAccessionNumber=secAccessionNumber; insiderTransaction.Form=form; insiderTransaction.FilingDate=filingDate; insiderTransaction.InsiderName=insiderName; insiderTransaction.Securities=GetFirstSection(Sections.GetSections(dictionary["Title of Security"])); insiderTransaction.OwnershipType=GetOwnershipForm(Sections.GetSections(dictionary["Ownership Form"])); if(String.IsNullOrEmpty(insiderTransaction.OwnershipType))continue; strItem=GetFirstSection(Sections.GetSections(dictionary["Transaction Date"])); if(String.IsNullOrEmpty(strItem))continue; insiderTransaction.TransactionDate=Utility.ParseDate(strItem); insiderTransaction.NatureOfTransaction=transactionCodes.ContainsKey(GetFirstSection(Sections.GetSections(dictionary["Transaction Code"])))?transactionCodes[GetFirstSection(Sections.GetSections(dictionary["Transaction Code"]))]:Constants.CONST_QUESTION; insiderTransaction.NumberOrValueAcquiredDisposed=FeedParser.ParseValue(GetFirstSection(Sections.GetSections(dictionary["Securities Acquired or Disposed"]))); // insiderTransaction.FormRowNumber=((decimal)insiderTransaction.NumberOrValueAcquiredDisposed).ToString(); insiderTransaction.FormRowNumber=(++sequenceNumber).ToString(); insiderTransaction.Price=FeedParser.ParseValue(CombineSections(Sections.GetSections(dictionary["Price"]))); String acquiredOrDisposed=GetAcquiredOrDisposed(dictionary); if(null==acquiredOrDisposed) { MDTrace.WriteLine(LogLevel.DEBUG,String.Format("Parse - Cannot determine acquied or disposed for accession#{0}",secAccessionNumber)); continue; } if(acquiredOrDisposed.Equals("D")) { insiderTransaction.NumberOrValueAcquiredDisposed*=-1; } insiderTransactions.Add(insiderTransaction); } return insiderTransactions; } catch(Exception exception) { MDTrace.WriteLine(LogLevel.DEBUG,String.Format("Parse - Got exception {0}",exception.ToString())); return null; } } private HtmlNode FindTable(HtmlNodeCollection tables,String startsWith) { if(null==tables)return null; for(int index=0;index1)sb.Append(item.Substring(0,1).ToUpper()+item.Substring(1)); else sb.Append(item.ToUpper()); if(index sections) { String item=GetFirstSection(sections); if(null==item)item=""; item=item.ToUpper(); if(item.Equals("D"))return "Direct Ownership"; else if(item.Equals("I"))return "Indirect Ownership"; return ""; } private String GetAcquiredOrDisposed(Dictionary dictionary) { if(!dictionary.ContainsKey("Acquired or Disposed"))return null; List section=Sections.GetSections(dictionary["Acquired or Disposed"]); if(null==section||0==section.Count)return null; String acquiredOrDisposed=section[0]; if(null==acquiredOrDisposed)return null; return acquiredOrDisposed.Trim().ToUpper(); } private String GetFirstSection(List sections) { if(null==sections || 0==sections.Count)return ""; return sections[0]; } private String CombineSections(List sections) { StringBuilder sb=new StringBuilder(); if(null==sections || 0==sections.Count)return ""; foreach(String section in sections) { sb.Append(section); } return sb.ToString(); } private void BuildTransactionCodes() { transactionCodes.TryAdd("P","Open market or private purchase of non-derivative or derivative security"); transactionCodes.TryAdd("S","Open market or private sale of non-derivative or derivative security"); transactionCodes.TryAdd("V","Transaction voluntarily reported earlier than required"); transactionCodes.TryAdd("A","Grant, award or other acquisition pursuant to Rule 16b-3(d)"); transactionCodes.TryAdd("D","Disposition to the issuer of issuer equity securities pursuant to Rule 16b-3(e)"); transactionCodes.TryAdd("F","Payment of exercise price or tax liability by delivering or withholding securities incident to the receipt, exercise or vesting of a security issued in accordance with Rule 16b-3"); transactionCodes.TryAdd("I","Discretionary transaction in accordance with Rule 16b-3(f) resulting in acquisition or disposition of issuer securities"); transactionCodes.TryAdd("M","Exercise or conversion of derivative security exempted pursuant to Rule 16b-3"); transactionCodes.TryAdd("C","Conversion of derivative security"); transactionCodes.TryAdd("E","Expiration of short derivative position"); transactionCodes.TryAdd("H","Expiration (or cancellation) of long derivative position with value received"); transactionCodes.TryAdd("O","Exercise of out-of-the-money derivative security"); transactionCodes.TryAdd("X","Exercise of in-the-money or at-the-money derivative security"); transactionCodes.TryAdd("G","Bona fide gift"); transactionCodes.TryAdd("L","Small acquisition under Rule 16a-6"); transactionCodes.TryAdd("W","Acquisition or disposition by will or the laws of descent and distribution"); transactionCodes.TryAdd("Z","Deposit into or withdrawal from voting trust"); transactionCodes.TryAdd("J","Other acquisition or disposition (describe transaction)"); transactionCodes.TryAdd("K","Transaction in equity swap or instrument with similar characteristics"); transactionCodes.TryAdd("U","Disposition pursuant to a tender of shares in a change of control transaction"); } } }