Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
kevinsawicki committed May 11, 2013
0 parents commit 6e2f228
Show file tree
Hide file tree
Showing 10 changed files with 174 additions and 0 deletions.
4 changes: 4 additions & 0 deletions .gitignore
@@ -0,0 +1,4 @@
node_modules/
*.js
.DS_Store
*.log
4 changes: 4 additions & 0 deletions .npmignore
@@ -0,0 +1,4 @@
.npmignore
*.coffee
.DS_Store
*.log
36 changes: 36 additions & 0 deletions Gruntfile.coffee
@@ -0,0 +1,36 @@
module.exports = (grunt) ->
grunt.initConfig
pkg: grunt.file.readJSON('package.json')

coffee:
glob_to_multiple:
expand: true
cwd: 'src'
src: ['*.coffee']
dest: 'lib'
ext: '.js'

coffeelint:
options:
max_line_length:
level: 'ignore'

src: ['src/*.coffee']
test: ['spec/*.coffee']

shell:
test:
command: 'npm test'
options:
stdout: true
stderr: true
failOnError: true

grunt.loadNpmTasks('grunt-coffeelint')
grunt.loadNpmTasks('grunt-contrib-coffee')
grunt.loadNpmTasks('grunt-shell')

grunt.registerTask 'clean', -> require('rimraf').sync('lib')
grunt.registerTask('lint', ['coffeelint:src', 'coffeelint:test'])
grunt.registerTask('default', ['coffeelint:src', 'coffee'])
grunt.registerTask('test', ['lint', 'coffee', 'shell:test'])
20 changes: 20 additions & 0 deletions LICENSE.md
@@ -0,0 +1,20 @@
Copyright (c) 2013 Kevin Sawicki

Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
14 changes: 14 additions & 0 deletions README.md
@@ -0,0 +1,14 @@
# Filings

Node module for downloading and querying SEC filings.

## Installing

```sh
npm install filings
```

## Building
* Clone this repository
* Run `npm install`
* Run `grunt` to compile the CoffeeScript code
44 changes: 44 additions & 0 deletions package.json
@@ -0,0 +1,44 @@
{
"name": "filings",
"descriptions": "SEC filings module",
"licenses": [
{
"type": "MIT",
"url": "http://github.com/kevinsawicki/filings/raw/master/LICENSE.md"
}
],
"keywords": [
"sec",
"edgar",
"10-K"
],
"author": {
"name": "Kevin Sawicki",
"email": "kevinsawicki@gmail.com"
},
"repository": {
"type": "git",
"url": "https://github.com/kevinsawicki/filings.git"
},
"bugs": {
"url": "https://github.com/kevinsawicki/filings/issues"
},
"scripts": {
"prepublish": "grunt",
"test": "jasmine-focused --captureExceptions --coffee spec/"
},
"devDependencies": {
"grunt": "~0.4.1",
"grunt-cli": "~0.1.8",
"grunt-contrib-coffee": "~0.7.0",
"grunt-coffeelint": "0.0.6",
"rimraf": "~2.1.4",
"jasmine-focused": "~0.1.0",
"grunt-shell": "~0.2.2"
},
"dependencies": {
"xpath": "0.0.5",
"xmldom": "~0.1.16",
"ls-archive": "~0.5.0"
}
}
Binary file added spec/fixtures/luv-2012-10-K.gz
Binary file not shown.
Binary file added spec/fixtures/tr-2012-10-K.gz
Binary file not shown.
15 changes: 15 additions & 0 deletions spec/ten-k-spec.coffee
@@ -0,0 +1,15 @@
path = require 'path'
TenK = require '../lib/ten-k'

describe '10-K', ->
describe '.getProfit(year)', ->
it 'returns the profit for the given year', ->
reportPath = path.join(__dirname, 'fixtures', 'luv-2012-10-K.gz')
openedReport = null
TenK.open reportPath, (error, report) ->
openedReport = report
waitsFor -> openedReport?
runs ->
expect(openedReport.getProfit(2012)).toBe 421000000
expect(openedReport.getProfit(2011)).toBe 178000000
expect(openedReport.getProfit(2010)).toBe 459000000
37 changes: 37 additions & 0 deletions src/ten-k.coffee
@@ -0,0 +1,37 @@
archive = require 'ls-archive'
{DOMParser} = require 'xmldom'
xpath = require 'xpath'

module.exports =
class TenK
@open: (path, callback) ->
archive.readGzip path, (error, data) ->
if error?
callback(error)
else
callback(null, new TenK(data))

constructor: (@contents) ->
@document = new DOMParser().parseFromString(@contents)

getYear: (dateRange='') ->
if match = dateRange.match(/^from_([a-z]+\d{2})_(\d{4})_to_([a-z]+\d{2})_(\d{4})$/i)
fromDate = Date.parse("#{match[1]} #{match[2]}")
return -1 if isNaN(fromDate)
toDate = Date.parse("#{match[3]} #{match[4]}")
return -1 if isNaN(toDate)
day = 24 * 60 *(1000 * 60)
days = (toDate - fromDate) / day
return new Date(toDate).getFullYear() if 300 < days < 400
-1

getProfit: (year) ->
nodes = xpath.select("//*[local-name() = 'NetIncomeLoss']", @document)
netIncomeLoss = 0
for node in nodes
continue unless node.prefix is 'us-gaap'
nodeYear = @getYear(xpath.select("@contextRef", node)[0]?.value)
nodeNetIncomeLoss = parseFloat(node.firstChild.data)
continue if isNaN(nodeNetIncomeLoss)
netIncomeLoss += nodeNetIncomeLoss if year is nodeYear
netIncomeLoss

0 comments on commit 6e2f228

Please sign in to comment.