{"_id":"currency-market","_rev":"43-fbd90b0f2c93408f5710110d7456c04e","name":"currency-market","description":"A synchronous implementation of a limit order based currency market","dist-tags":{"latest":"0.4.2"},"versions":{"0.0.1":{"name":"currency-market","description":"A synchronous implementation of a limit order based currency market","version":"0.0.1","homepage":"https://github.com/pghalliday/currency-market","author":{"name":"Peter Halliday","email":"pghalliday@gmail.com","url":"http://stuffpetedoes.blogspot.nl/"},"repository":{"type":"git","url":"git://github.com/pghalliday/currency-market.git"},"bugs":{"url":"https://github.com/pghalliday/currency-market/issues"},"licenses":[{"type":"MIT","url":"https://github.com/pghalliday/currency-market/blob/master/LICENSE-MIT"}],"main":"lib/src/CurrencyMarket","engines":{"node":">= 0.10.4"},"scripts":{"prepublish":"grunt","test":"grunt"},"dependencies":{"bigdecimal":"~0.6.1"},"devDependencies":{"chai":"~1.5.0","node-uuid":"~1.4.0","checklist":"0.0.6","grunt-cli":"~0.1.7","grunt":"~0.4.1","grunt-contrib-coffee":"~0.7.0","grunt-mocha-test":"~0.2.2","grunt-contrib-clean":"~0.4.1"},"keywords":["currency","trading","limit order","synchronous","market"],"readme":"currency-market\n===============\n\nA synchronous implementation of a limit order based currency market\n\n## Features\n\n- Supports an arbitrary list of currencies\n- Synchronously executes trades as orders are added\n- Emits events when changes are made to the market\n\n## Installation\n\n```\nnpm install currency-market\n```\n\n## API\n\nAll functions complete synchronously and throw errors if they fail.\nEvents are made available for monitoring changes in the market.\n\n```javascript\nvar CurrencyMarket = require('currency-market');\n\n// instantiate a market\nvar currencyMarket = new CurrencyMarket({\n  currencies: [\n    'EUR',\n    'USD',\n    'BTC'\n  ]\n});\n\n// register for events\ncurrencyMarket.on('account', function(account) {\n  console.log(account);\n});\ncurrencyMarket.on('deposit', function(deposit) {\n  console.log(deposit);\n});\ncurrencyMarket.on('withdrawal', function(withdrawal) {\n  console.log(withdrawal);\n});\ncurrencyMarket.on('order', function(order) {\n  console.log(order);\n});\ncurrencyMarket.on('cancellation', function(order) {\n  console.log(order);\n});\ncurrencyMarket.on('trade', function(trade) {\n  console.log(trade);\n});\n\n// add accounts\ncurrencyMarket.register({\n  id: 'Peter'\n});\ncurrencyMarket.register({\n  id: 'Paul'\n});\n\n// make deposits\ncurrencyMarket.deposit({\n  account: 'Peter',\n  currency: 'EUR',\n  amount: '5000'\n});\ncurrencyMarket.deposit({\n  account: 'Paul',\n  currency: 'BTC',\n  amount: '5000'\n});\n\n// make withdrawals\ncurrencyMarket.withdraw({\n  account: 'Peter',\n  currency: 'EUR',\n  amount: '1000'\n});\ncurrencyMarket.withdraw({\n  account: 'Paul',\n  currency: 'BTC',\n  amount: '1000'\n});\n\n// submit orders\ncurrencyMarket.submit({\n  id: '1',\n  timestamp: '1366758222',\n  account: 'Peter',\n  bidCurrency: 'BTC',\n  offerCurrency: 'EUR',\n  bidPrice: '2',\n  bidAmount: '500'\n});\ncurrencyMarket.submit({\n  id: '2',\n  timestamp: '1366758245',\n  account: 'Peter',\n  bidCurrency: 'BTC',\n  offerCurrency: 'EUR',\n  bidPrice: '1',\n  bidAmount: '2000'\n});\ncurrencyMarket.submit({\n  id: '3',\n  timestamp: '1366758256',\n  account: 'Paul',\n  bidCurrency: 'EUR',\n  offerCurrency: 'BTC',\n  offerPrice: '2',\n  offerAmount: '250'\n});\ncurrencyMarket.submit({\n  id: '4',\n  timestamp: '1366758268',\n  account: 'Paul',\n  bidCurrency: 'EUR',\n  offerCurrency: 'BTC',\n  offerPrice: '3',\n  offerAmount: '3000'\n});\n\n// cancel an order\ncurrencyMarket.cancel({\n  id: '1',\n  timestamp: '1366758222',\n  account: 'Peter',\n  bidCurrency: 'BTC',\n  offerCurrency: 'EUR',\n  bidPrice: '2',\n  bidAmount: '250'\n});\n\n// list all the active orders (keyed by id)\nconsole.log(currencyMarket.orders);\n\n// list all the active accounts (keyed by id)\nconsole.log(currencyMarket.accounts);\n\n// list all the active order books \nconsole.log(currencyMarket.books);\n\n// Get the top of an order book\nconsole.log(currencyMarket.books['EUR']['BTC'].highest);\nconsole.log(currencyMarket.books['BTC']['EUR'].highest);\n```\n\n## Roadmap\n\n- Instant orders (execute or cancel)\n- Pluggable rounding policies\n- Pluggable commission schemes\n\n## Contributing\n\nIn lieu of a formal styleguide, take care to maintain the existing coding style. Add unit tests for any new or changed functionality.\n\nThe CoffeeScript source is located in the `src/` directory and tests in the `test/` directory. Do not edit the contents of the `lib/` directory as this is compiled from the CoffeeScript source.\n\nBefore commiting run `npm test` to perform a clean compile of the source and run the tests. This ensures that everything commited is up to date and tested and allows people to `npm install` directly from the git repository (useful for integrating development branches, etc).\n\n## License\nCopyright (c) 2013 Peter Halliday  \nLicensed under the MIT license.","readmeFilename":"README.md","_id":"currency-market@0.0.1","dist":{"shasum":"7decc6dad9ede962efc86de2ee8a2072f3e8dfa9","tarball":"https://registry.npmjs.org/currency-market/-/currency-market-0.0.1.tgz","integrity":"sha512-goAro0TEAr/DmfwcMv0jnCU9r+bZDS50DpzXW3UzLJ4MFdc5b5Y381fOK3zm8ftJ3EhoZSp059Itii7ggJx3VA==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIFF6I1g0JZHNlmzNKF8hMi9CdOdr6OhlRcfb1MZDICCsAiEApOSBdCmEcLYh157unl586BCqwBQ237IagPHVoTZUE/w="}]},"_from":".","_npmVersion":"1.2.18","_npmUser":{"name":"pghalliday","email":"pghalliday@gmail.com"},"maintainers":[{"name":"pghalliday","email":"pghalliday@gmail.com"}],"directories":{}},"0.1.0":{"name":"currency-market","description":"A synchronous implementation of a limit order based currency market","version":"0.1.0","homepage":"https://github.com/pghalliday/currency-market","author":{"name":"Peter Halliday","email":"pghalliday@gmail.com","url":"http://stuffpetedoes.blogspot.nl/"},"repository":{"type":"git","url":"git://github.com/pghalliday/currency-market.git"},"bugs":{"url":"https://github.com/pghalliday/currency-market/issues"},"licenses":[{"type":"MIT","url":"https://github.com/pghalliday/currency-market/blob/master/LICENSE-MIT"}],"main":"lib/src/","engines":{"node":">= 0.10.4"},"scripts":{"prepublish":"grunt","test":"grunt"},"dependencies":{"bigdecimal":"~0.6.1"},"devDependencies":{"chai":"~1.5.0","node-uuid":"~1.4.0","checklist":"0.0.6","grunt-cli":"~0.1.7","grunt":"~0.4.1","grunt-contrib-coffee":"~0.7.0","grunt-mocha-test":"~0.2.2","grunt-contrib-clean":"~0.4.1","sinon":"~1.6.0","sinon-chai":"~2.4.0"},"keywords":["currency","trading","limit order","synchronous","market"],"readme":"currency-market\n===============\n\nA synchronous implementation of a limit order based currency market\n\n## Features\n\n- Supports an arbitrary list of currencies\n- Synchronously executes trades as orders are added\n- Emits events when changes are made to the market\n- Can export the state and initialise from an exported state\n\n## Installation\n\n```\nnpm install currency-market\n```\n\n## API\n\nAll functions and constructors complete synchronously and throw errors if they fail.\nEvents are made available for monitoring changes in the market.\n\n```javascript\nvar Market = require('currency-market').Market;\nvar Account = require('currency-market').Account;\nvar Amount = require('currency-market').Amount;\nvar Order = require('currency-market').Order;\n\n// instantiate a market\nvar market = new Market({\n  currencies: [\n    'EUR',\n    'USD',\n    'BTC'\n  ]\n});\n\n// register for events\nmarket.on('account', function(account) {\n  console.log('');\n  console.log('********************');\n  console.log('********************');\n  console.log('');\n  console.log('Account');\n  console.log('');\n  console.log('********************');\n  console.log('********************');\n  console.log('');\n  console.log(account);\n});\nmarket.on('deposit', function(deposit) {\n  console.log('');\n  console.log('********************');\n  console.log('********************');\n  console.log('');\n  console.log('Deposit');\n  console.log('');\n  console.log('********************');\n  console.log('********************');\n  console.log('');\n  console.log(deposit);\n});\nmarket.on('withdrawal', function(withdrawal) {\n  console.log('');\n  console.log('********************');\n  console.log('********************');\n  console.log('');\n  console.log('Withdrawal');\n  console.log('');\n  console.log('********************');\n  console.log('********************');\n  console.log('');\n  console.log(withdrawal);\n});\nmarket.on('order', function(order) {\n  console.log('');\n  console.log('********************');\n  console.log('********************');\n  console.log('');\n  console.log('Order');\n  console.log('');\n  console.log('********************');\n  console.log('********************');\n  console.log('');\n  console.log(order);\n});\nmarket.on('cancellation', function(cancellation) {\n  console.log('');\n  console.log('********************');\n  console.log('********************');\n  console.log('');\n  console.log('Cancellation');\n  console.log('');\n  console.log('********************');\n  console.log('********************');\n  console.log('');\n  console.log(cancellation);\n});\nmarket.on('trade', function(trade) {\n  console.log('');\n  console.log('********************');\n  console.log('********************');\n  console.log('');\n  console.log('Trade');\n  console.log('');\n  console.log('********************');\n  console.log('********************');\n  console.log('');\n  console.log(trade);\n});\n\n// add accounts\nmarket.register(new Account({\n  id: '100000',\n  timestamp: '1366758222',\n  currencies: [\n    'EUR',\n    'USD',\n    'BTC'\n  ]\n}));\nmarket.register(new Account({\n  id: '100001',\n  timestamp: '1366758223',\n  currencies: [\n    'EUR',\n    'USD',\n    'BTC'\n  ]\n}));\n\n// make deposits\nmarket.deposit({\n  id: '100002',\n  timestamp: '1366758224',\n  account: '100000',\n  currency: 'EUR',\n  amount: new Amount('5000')\n});\nmarket.deposit({\n  id: '100003',\n  timestamp: '1366758225',\n  account: '100001',\n  currency: 'BTC',\n  amount: new Amount('5000')\n});\n\n// make withdrawals\nmarket.withdraw({\n  id: '100004',\n  timestamp: '1366758226',\n  account: '100000',\n  currency: 'EUR',\n  amount: new Amount('1000')\n});\nmarket.withdraw({\n  id: '100005',\n  timestamp: '1366758227',\n  account: '100001',\n  currency: 'BTC',\n  amount: new Amount('1000')\n});\n\n// submit orders\nmarket.submit(new Order({\n  id: '100006',\n  timestamp: '1366758228',\n  account: '100000',\n  bidCurrency: 'BTC',\n  offerCurrency: 'EUR',\n  bidPrice: new Amount('2'),\n  bidAmount: new Amount('500')\n}));\nmarket.submit(new Order({\n  id: '100007',\n  timestamp: '1366758229',\n  account: '100000',\n  bidCurrency: 'BTC',\n  offerCurrency: 'EUR',\n  bidPrice: new Amount('1'),\n  bidAmount: new Amount('2000')\n}));\nmarket.submit(new Order({\n  id: '100008',\n  timestamp: '1366758230',\n  account: '100001',\n  bidCurrency: 'EUR',\n  offerCurrency: 'BTC',\n  offerPrice: new Amount('2'),\n  offerAmount: new Amount('250')\n}));\nmarket.submit(new Order({\n  id: '100009',\n  timestamp: '1366758231',\n  account: '100001',\n  bidCurrency: 'EUR',\n  offerCurrency: 'BTC',\n  offerPrice: new Amount('3'),\n  offerAmount: new Amount('3000')\n}));\n\n// cancel an order (this will match because 250 BTC was already traded on this order)\nmarket.cancel({\n  id: '100010',\n  timestamp: '1366758232',\n  order: new Order({\n    id: '100006',\n    timestamp: '1366758228',\n    account: '100000',\n    bidCurrency: 'BTC',\n    offerCurrency: 'EUR',\n    bidPrice: new Amount('2'),\n    bidAmount: new Amount('250')\n  })\n});\n\n// list all the active accounts (keyed by id)\nconsole.log('');\nconsole.log('********************');\nconsole.log('********************');\nconsole.log('');\nconsole.log('Accounts');\nconsole.log('');\nconsole.log('********************');\nconsole.log('********************');\nconsole.log('');\nconsole.log(market.accounts);\n\n// list all the active order books \nconsole.log('');\nconsole.log('********************');\nconsole.log('********************');\nconsole.log('');\nconsole.log('Books');\nconsole.log('');\nconsole.log('********************');\nconsole.log('********************');\nconsole.log('');\nconsole.log(market.books);\n\n// Get the top of an order book\nconsole.log('');\nconsole.log('********************');\nconsole.log('********************');\nconsole.log('');\nconsole.log('Highest EUR bid');\nconsole.log('');\nconsole.log('********************');\nconsole.log('********************');\nconsole.log('');\nconsole.log(market.books['EUR']['BTC'].highest);\nconsole.log('');\nconsole.log('********************');\nconsole.log('********************');\nconsole.log('');\nconsole.log('Highest BTC bid');\nconsole.log('');\nconsole.log('********************');\nconsole.log('********************');\nconsole.log('');\nconsole.log(market.books['BTC']['EUR'].highest);\n\n// export the state (as an object that can be converted to JSON)\nvar state  = market.export();\n\n// JSON stringify the state\nvar json = JSON.stringify(state);\nconsole.log('');\nconsole.log('********************');\nconsole.log('********************');\nconsole.log('');\nconsole.log('Stringified market state');\nconsole.log('');\nconsole.log('********************');\nconsole.log('********************');\nconsole.log('');\nconsole.log(json);\n\n// initialise an identical market from the state\nvar anotherMarket = new Market({\n  state: JSON.parse(json)\n});\n\n// Retrieve the last transaction ID processed \nconsole.log('');\nconsole.log('********************');\nconsole.log('********************');\nconsole.log('');\nconsole.log('Last transaction ID from new Market: ' + anotherMarket.lastTransaction);\nconsole.log('');\nconsole.log('********************');\nconsole.log('********************');\n```\n\n## Roadmap\n\n- Instant orders\n  - Fill or Kill limit orders\n  - Market orders\n- Pluggable commission schemes\n  - fixed rate\n  - calculated through callback\n- Pluggable rounding policies\n  - Amount factory required?\n  - Divide at last possible moment?\n\n## Contributing\n\nIn lieu of a formal styleguide, take care to maintain the existing coding style. Add unit tests for any new or changed functionality.\n\nThe CoffeeScript source is located in the `src/` directory and tests in the `test/` directory. Do not edit the contents of the `lib/` directory as this is compiled from the CoffeeScript source.\n\nBefore commiting run `npm test` to perform a clean compile of the source and run the tests. This ensures that everything commited is up to date and tested and allows people to `npm install` directly from the git repository (useful for integrating development branches, etc).\n\n## License\nCopyright (c) 2013 Peter Halliday  \nLicensed under the MIT license.","readmeFilename":"README.md","_id":"currency-market@0.1.0","dist":{"shasum":"3a01028917f8a0637df32f499f86bb3951d684aa","tarball":"https://registry.npmjs.org/currency-market/-/currency-market-0.1.0.tgz","integrity":"sha512-mjpCEZOkIY7cIDda7zQLwWM+LhpiFzIEngnFnLTsu8MYh/9cVK/Ut2c+FAIUD7IhFpQSy1We5m5L4A6FISoeyw==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDv70HywUEtZPp4D4dHvUBHd0xOx4+JL212I/tXC2CfXQIhAPnkvxpWjZbnazDLFutd31vhQ/MbEDwYQ1mlkXErbIYx"}]},"_from":".","_npmVersion":"1.2.18","_npmUser":{"name":"pghalliday","email":"pghalliday@gmail.com"},"maintainers":[{"name":"pghalliday","email":"pghalliday@gmail.com"}],"directories":{}},"0.1.1":{"name":"currency-market","description":"A synchronous implementation of a limit order based currency market","version":"0.1.1","homepage":"https://github.com/pghalliday/currency-market","author":{"name":"Peter Halliday","email":"pghalliday@gmail.com","url":"http://stuffpetedoes.blogspot.nl/"},"repository":{"type":"git","url":"git://github.com/pghalliday/currency-market.git"},"bugs":{"url":"https://github.com/pghalliday/currency-market/issues"},"licenses":[{"type":"MIT","url":"https://github.com/pghalliday/currency-market/blob/master/LICENSE-MIT"}],"main":"lib/src/","engines":{"node":">= 0.10.4"},"scripts":{"prepublish":"grunt","test":"grunt"},"dependencies":{"bigdecimal":"~0.6.1"},"devDependencies":{"chai":"~1.5.0","node-uuid":"~1.4.0","checklist":"0.0.6","grunt-cli":"~0.1.7","grunt":"~0.4.1","grunt-contrib-coffee":"~0.7.0","grunt-mocha-test":"~0.2.2","grunt-contrib-clean":"~0.4.1","sinon":"~1.6.0","sinon-chai":"~2.4.0","randgen":"0.0.2"},"keywords":["currency","trading","limit order","synchronous","market"],"readme":"currency-market\n===============\n\nA synchronous implementation of a limit order based currency market\n\n## Features\n\n- Supports an arbitrary list of currencies\n- Synchronously executes trades as orders are added\n- Emits events when changes are made to the market\n- Can export the state and initialise from an exported state\n\n## Installation\n\n```\nnpm install currency-market\n```\n\n## API\n\nAll functions and constructors complete synchronously and throw errors if they fail.\nEvents are made available for monitoring changes in the market.\n\n```javascript\nvar Market = require('currency-market').Market;\nvar Account = require('currency-market').Account;\nvar Amount = require('currency-market').Amount;\nvar Order = require('currency-market').Order;\n\n// instantiate a market\nvar market = new Market({\n  currencies: [\n    'EUR',\n    'USD',\n    'BTC'\n  ]\n});\n\n// register for events\nmarket.on('account', function(account) {\n  console.log('');\n  console.log('********************');\n  console.log('********************');\n  console.log('');\n  console.log('Account');\n  console.log('');\n  console.log('********************');\n  console.log('********************');\n  console.log('');\n  console.log(account);\n});\nmarket.on('deposit', function(deposit) {\n  console.log('');\n  console.log('********************');\n  console.log('********************');\n  console.log('');\n  console.log('Deposit');\n  console.log('');\n  console.log('********************');\n  console.log('********************');\n  console.log('');\n  console.log(deposit);\n});\nmarket.on('withdrawal', function(withdrawal) {\n  console.log('');\n  console.log('********************');\n  console.log('********************');\n  console.log('');\n  console.log('Withdrawal');\n  console.log('');\n  console.log('********************');\n  console.log('********************');\n  console.log('');\n  console.log(withdrawal);\n});\nmarket.on('order', function(order) {\n  console.log('');\n  console.log('********************');\n  console.log('********************');\n  console.log('');\n  console.log('Order');\n  console.log('');\n  console.log('********************');\n  console.log('********************');\n  console.log('');\n  console.log(order);\n});\nmarket.on('cancellation', function(cancellation) {\n  console.log('');\n  console.log('********************');\n  console.log('********************');\n  console.log('');\n  console.log('Cancellation');\n  console.log('');\n  console.log('********************');\n  console.log('********************');\n  console.log('');\n  console.log(cancellation);\n});\nmarket.on('trade', function(trade) {\n  console.log('');\n  console.log('********************');\n  console.log('********************');\n  console.log('');\n  console.log('Trade');\n  console.log('');\n  console.log('********************');\n  console.log('********************');\n  console.log('');\n  console.log(trade);\n});\n\n// add accounts\nmarket.register(new Account({\n  // All IDs are intended to be the transaction IDs and as such\n  // should be globally unique. If not unique then the lastTransaction\n  // field may be rendered meaningless preventing restoration from a \n  // saved transaction log.\n  // Additionally these IDs are used to key collections so strange behaviour\n  // may result if they are not unique\n  id: '100000',\n  // Although the timestamp is not used internally, it is required\n  // so that any functionality hanging off the events can replicate\n  // their time relative behaviour in case a Market has to be restored\n  // from a transaction log\n  timestamp: '1366758222',\n  currencies: [\n    'EUR',\n    'USD',\n    'BTC'\n  ]\n}));\nmarket.register(new Account({\n  id: '100001',\n  timestamp: '1366758223',\n  currencies: [\n    'EUR',\n    'USD',\n    'BTC'\n  ]\n}));\n\n// make deposits\nmarket.deposit({\n  id: '100002',\n  timestamp: '1366758224',\n  // Note that the acount field should be set to the ID of the account.\n  // This is one of the instances whre the transaction ID is used as a key\n  account: '100000',\n  currency: 'EUR',\n  amount: new Amount('5000')\n});\nmarket.deposit({\n  id: '100003',\n  timestamp: '1366758225',\n  account: '100001',\n  currency: 'BTC',\n  amount: new Amount('5000')\n});\n\n// make withdrawals\nmarket.withdraw({\n  id: '100004',\n  timestamp: '1366758226',\n  account: '100000',\n  currency: 'EUR',\n  amount: new Amount('1000')\n});\nmarket.withdraw({\n  id: '100005',\n  timestamp: '1366758227',\n  account: '100001',\n  currency: 'BTC',\n  amount: new Amount('1000')\n});\n\n// submit orders\nmarket.submit(new Order({\n  id: '100006',\n  timestamp: '1366758228',\n  account: '100000',\n  bidCurrency: 'BTC',\n  offerCurrency: 'EUR',\n  bidPrice: new Amount('2'),\n  bidAmount: new Amount('500')\n}));\nmarket.submit(new Order({\n  id: '100007',\n  timestamp: '1366758229',\n  account: '100000',\n  bidCurrency: 'BTC',\n  offerCurrency: 'EUR',\n  bidPrice: new Amount('1'),\n  bidAmount: new Amount('2000')\n}));\nmarket.submit(new Order({\n  id: '100008',\n  timestamp: '1366758230',\n  account: '100001',\n  bidCurrency: 'EUR',\n  offerCurrency: 'BTC',\n  offerPrice: new Amount('2'),\n  offerAmount: new Amount('250')\n}));\nmarket.submit(new Order({\n  id: '100009',\n  timestamp: '1366758231',\n  account: '100001',\n  bidCurrency: 'EUR',\n  offerCurrency: 'BTC',\n  offerPrice: new Amount('3'),\n  offerAmount: new Amount('3000')\n}));\n\n// cancel an order\nmarket.cancel({\n  id: '100010',\n  timestamp: '1366758232',\n  // The Order instance must exactly match the current state\n  // of the order being cancelled. This example will match \n  // because 250 BTC was already traded on this order. This is\n  // another instance where the transaction ID is used as a key\n  order: new Order({\n    id: '100006',\n    timestamp: '1366758228',\n    account: '100000',\n    bidCurrency: 'BTC',\n    offerCurrency: 'EUR',\n    bidPrice: new Amount('2'),\n    bidAmount: new Amount('250')\n  })\n});\n\n// list all the active accounts (keyed by id)\nconsole.log('');\nconsole.log('********************');\nconsole.log('********************');\nconsole.log('');\nconsole.log('Accounts');\nconsole.log('');\nconsole.log('********************');\nconsole.log('********************');\nconsole.log('');\nconsole.log(market.accounts);\n\n// list all the active order books \nconsole.log('');\nconsole.log('********************');\nconsole.log('********************');\nconsole.log('');\nconsole.log('Books');\nconsole.log('');\nconsole.log('********************');\nconsole.log('********************');\nconsole.log('');\nconsole.log(market.books);\n\n// Get the top of an order book\nconsole.log('');\nconsole.log('********************');\nconsole.log('********************');\nconsole.log('');\nconsole.log('Highest EUR bid');\nconsole.log('');\nconsole.log('********************');\nconsole.log('********************');\nconsole.log('');\nconsole.log(market.books['EUR']['BTC'].highest);\nconsole.log('');\nconsole.log('********************');\nconsole.log('********************');\nconsole.log('');\nconsole.log('Highest BTC bid');\nconsole.log('');\nconsole.log('********************');\nconsole.log('********************');\nconsole.log('');\nconsole.log(market.books['BTC']['EUR'].highest);\n\n// export the state (as an object that can be converted to JSON)\nvar state  = market.export();\n\n// JSON stringify the state\nvar json = JSON.stringify(state);\nconsole.log('');\nconsole.log('********************');\nconsole.log('********************');\nconsole.log('');\nconsole.log('Stringified market state');\nconsole.log('');\nconsole.log('********************');\nconsole.log('********************');\nconsole.log('');\nconsole.log(json);\n\n// initialise an identical market from the state\nvar anotherMarket = new Market({\n  state: JSON.parse(json)\n});\n\n// Retrieve the last transaction ID processed \nconsole.log('');\nconsole.log('********************');\nconsole.log('********************');\nconsole.log('');\nconsole.log('Last transaction ID from new Market: ' + anotherMarket.lastTransaction);\nconsole.log('');\nconsole.log('********************');\nconsole.log('********************');\n```\n\n## Roadmap\n\n- Performance tests\n  - Create performance test classes to see how performance changes as parameters change\n    ie: why does the random test perform less trades/second the more iterations there are when each iteration should be independent\n      - test parameter lookups? - cut them out of the timings!\n      - garbage collection?\n- List orders by account\n- List orders by book (in order)\n- Instant orders\n  - Fill or Kill limit orders\n  - Market orders\n- Pluggable commission schemes\n  - fixed rate\n  - calculated through callback\n- Pluggable rounding policies\n  - Amount factory required?\n  - Divide at last possible moment?\n- Protection against attacks?\n  - entering orders that satisfy each other\n  - entering tiny orders\n  - should this be in a another layer?\n\n## Contributing\n\nIn lieu of a formal styleguide, take care to maintain the existing coding style. Add unit tests for any new or changed functionality.\n\nThe CoffeeScript source is located in the `src/` directory and tests in the `test/` directory. Do not edit the contents of the `lib/` directory as this is compiled from the CoffeeScript source.\n\nBefore commiting run `npm test` to perform a clean compile of the source and run the tests. This ensures that everything commited is up to date and tested and allows people to `npm install` directly from the git repository (useful for integrating development branches, etc).\n\n## License\nCopyright (c) 2013 Peter Halliday  \nLicensed under the MIT license.","readmeFilename":"README.md","_id":"currency-market@0.1.1","dist":{"shasum":"4bb932c5ba488410661c898c1336b0a33409656d","tarball":"https://registry.npmjs.org/currency-market/-/currency-market-0.1.1.tgz","integrity":"sha512-ruhcW+Qhn/to2aLnLTAk3y/9bHxqAEdqMvta1D4xpduN2K5h7KY07P+Iq8JhiL0WmynpLvlNDfVhQ5Bs1KCEuQ==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDck3rbKtDKyGEJwOFUUqi0VdoQhv8tDBu5rj+1HzSyAgIgHK0Fm/lgwJ6Ct3CZ62GzldgJWluvqqDaUhd+x6z1rDE="}]},"_from":".","_npmVersion":"1.2.18","_npmUser":{"name":"pghalliday","email":"pghalliday@gmail.com"},"maintainers":[{"name":"pghalliday","email":"pghalliday@gmail.com"}],"directories":{}},"0.1.2":{"name":"currency-market","description":"A synchronous implementation of a limit order based currency market","version":"0.1.2","homepage":"https://github.com/pghalliday/currency-market","author":{"name":"Peter Halliday","email":"pghalliday@gmail.com","url":"http://stuffpetedoes.blogspot.nl/"},"repository":{"type":"git","url":"git://github.com/pghalliday/currency-market.git"},"bugs":{"url":"https://github.com/pghalliday/currency-market/issues"},"licenses":[{"type":"MIT","url":"https://github.com/pghalliday/currency-market/blob/master/LICENSE-MIT"}],"main":"lib/src/","engines":{"node":">= 0.10.4"},"scripts":{"prepublish":"grunt","test":"grunt"},"dependencies":{"bigdecimal":"~0.6.1"},"devDependencies":{"chai":"~1.5.0","node-uuid":"~1.4.0","checklist":"0.0.6","grunt-cli":"~0.1.7","grunt":"~0.4.1","grunt-contrib-coffee":"~0.7.0","grunt-mocha-test":"~0.2.2","grunt-contrib-clean":"~0.4.1","sinon":"~1.6.0","sinon-chai":"~2.4.0","randgen":"0.0.2"},"keywords":["currency","trading","limit order","synchronous","market"],"readme":"currency-market\n===============\n\nA synchronous implementation of a limit order based currency market\n\n## Features\n\n- Supports an arbitrary list of currencies\n- Synchronously executes trades as orders are added\n- Emits events when changes are made to the market\n- Can export the state and initialise from an exported state\n\n## Installation\n\n```\nnpm install currency-market\n```\n\n## API\n\nAll functions and constructors complete synchronously and throw errors if they fail.\nEvents are made available for monitoring changes in the market.\n\n```javascript\nvar Market = require('currency-market').Market;\nvar Account = require('currency-market').Account;\nvar Amount = require('currency-market').Amount;\nvar Order = require('currency-market').Order;\n\n// instantiate a market\nvar market = new Market({\n  currencies: [\n    'EUR',\n    'USD',\n    'BTC'\n  ]\n});\n\n// register for events\nmarket.on('account', function(account) {\n  console.log('');\n  console.log('********************');\n  console.log('********************');\n  console.log('');\n  console.log('Account');\n  console.log('');\n  console.log('********************');\n  console.log('********************');\n  console.log('');\n  console.log(account);\n});\nmarket.on('deposit', function(deposit) {\n  console.log('');\n  console.log('********************');\n  console.log('********************');\n  console.log('');\n  console.log('Deposit');\n  console.log('');\n  console.log('********************');\n  console.log('********************');\n  console.log('');\n  console.log(deposit);\n});\nmarket.on('withdrawal', function(withdrawal) {\n  console.log('');\n  console.log('********************');\n  console.log('********************');\n  console.log('');\n  console.log('Withdrawal');\n  console.log('');\n  console.log('********************');\n  console.log('********************');\n  console.log('');\n  console.log(withdrawal);\n});\nmarket.on('order', function(order) {\n  console.log('');\n  console.log('********************');\n  console.log('********************');\n  console.log('');\n  console.log('Order');\n  console.log('');\n  console.log('********************');\n  console.log('********************');\n  console.log('');\n  console.log(order);\n});\nmarket.on('cancellation', function(cancellation) {\n  console.log('');\n  console.log('********************');\n  console.log('********************');\n  console.log('');\n  console.log('Cancellation');\n  console.log('');\n  console.log('********************');\n  console.log('********************');\n  console.log('');\n  console.log(cancellation);\n});\nmarket.on('trade', function(trade) {\n  console.log('');\n  console.log('********************');\n  console.log('********************');\n  console.log('');\n  console.log('Trade');\n  console.log('');\n  console.log('********************');\n  console.log('********************');\n  console.log('');\n  console.log(trade);\n});\n\n// add accounts\nmarket.register(new Account({\n  // All IDs are intended to be the transaction IDs and as such\n  // should be globally unique. If not unique then the lastTransaction\n  // field may be rendered meaningless preventing restoration from a \n  // saved transaction log.\n  // Additionally these IDs are used to key collections so strange behaviour\n  // may result if they are not unique\n  id: '100000',\n  // Although the timestamp is not used internally, it is required\n  // so that any functionality hanging off the events can replicate\n  // their time relative behaviour in case a Market has to be restored\n  // from a transaction log\n  timestamp: '1366758222',\n  currencies: [\n    'EUR',\n    'USD',\n    'BTC'\n  ]\n}));\nmarket.register(new Account({\n  id: '100001',\n  timestamp: '1366758223',\n  currencies: [\n    'EUR',\n    'USD',\n    'BTC'\n  ]\n}));\n\n// make deposits\nmarket.deposit({\n  id: '100002',\n  timestamp: '1366758224',\n  // Note that the acount field should be set to the ID of the account.\n  // This is one of the instances whre the transaction ID is used as a key\n  account: '100000',\n  currency: 'EUR',\n  amount: new Amount('5000')\n});\nmarket.deposit({\n  id: '100003',\n  timestamp: '1366758225',\n  account: '100001',\n  currency: 'BTC',\n  amount: new Amount('5000')\n});\n\n// make withdrawals\nmarket.withdraw({\n  id: '100004',\n  timestamp: '1366758226',\n  account: '100000',\n  currency: 'EUR',\n  amount: new Amount('1000')\n});\nmarket.withdraw({\n  id: '100005',\n  timestamp: '1366758227',\n  account: '100001',\n  currency: 'BTC',\n  amount: new Amount('1000')\n});\n\n// submit orders\nmarket.submit(new Order({\n  id: '100006',\n  timestamp: '1366758228',\n  account: '100000',\n  bidCurrency: 'BTC',\n  offerCurrency: 'EUR',\n  bidPrice: new Amount('2'),\n  bidAmount: new Amount('500')\n}));\nmarket.submit(new Order({\n  id: '100007',\n  timestamp: '1366758229',\n  account: '100000',\n  bidCurrency: 'BTC',\n  offerCurrency: 'EUR',\n  bidPrice: new Amount('1'),\n  bidAmount: new Amount('2000')\n}));\nmarket.submit(new Order({\n  id: '100008',\n  timestamp: '1366758230',\n  account: '100001',\n  bidCurrency: 'EUR',\n  offerCurrency: 'BTC',\n  offerPrice: new Amount('2'),\n  offerAmount: new Amount('250')\n}));\nmarket.submit(new Order({\n  id: '100009',\n  timestamp: '1366758231',\n  account: '100001',\n  bidCurrency: 'EUR',\n  offerCurrency: 'BTC',\n  offerPrice: new Amount('3'),\n  offerAmount: new Amount('3000')\n}));\n\n// cancel an order\nmarket.cancel({\n  id: '100010',\n  timestamp: '1366758232',\n  // The Order instance must exactly match the current state\n  // of the order being cancelled. This example will match \n  // because 250 BTC was already traded on this order. This is\n  // another instance where the transaction ID is used as a key\n  order: new Order({\n    id: '100006',\n    timestamp: '1366758228',\n    account: '100000',\n    bidCurrency: 'BTC',\n    offerCurrency: 'EUR',\n    bidPrice: new Amount('2'),\n    bidAmount: new Amount('250')\n  })\n});\n\n// list all the active accounts (keyed by id)\nconsole.log('');\nconsole.log('********************');\nconsole.log('********************');\nconsole.log('');\nconsole.log('Accounts');\nconsole.log('');\nconsole.log('********************');\nconsole.log('********************');\nconsole.log('');\nconsole.log(market.accounts);\n\n// list all the active order books \nconsole.log('');\nconsole.log('********************');\nconsole.log('********************');\nconsole.log('');\nconsole.log('Books');\nconsole.log('');\nconsole.log('********************');\nconsole.log('********************');\nconsole.log('');\nconsole.log(market.books);\n\n// Get the top of an order book\nconsole.log('');\nconsole.log('********************');\nconsole.log('********************');\nconsole.log('');\nconsole.log('Highest EUR bid');\nconsole.log('');\nconsole.log('********************');\nconsole.log('********************');\nconsole.log('');\nconsole.log(market.books['EUR']['BTC'].highest);\nconsole.log('');\nconsole.log('********************');\nconsole.log('********************');\nconsole.log('');\nconsole.log('Highest BTC bid');\nconsole.log('');\nconsole.log('********************');\nconsole.log('********************');\nconsole.log('');\nconsole.log(market.books['BTC']['EUR'].highest);\n\n// export the state (as an object that can be converted to JSON)\nvar state  = market.export();\n\n// JSON stringify the state\nvar json = JSON.stringify(state);\nconsole.log('');\nconsole.log('********************');\nconsole.log('********************');\nconsole.log('');\nconsole.log('Stringified market state');\nconsole.log('');\nconsole.log('********************');\nconsole.log('********************');\nconsole.log('');\nconsole.log(json);\n\n// initialise an identical market from the state\nvar anotherMarket = new Market({\n  state: JSON.parse(json)\n});\n\n// Retrieve the last transaction ID processed \nconsole.log('');\nconsole.log('********************');\nconsole.log('********************');\nconsole.log('');\nconsole.log('Last transaction ID from new Market: ' + anotherMarket.lastTransaction);\nconsole.log('');\nconsole.log('********************');\nconsole.log('********************');\n```\n\n## Roadmap\n\n- Performance tests\n  - Create performance test classes to see how performance changes as parameters change\n    ie: why does the random test perform less trades/second the more iterations there are when each iteration should be independent\n      - test parameter lookups? - cut them out of the timings!\n      - garbage collection?\n  - Create random BID/BID and OFFER/OFFER performance tests\n- List orders by account\n- List orders by book (in order)\n- Instant orders\n  - Fill or Kill limit orders\n  - Market orders\n- Pluggable commission schemes\n  - fixed rate\n  - calculated through callback\n- Pluggable rounding policies\n  - Amount factory required?\n  - Divide at last possible moment?\n- Protection against attacks?\n  - entering orders that satisfy each other\n  - entering tiny orders\n  - should this be in a another layer?\n\n## Contributing\n\nIn lieu of a formal styleguide, take care to maintain the existing coding style. Add unit tests for any new or changed functionality.\n\nThe CoffeeScript source is located in the `src/` directory and tests in the `test/` directory. Do not edit the contents of the `lib/` directory as this is compiled from the CoffeeScript source.\n\nBefore commiting run `npm test` to perform a clean compile of the source and run the tests. This ensures that everything commited is up to date and tested and allows people to `npm install` directly from the git repository (useful for integrating development branches, etc).\n\n## License\nCopyright (c) 2013 Peter Halliday  \nLicensed under the MIT license.","readmeFilename":"README.md","_id":"currency-market@0.1.2","dist":{"shasum":"042ec84a238aa833a7565826c110896a9993c3db","tarball":"https://registry.npmjs.org/currency-market/-/currency-market-0.1.2.tgz","integrity":"sha512-47QoQWz6xwHfeExDSgOy1W9E2cZH4wrSBpIcNlfUFd2G1nfjoyECy/u1nmYC8SIEgyuANNmGOhIovQJXW2vcsw==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIBpQZdocflgO+8I2584zHTg92pAf7fMAPRjcJKY/5LQDAiA5UR+cSqWSXsDXMuNoM+bOE1CtPpEfAMflz3ZRDTLmWA=="}]},"_from":".","_npmVersion":"1.2.18","_npmUser":{"name":"pghalliday","email":"pghalliday@gmail.com"},"maintainers":[{"name":"pghalliday","email":"pghalliday@gmail.com"}],"directories":{}},"0.2.0":{"name":"currency-market","description":"A synchronous implementation of a limit order based currency market","version":"0.2.0","homepage":"https://github.com/pghalliday/currency-market","author":{"name":"Peter Halliday","email":"pghalliday@gmail.com","url":"http://stuffpetedoes.blogspot.nl/"},"repository":{"type":"git","url":"git://github.com/pghalliday/currency-market.git"},"bugs":{"url":"https://github.com/pghalliday/currency-market/issues"},"licenses":[{"type":"MIT","url":"https://github.com/pghalliday/currency-market/blob/master/LICENSE-MIT"}],"main":"lib/src/","engines":{"node":">= 0.10.4"},"scripts":{"prepublish":"grunt","test":"grunt"},"dependencies":{},"devDependencies":{"chai":"~1.5.0","grunt-cli":"~0.1.7","grunt":"~0.4.1","grunt-contrib-coffee":"~0.7.0","grunt-mocha-test":"~0.2.2","grunt-contrib-clean":"~0.4.1","sinon":"~1.6.0","sinon-chai":"~2.4.0","randgen":"0.0.2","grunt-contrib-copy":"~0.4.1"},"keywords":["currency","trading","limit order","synchronous","market"],"readme":"currency-market\n===============\n\nA synchronous implementation of a limit order based currency market\n\n## Features\n\n- Supports an arbitrary list of currencies\n- Synchronously executes trades as orders are added\n- Emits events when changes are made to the market\n- Can export the state and initialise from an exported state\n\n## Installation\n\n```\nnpm install currency-market\n```\n\n## API\n\nAll functions and constructors complete synchronously and throw errors if they fail.\nEvents are made available for monitoring changes in the market.\n\n```javascript\nvar Market = require('currency-market').Market;\nvar Account = require('currency-market').Account;\nvar Amount = require('currency-market').Amount;\nvar Order = require('currency-market').Order;\n\n// instantiate a market\nvar market = new Market();\n\n// register for events\nmarket.on('deposit', function(deposit) {\n  console.log('');\n  console.log('********************');\n  console.log('********************');\n  console.log('');\n  console.log('Deposit');\n  console.log('');\n  console.log('********************');\n  console.log('********************');\n  console.log('');\n  console.log(deposit);\n});\nmarket.on('withdrawal', function(withdrawal) {\n  console.log('');\n  console.log('********************');\n  console.log('********************');\n  console.log('');\n  console.log('Withdrawal');\n  console.log('');\n  console.log('********************');\n  console.log('********************');\n  console.log('');\n  console.log(withdrawal);\n});\nmarket.on('order', function(order) {\n  console.log('');\n  console.log('********************');\n  console.log('********************');\n  console.log('');\n  console.log('Order');\n  console.log('');\n  console.log('********************');\n  console.log('********************');\n  console.log('');\n  console.log(order);\n});\nmarket.on('cancellation', function(cancellation) {\n  console.log('');\n  console.log('********************');\n  console.log('********************');\n  console.log('');\n  console.log('Cancellation');\n  console.log('');\n  console.log('********************');\n  console.log('********************');\n  console.log('');\n  console.log(cancellation);\n});\nmarket.on('trade', function(trade) {\n  console.log('');\n  console.log('********************');\n  console.log('********************');\n  console.log('');\n  console.log('Trade');\n  console.log('');\n  console.log('********************');\n  console.log('********************');\n  console.log('');\n  console.log(trade);\n});\n\n// make deposits\nmarket.deposit({\n  // All IDs are intended to be the transaction IDs and as such\n  // should be globally unique. If not unique then the lastTransaction\n  // field may be rendered meaningless preventing restoration from a \n  // saved transaction log.\n  // Additionally these IDs are used to key collections so strange behaviour\n  // may result if they are not unique\n  id: '100002',\n  // Although the timestamp is not used internally, it is required\n  // so that any functionality hanging off the events can replicate\n  // their time relative behaviour in case a Market has to be restored\n  // from a transaction log\n  timestamp: '1366758224',\n  // Note that the acount field should be set to the unique ID of the account.\n  // Accounts will be created and initialised on first reference\n  account: 'Peter',\n  currency: 'EUR',\n  amount: new Amount('5000')\n});\nmarket.deposit({\n  id: '100003',\n  timestamp: '1366758225',\n  account: 'Paul',\n  currency: 'BTC',\n  amount: new Amount('5000')\n});\n\n// make withdrawals\nmarket.withdraw({\n  id: '100004',\n  timestamp: '1366758226',\n  account: 'Peter',\n  currency: 'EUR',\n  amount: new Amount('1000')\n});\nmarket.withdraw({\n  id: '100005',\n  timestamp: '1366758227',\n  account: 'Paul',\n  currency: 'BTC',\n  amount: new Amount('1000')\n});\n\n// submit orders\nmarket.submit(new Order({\n  id: '100006',\n  timestamp: '1366758228',\n  account: 'Peter',\n  bidCurrency: 'BTC',\n  offerCurrency: 'EUR',\n  bidPrice: new Amount('2'),\n  bidAmount: new Amount('500')\n}));\nmarket.submit(new Order({\n  id: '100007',\n  timestamp: '1366758229',\n  account: 'Peter',\n  bidCurrency: 'BTC',\n  offerCurrency: 'EUR',\n  bidPrice: new Amount('1'),\n  bidAmount: new Amount('2000')\n}));\nmarket.submit(new Order({\n  id: '100008',\n  timestamp: '1366758230',\n  account: 'Paul',\n  bidCurrency: 'EUR',\n  offerCurrency: 'BTC',\n  offerPrice: new Amount('2'),\n  offerAmount: new Amount('250')\n}));\nmarket.submit(new Order({\n  id: '100009',\n  timestamp: '1366758231',\n  account: 'Paul',\n  bidCurrency: 'EUR',\n  offerCurrency: 'BTC',\n  offerPrice: new Amount('3'),\n  offerAmount: new Amount('3000')\n}));\n\n// cancel an order\nmarket.cancel({\n  id: '100010',\n  timestamp: '1366758232',\n  order: new Order({\n    id: '100006',\n    timestamp: '1366758228',\n    account: 'Peter',\n    bidCurrency: 'BTC',\n    offerCurrency: 'EUR',\n    bidPrice: new Amount('2'),\n    bidAmount: new Amount('250')\n  })\n});\n\n// Export an account as an object that can be converted to JSON\nconsole.log('');\nconsole.log('********************');\nconsole.log('********************');\nconsole.log('');\nconsole.log('Peter\\'s account');\nconsole.log('');\nconsole.log('********************');\nconsole.log('********************');\nconsole.log('');\nconsole.log(market.getAccount('Peter').export());\nconsole.log('');\nconsole.log('********************');\nconsole.log('********************');\nconsole.log('');\nconsole.log('Paul\\'s account');\nconsole.log('');\nconsole.log('********************');\nconsole.log('********************');\nconsole.log('');\nconsole.log(market.getAccount('Paul').export());\n\n// Export an order book as an array that can be converted to JSON\nconsole.log('');\nconsole.log('********************');\nconsole.log('********************');\nconsole.log('');\nconsole.log('EUR bids in order');\nconsole.log('');\nconsole.log('********************');\nconsole.log('********************');\nconsole.log('');\nconsole.log(market.getBook('EUR', 'BTC').export());\nconsole.log('');\nconsole.log('********************');\nconsole.log('********************');\nconsole.log('');\nconsole.log('BTC bids in order');\nconsole.log('');\nconsole.log('********************');\nconsole.log('********************');\nconsole.log('');\nconsole.log(market.getBook('BTC', 'EUR').export());\n\n// export a snapshot of the market as an object that can be converted to JSON\nvar snapshot  = market.export();\n\n// JSON stringify the snapshot\nvar json = JSON.stringify(snapshot);\nconsole.log('');\nconsole.log('********************');\nconsole.log('********************');\nconsole.log('');\nconsole.log('Stringified market snapshot');\nconsole.log('');\nconsole.log('********************');\nconsole.log('********************');\nconsole.log('');\nconsole.log(json);\n\n// initialise an identical market from the snapshot\nvar anotherMarket = new Market(JSON.parse(json));\n\n// Retrieve the last transaction ID processed \nconsole.log('');\nconsole.log('********************');\nconsole.log('********************');\nconsole.log('');\nconsole.log('Last transaction ID from new Market: ' + anotherMarket.lastTransaction);\nconsole.log('');\nconsole.log('********************');\nconsole.log('********************');\n```\n\n## Roadmap\n\n- Instant orders\n  - Market orders\n    - zero priced offers that are rejected if they cannot be completely filled by the market\n      - if a zero price is used then any remainder cannot be left on the book as it may cause a division by zero\n      - partial fills could be executed as long as the remainder is instantly cancelled\n  - Fill or Kill limit orders?\n    - will be tougher (less efficient) than market orders as an average price will have to be calculated?\n- Pluggable commission schemes\n  - fixed rate\n  - calculated through callback\n- Stop requiring currencies to be declared in advance?\n  - this could make it tough to add currencies later (but not impossible - maybe add an addCurrency function)\n- Pluggable rounding policies\n  - Amount factory required?\n  - currently we only round down debits and credits so as not to debit more funds than available\n    - current rounding is done to an arbitrary scale of 25\n- Protection against attacks?\n  - entering orders that satisfy each other\n  - entering tiny orders\n  - should this be in another layer?\n\n## Contributing\n\nIn lieu of a formal styleguide, take care to maintain the existing coding style. Add unit tests for any new or changed functionality.\n\nThe CoffeeScript source is located in the `src/` directory and tests in the `test/` directory. Do not edit the contents of the `lib/` directory as this is compiled from the CoffeeScript source.\n\nBefore commiting run `npm test` to perform a clean compile of the source and run the tests. This ensures that everything commited is up to date and tested and allows people to `npm install` directly from the git repository (useful for integrating development branches, etc).\n\n## License\nCopyright (c) 2013 Peter Halliday  \nLicensed under the MIT license.","readmeFilename":"README.md","_id":"currency-market@0.2.0","dist":{"shasum":"bcc097876480e6c96b2e45a5404f77fa0e618084","tarball":"https://registry.npmjs.org/currency-market/-/currency-market-0.2.0.tgz","integrity":"sha512-fol8TZgHyO/KFqpEZxoa4BnoWgnYCD95wncaUB1pWShnCSvNTGFBuJKzLb5FjsKPNXo9FVP0cTBfUSHW0z3npg==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIHzobBoPW+MF4or2CYD/shhBODDJnjSt5sGbRRqeKFKMAiEA7zUq+OxUHYk8XjDFb4jcBxu3MHij7JCCaEn3WHgVV1w="}]},"_from":".","_npmVersion":"1.2.18","_npmUser":{"name":"pghalliday","email":"pghalliday@gmail.com"},"maintainers":[{"name":"pghalliday","email":"pghalliday@gmail.com"}],"directories":{}},"0.3.0":{"name":"currency-market","description":"A synchronous implementation of a limit order based currency market","version":"0.3.0","homepage":"https://github.com/pghalliday/currency-market","author":{"name":"Peter Halliday","email":"pghalliday@gmail.com","url":"http://stuffpetedoes.blogspot.nl/"},"repository":{"type":"git","url":"git://github.com/pghalliday/currency-market.git"},"bugs":{"url":"https://github.com/pghalliday/currency-market/issues"},"licenses":[{"type":"MIT","url":"https://github.com/pghalliday/currency-market/blob/master/LICENSE-MIT"}],"main":"lib/src/","engines":{"node":">= 0.10.4"},"scripts":{"prepublish":"grunt","test":"grunt"},"dependencies":{},"devDependencies":{"chai":"~1.5.0","grunt-cli":"~0.1.7","grunt":"~0.4.1","grunt-contrib-coffee":"~0.7.0","grunt-mocha-test":"~0.2.2","grunt-contrib-clean":"~0.4.1","sinon":"~1.6.0","sinon-chai":"~2.4.0","randgen":"0.0.2","grunt-contrib-copy":"~0.4.1"},"keywords":["currency","trading","limit order","synchronous","market"],"readme":"currency-market\n===============\n\nA synchronous implementation of a limit order based currency market\n\n## Features\n\n- Supports an arbitrary list of currencies\n- Synchronously executes trades as orders are added\n- Emits events when changes are made to the market\n- Can export the state and initialise from an exported state\n- Supports pluggable commission schemes\n\n## Installation\n\n```\nnpm install currency-market\n```\n\n## API\n\nAll functions and constructors complete synchronously and throw errors if they fail.\nEvents are made available for monitoring changes in the market.\n\n```javascript\nvar Market = require('currency-market').Market;\nvar Account = require('currency-market').Account;\nvar Amount = require('currency-market').Amount;\nvar Order = require('currency-market').Order;\n\n\n// Define a commission rate of 0.5%\nvar COMMISSION_RATE = new Amount('0.005');\n\n// instantiate a market\nvar market = new Market({\n  commission: {\n    // The account ID of the account to recieve the commission\n    account: 'commission',\n    // A callback to use for calculating the commission amount to subtract from a deposit\n    // resulting from an order match\n    calculate: function(params) {\n      // The matched bid order corresponding to the deposit\n      var bid = params.bid;\n      // The amount to be deposited before commission (due to partial and better price\n      // matches this amount may be different to the bidAmount from the bid order)\n      var bidAmount = params.bidAmount;\n      // The timestamp of the order that triggered the match (not necessarily from the bid\n      // order, this is effectively the time that the trade was made)\n      var timestamp = params.timestamp;\n      // return the calculated commission amount to be subtracted from the deposit\n      // and deposited in the commission account (it's best to avoid divisions\n      // here in order to avoid rounding errors)\n      return bidAmount.multiply(COMMISSION_RATE);\n    }\n  }\n});\n\n// register for events\nmarket.on('deposit', function(deposit) {\n  console.log('');\n  console.log('********************');\n  console.log('********************');\n  console.log('');\n  console.log('Deposit');\n  console.log('');\n  console.log('********************');\n  console.log('********************');\n  console.log('');\n  console.log(deposit);\n});\nmarket.on('withdrawal', function(withdrawal) {\n  console.log('');\n  console.log('********************');\n  console.log('********************');\n  console.log('');\n  console.log('Withdrawal');\n  console.log('');\n  console.log('********************');\n  console.log('********************');\n  console.log('');\n  console.log(withdrawal);\n});\nmarket.on('order', function(order) {\n  console.log('');\n  console.log('********************');\n  console.log('********************');\n  console.log('');\n  console.log('Order');\n  console.log('');\n  console.log('********************');\n  console.log('********************');\n  console.log('');\n  console.log(order);\n});\nmarket.on('cancellation', function(cancellation) {\n  console.log('');\n  console.log('********************');\n  console.log('********************');\n  console.log('');\n  console.log('Cancellation');\n  console.log('');\n  console.log('********************');\n  console.log('********************');\n  console.log('');\n  console.log(cancellation);\n});\nmarket.on('trade', function(trade) {\n  console.log('');\n  console.log('********************');\n  console.log('********************');\n  console.log('');\n  console.log('Trade');\n  console.log('');\n  console.log('********************');\n  console.log('********************');\n  console.log('');\n  console.log(trade);\n});\n\n// make deposits\nmarket.deposit({\n  // All IDs are intended to be the transaction IDs and as such\n  // should be globally unique. If not unique then the lastTransaction\n  // field may be rendered meaningless preventing restoration from a \n  // saved transaction log.\n  // Additionally these IDs are used to key collections so strange behaviour\n  // may result if they are not unique\n  id: '100002',\n  // Although the timestamp is not used internally, it is required\n  // so that any functionality hanging off the events can replicate\n  // their time relative behaviour in case a Market has to be restored\n  // from a transaction log\n  timestamp: '1366758224',\n  // Note that the acount field should be set to the unique ID of the account.\n  // Accounts will be created and initialised on first reference\n  account: 'Peter',\n  currency: 'EUR',\n  amount: new Amount('5000')\n});\nmarket.deposit({\n  id: '100003',\n  timestamp: '1366758225',\n  account: 'Paul',\n  currency: 'BTC',\n  amount: new Amount('5000')\n});\n\n// make withdrawals\nmarket.withdraw({\n  id: '100004',\n  timestamp: '1366758226',\n  account: 'Peter',\n  currency: 'EUR',\n  amount: new Amount('1000')\n});\nmarket.withdraw({\n  id: '100005',\n  timestamp: '1366758227',\n  account: 'Paul',\n  currency: 'BTC',\n  amount: new Amount('1000')\n});\n\n// submit orders\nmarket.submit(new Order({\n  id: '100006',\n  timestamp: '1366758228',\n  account: 'Peter',\n  bidCurrency: 'BTC',\n  offerCurrency: 'EUR',\n  bidPrice: new Amount('2'),\n  bidAmount: new Amount('500')\n}));\nmarket.submit(new Order({\n  id: '100007',\n  timestamp: '1366758229',\n  account: 'Peter',\n  bidCurrency: 'BTC',\n  offerCurrency: 'EUR',\n  bidPrice: new Amount('1'),\n  bidAmount: new Amount('2000')\n}));\nmarket.submit(new Order({\n  id: '100008',\n  timestamp: '1366758230',\n  account: 'Paul',\n  bidCurrency: 'EUR',\n  offerCurrency: 'BTC',\n  offerPrice: new Amount('2'),\n  offerAmount: new Amount('250')\n}));\nmarket.submit(new Order({\n  id: '100009',\n  timestamp: '1366758231',\n  account: 'Paul',\n  bidCurrency: 'EUR',\n  offerCurrency: 'BTC',\n  offerPrice: new Amount('3'),\n  offerAmount: new Amount('3000')\n}));\n\n// cancel an order\nmarket.cancel({\n  id: '100010',\n  timestamp: '1366758232',\n  order: new Order({\n    id: '100006',\n    timestamp: '1366758228',\n    account: 'Peter',\n    bidCurrency: 'BTC',\n    offerCurrency: 'EUR',\n    bidPrice: new Amount('2'),\n    bidAmount: new Amount('250')\n  })\n});\n\n// Export an account as an object that can be converted to JSON\nconsole.log('');\nconsole.log('********************');\nconsole.log('********************');\nconsole.log('');\nconsole.log('Peter\\'s account');\nconsole.log('');\nconsole.log('********************');\nconsole.log('********************');\nconsole.log('');\nconsole.log(market.getAccount('Peter').export());\nconsole.log('');\nconsole.log('********************');\nconsole.log('********************');\nconsole.log('');\nconsole.log('Paul\\'s account');\nconsole.log('');\nconsole.log('********************');\nconsole.log('********************');\nconsole.log('');\nconsole.log(market.getAccount('Paul').export());\nconsole.log('');\nconsole.log('********************');\nconsole.log('********************');\nconsole.log('');\nconsole.log('Commission account');\nconsole.log('');\nconsole.log('********************');\nconsole.log('********************');\nconsole.log('');\nconsole.log(market.getAccount('commission').export());\n\n// Export an order book as an array that can be converted to JSON\nconsole.log('');\nconsole.log('********************');\nconsole.log('********************');\nconsole.log('');\nconsole.log('EUR bids in order');\nconsole.log('');\nconsole.log('********************');\nconsole.log('********************');\nconsole.log('');\nconsole.log(market.getBook('EUR', 'BTC').export());\nconsole.log('');\nconsole.log('********************');\nconsole.log('********************');\nconsole.log('');\nconsole.log('BTC bids in order');\nconsole.log('');\nconsole.log('********************');\nconsole.log('********************');\nconsole.log('');\nconsole.log(market.getBook('BTC', 'EUR').export());\n\n// export a snapshot of the market as an object that can be converted to JSON\nvar snapshot = market.export();\n\n// JSON stringify the snapshot\nvar json = JSON.stringify(snapshot);\nconsole.log('');\nconsole.log('********************');\nconsole.log('********************');\nconsole.log('');\nconsole.log('Stringified market snapshot');\nconsole.log('');\nconsole.log('********************');\nconsole.log('********************');\nconsole.log('');\nconsole.log(json);\n\n// initialise an identical market from the snapshot\nvar anotherMarket = new Market();\nanotherMarket.import(JSON.parse(json));\n\n// Retrieve the last transaction ID processed \nconsole.log('');\nconsole.log('********************');\nconsole.log('********************');\nconsole.log('');\nconsole.log('Last transaction ID from new Market: ' + anotherMarket.lastTransaction);\nconsole.log('');\nconsole.log('********************');\nconsole.log('********************');\n```\n\n## Roadmap\n\n- Instant orders\n  - Market orders\n    - zero priced offers that are rejected if they cannot be completely filled by the market\n      - if a zero price is used then any remainder cannot be left on the book as it may cause a division by zero\n      - partial fills could be executed as long as the remainder is instantly cancelled\n  - Fill or Kill limit orders?\n    - will be tougher (less efficient) than market orders as an average price will have to be calculated?\n- Pluggable rounding policies\n  - Amount factory required?\n  - currently we only round down debits and credits so as not to debit more funds than available\n    - current rounding is done to an arbitrary scale of 25\n- Separate transaction IDs and sequence IDs\n  - Use sequence numbers instead of transaction IDs so the engine knows that it hasn't missed anything?\n  - Use both sequence numbers and transaction IDs?\n    - transaction IDs provide replayability\n      - have to be unique forever (uuid?)\n    - sequence numbers provide integrity checking\n      - may get unweildy if required to be unique forever and could loop instead\n- Protection against attacks?\n  - entering orders that satisfy each other\n  - entering tiny orders\n  - should this be in another layer?\n\n## Contributing\n\nIn lieu of a formal styleguide, take care to maintain the existing coding style. Add unit tests for any new or changed functionality.\n\nThe CoffeeScript source is located in the `src/` directory and tests in the `test/` directory. Do not edit the contents of the `lib/` directory as this is compiled from the CoffeeScript source.\n\nBefore commiting run `npm test` to perform a clean compile of the source and run the tests. This ensures that everything commited is up to date and tested and allows people to `npm install` directly from the git repository (useful for integrating development branches, etc).\n\n## License\nCopyright (c) 2013 Peter Halliday  \nLicensed under the MIT license.","readmeFilename":"README.md","_id":"currency-market@0.3.0","dist":{"shasum":"ae4a2ee615861d9c3f97812ca752e506654f3b2e","tarball":"https://registry.npmjs.org/currency-market/-/currency-market-0.3.0.tgz","integrity":"sha512-tB1oDgXcF4B761ChfLNnIP/pz8/KP3Uo7+HCGrUjY60tcBbnMqDvC6GA/r+5YODppELohrqpFLSJ24G33/ACfA==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCzAwnN8k6um50bnECnwDbxAcenNbVM0zeIJ/Cxdsp4wwIhAOIKPwiyXJqfk8sk7HvqgoGLfR3MZTj4LO3HyLNbfQr0"}]},"_from":".","_npmVersion":"1.2.18","_npmUser":{"name":"pghalliday","email":"pghalliday@gmail.com"},"maintainers":[{"name":"pghalliday","email":"pghalliday@gmail.com"}],"directories":{}},"0.3.1":{"name":"currency-market","description":"A synchronous implementation of a limit order based currency market","version":"0.3.1","homepage":"https://github.com/pghalliday/currency-market","author":{"name":"Peter Halliday","email":"pghalliday@gmail.com","url":"http://stuffpetedoes.blogspot.nl/"},"repository":{"type":"git","url":"git://github.com/pghalliday/currency-market.git"},"bugs":{"url":"https://github.com/pghalliday/currency-market/issues"},"licenses":[{"type":"MIT","url":"https://github.com/pghalliday/currency-market/blob/master/LICENSE-MIT"}],"main":"lib/src/","engines":{"node":">= 0.10.4"},"scripts":{"prepublish":"grunt","test":"grunt","blanket":{"pattern":"/src/"},"travis-cov":{"threshold":100}},"dependencies":{},"devDependencies":{"chai":"~1.5.0","grunt-cli":"~0.1.7","grunt":"~0.4.1","grunt-contrib-coffee":"~0.7.0","grunt-mocha-test":"~0.3.4","grunt-contrib-clean":"~0.4.1","sinon":"~1.6.0","sinon-chai":"~2.4.0","randgen":"0.0.2","grunt-contrib-copy":"~0.4.1","blanket":"~1.1.4","travis-cov":"~0.2.4"},"keywords":["currency","trading","limit order","synchronous","market"],"readme":"currency-market\n===============\n\n[![Build Status](https://travis-ci.org/pghalliday/currency-market.png)](https://travis-ci.org/pghalliday/currency-market)\n\nA synchronous implementation of a limit order based currency market\n\n## Features\n\n- Supports an arbitrary list of currencies\n- Synchronously executes trades as orders are added\n- Emits events when changes are made to the market\n- Can export the state and initialise from an exported state\n- Supports pluggable commission schemes\n\n## Installation\n\n```\nnpm install currency-market\n```\n\n## API\n\nAll functions and constructors complete synchronously and throw errors if they fail.\nEvents are made available for monitoring changes in the market.\n\n```javascript\nvar Market = require('currency-market').Market;\nvar Account = require('currency-market').Account;\nvar Amount = require('currency-market').Amount;\nvar Order = require('currency-market').Order;\n\n\n// Define a commission rate of 0.5%\nvar COMMISSION_RATE = new Amount('0.005');\n\n// instantiate a market\nvar market = new Market({\n  commission: {\n    // The account ID of the account to receive the commission\n    account: 'commission',\n    // A callback to use for calculating the commission amount to subtract from a deposit\n    // resulting from an order match\n    calculate: function(params) {\n      // The matched bid order corresponding to the deposit\n      var bid = params.bid;\n      // The amount to be deposited before commission (due to partial and better price\n      // matches this amount may be different to the bidAmount from the bid order)\n      var bidAmount = params.bidAmount;\n      // The timestamp of the order that triggered the match (not necessarily from the bid\n      // order, this is effectively the time that the trade was made)\n      var timestamp = params.timestamp;\n      // return the calculated commission amount to be subtracted from the deposit\n      // and deposited in the commission account (it's best to avoid divisions\n      // here in order to avoid rounding errors)\n      return bidAmount.multiply(COMMISSION_RATE);\n    }\n  }\n});\n\n// register for events\nmarket.on('deposit', function(deposit) {\n  console.log('');\n  console.log('********************');\n  console.log('********************');\n  console.log('');\n  console.log('Deposit');\n  console.log('');\n  console.log('********************');\n  console.log('********************');\n  console.log('');\n  console.log(deposit);\n});\nmarket.on('withdrawal', function(withdrawal) {\n  console.log('');\n  console.log('********************');\n  console.log('********************');\n  console.log('');\n  console.log('Withdrawal');\n  console.log('');\n  console.log('********************');\n  console.log('********************');\n  console.log('');\n  console.log(withdrawal);\n});\nmarket.on('order', function(order) {\n  console.log('');\n  console.log('********************');\n  console.log('********************');\n  console.log('');\n  console.log('Order');\n  console.log('');\n  console.log('********************');\n  console.log('********************');\n  console.log('');\n  console.log(order);\n});\nmarket.on('cancellation', function(cancellation) {\n  console.log('');\n  console.log('********************');\n  console.log('********************');\n  console.log('');\n  console.log('Cancellation');\n  console.log('');\n  console.log('********************');\n  console.log('********************');\n  console.log('');\n  console.log(cancellation);\n});\nmarket.on('trade', function(trade) {\n  console.log('');\n  console.log('********************');\n  console.log('********************');\n  console.log('');\n  console.log('Trade');\n  console.log('');\n  console.log('********************');\n  console.log('********************');\n  console.log('');\n  console.log(trade);\n});\n\n// make deposits\nmarket.deposit({\n  // All IDs are intended to be the transaction IDs and as such\n  // should be globally unique. If not unique then the lastTransaction\n  // field may be rendered meaningless preventing restoration from a \n  // saved transaction log.\n  // Additionally these IDs are used to key collections so strange behaviour\n  // may result if they are not unique\n  id: '100002',\n  // Although the timestamp is not used internally, it is required\n  // so that any functionality hanging off the events can replicate\n  // their time relative behaviour in case a Market has to be restored\n  // from a transaction log\n  timestamp: '1366758224',\n  // Note that the acount field should be set to the unique ID of the account.\n  // Accounts will be created and initialised on first reference\n  account: 'Peter',\n  currency: 'EUR',\n  amount: new Amount('5000')\n});\nmarket.deposit({\n  id: '100003',\n  timestamp: '1366758225',\n  account: 'Paul',\n  currency: 'BTC',\n  amount: new Amount('5000')\n});\n\n// make withdrawals\nmarket.withdraw({\n  id: '100004',\n  timestamp: '1366758226',\n  account: 'Peter',\n  currency: 'EUR',\n  amount: new Amount('1000')\n});\nmarket.withdraw({\n  id: '100005',\n  timestamp: '1366758227',\n  account: 'Paul',\n  currency: 'BTC',\n  amount: new Amount('1000')\n});\n\n// submit orders\nmarket.submit(new Order({\n  id: '100006',\n  timestamp: '1366758228',\n  account: 'Peter',\n  bidCurrency: 'BTC',\n  offerCurrency: 'EUR',\n  bidPrice: new Amount('2'),\n  bidAmount: new Amount('500')\n}));\nmarket.submit(new Order({\n  id: '100007',\n  timestamp: '1366758229',\n  account: 'Peter',\n  bidCurrency: 'BTC',\n  offerCurrency: 'EUR',\n  bidPrice: new Amount('1'),\n  bidAmount: new Amount('2000')\n}));\nmarket.submit(new Order({\n  id: '100008',\n  timestamp: '1366758230',\n  account: 'Paul',\n  bidCurrency: 'EUR',\n  offerCurrency: 'BTC',\n  offerPrice: new Amount('2'),\n  offerAmount: new Amount('250')\n}));\nmarket.submit(new Order({\n  id: '100009',\n  timestamp: '1366758231',\n  account: 'Paul',\n  bidCurrency: 'EUR',\n  offerCurrency: 'BTC',\n  offerPrice: new Amount('3'),\n  offerAmount: new Amount('3000')\n}));\n\n// cancel an order\nmarket.cancel({\n  id: '100010',\n  timestamp: '1366758232',\n  order: new Order({\n    id: '100006',\n    timestamp: '1366758228',\n    account: 'Peter',\n    bidCurrency: 'BTC',\n    offerCurrency: 'EUR',\n    bidPrice: new Amount('2'),\n    bidAmount: new Amount('250')\n  })\n});\n\n// Export an account as an object that can be converted to JSON\nconsole.log('');\nconsole.log('********************');\nconsole.log('********************');\nconsole.log('');\nconsole.log('Peter\\'s account');\nconsole.log('');\nconsole.log('********************');\nconsole.log('********************');\nconsole.log('');\nconsole.log(market.getAccount('Peter').export());\nconsole.log('');\nconsole.log('********************');\nconsole.log('********************');\nconsole.log('');\nconsole.log('Paul\\'s account');\nconsole.log('');\nconsole.log('********************');\nconsole.log('********************');\nconsole.log('');\nconsole.log(market.getAccount('Paul').export());\nconsole.log('');\nconsole.log('********************');\nconsole.log('********************');\nconsole.log('');\nconsole.log('Commission account');\nconsole.log('');\nconsole.log('********************');\nconsole.log('********************');\nconsole.log('');\nconsole.log(market.getAccount('commission').export());\n\n// Export an order book as an array that can be converted to JSON\nconsole.log('');\nconsole.log('********************');\nconsole.log('********************');\nconsole.log('');\nconsole.log('EUR bids in order');\nconsole.log('');\nconsole.log('********************');\nconsole.log('********************');\nconsole.log('');\nconsole.log(market.getBook('EUR', 'BTC').export());\nconsole.log('');\nconsole.log('********************');\nconsole.log('********************');\nconsole.log('');\nconsole.log('BTC bids in order');\nconsole.log('');\nconsole.log('********************');\nconsole.log('********************');\nconsole.log('');\nconsole.log(market.getBook('BTC', 'EUR').export());\n\n// export a snapshot of the market as an object that can be converted to JSON\nvar snapshot = market.export();\n\n// JSON stringify the snapshot\nvar json = JSON.stringify(snapshot);\nconsole.log('');\nconsole.log('********************');\nconsole.log('********************');\nconsole.log('');\nconsole.log('Stringified market snapshot');\nconsole.log('');\nconsole.log('********************');\nconsole.log('********************');\nconsole.log('');\nconsole.log(json);\n\n// initialise an identical market from the snapshot\nvar anotherMarket = new Market();\nanotherMarket.import(JSON.parse(json));\n\n// Retrieve the last transaction ID processed \nconsole.log('');\nconsole.log('********************');\nconsole.log('********************');\nconsole.log('');\nconsole.log('Last transaction ID from new Market: ' + anotherMarket.lastTransaction);\nconsole.log('');\nconsole.log('********************');\nconsole.log('********************');\n```\n\n## Roadmap\n\n- Instant orders\n  - Market orders\n    - zero priced offers that are rejected if they cannot be completely filled by the market\n      - if a zero price is used then any remainder cannot be left on the book as it may cause a division by zero\n      - partial fills could be executed as long as the remainder is instantly cancelled\n  - Fill or Kill limit orders?\n    - will be tougher (less efficient) than market orders as an average price will have to be calculated?\n- Pluggable rounding policies\n  - Amount factory required?\n  - currently we only round down debits and credits so as not to debit more funds than available\n    - current rounding is done to an arbitrary scale of 25\n- Separate transaction IDs and sequence IDs\n  - Use sequence numbers instead of transaction IDs so the engine knows that it hasn't missed anything?\n  - Use both sequence numbers and transaction IDs?\n    - transaction IDs provide replayability\n      - have to be unique forever (uuid?)\n    - sequence numbers provide integrity checking\n      - may get unweildy if required to be unique forever and could loop instead\n      - where are sequence numbers assigned?\n        - This implies a state somewhere and a centralised component (bottleneck?)\n- Protection against attacks?\n  - entering orders that satisfy each other\n  - entering tiny orders\n  - should this be in another layer?\n\n## Contributing\n\nIn lieu of a formal styleguide, take care to maintain the existing coding style. Add unit tests for any new or changed functionality.\n\nThe CoffeeScript source is located in the `src/` directory and tests in the `test/` directory. Do not edit the contents of the `lib/` directory as this is compiled from the CoffeeScript source.\n\nBefore commiting run `npm test` to perform a clean compile of the source and run the tests. This ensures that everything commited is up to date and tested and allows people to `npm install` directly from the git repository (useful for integrating development branches, etc).\n\n## License\nCopyright (c) 2013 Peter Halliday  \nLicensed under the MIT license.","readmeFilename":"README.md","_id":"currency-market@0.3.1","dist":{"shasum":"ff9a151e04f134221d4ec4808c0499d7acc664eb","tarball":"https://registry.npmjs.org/currency-market/-/currency-market-0.3.1.tgz","integrity":"sha512-TDtZjib54oCdOJcgR4LEcvGAT8fscofueJOeF3/Cl3Um/rRQN8HmeuX5FfW+yFLxg291PbfzVCJYGGYrenmCUQ==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDcBldhe3tc4KQV+udyOcQMMnE2vTrKFtFxt/4V/vueIQIgeTyTl2xapfvrH5yhwkmdDQPWk0Gbca9gJEl8blbJ/EU="}]},"_from":".","_npmVersion":"1.2.18","_npmUser":{"name":"pghalliday","email":"pghalliday@gmail.com"},"maintainers":[{"name":"pghalliday","email":"pghalliday@gmail.com"}],"directories":{}},"0.4.0":{"name":"currency-market","description":"A synchronous implementation of a limit order based currency market","version":"0.4.0","homepage":"https://github.com/pghalliday/currency-market","author":{"name":"Peter Halliday","email":"pghalliday@gmail.com","url":"http://stuffpetedoes.blogspot.nl/"},"repository":{"type":"git","url":"git://github.com/pghalliday/currency-market.git"},"bugs":{"url":"https://github.com/pghalliday/currency-market/issues"},"licenses":[{"type":"MIT","url":"https://github.com/pghalliday/currency-market/blob/master/LICENSE-MIT"}],"main":"lib/src/","engines":{"node":">= 0.10.4"},"scripts":{"prepublish":"grunt build","test":"grunt","perf":"grunt perf","travis-cov":{"threshold":100}},"dependencies":{},"devDependencies":{"chai":"~1.7.1","grunt-cli":"~0.1.9","grunt":"~0.4.1","grunt-contrib-coffee":"~0.7.0","grunt-mocha-test":"~0.5.0","grunt-contrib-clean":"~0.4.1","sinon":"~1.7.3","sinon-chai":"~2.4.0","randgen":"~0.0.4","grunt-contrib-copy":"~0.4.1","grunt-blanket":"~0.0.8","travis-cov":"~0.2.4"},"keywords":["currency","trading","limit order","synchronous","market"],"readme":"currency-market\n===============\n\n[![Build Status](https://travis-ci.org/pghalliday/currency-market.png)](https://travis-ci.org/pghalliday/currency-market)\n[![Dependency Status](https://gemnasium.com/pghalliday/currency-market.png)](https://gemnasium.com/pghalliday/currency-market)\n\nA synchronous implementation of a limit order based currency market\n\n## Installation\n\n```\nnpm install currency-market\n```\n\n## Usage\n\nThe `currency-market` package is intended to be used by a system of components that need to be synchronized. Those components are\n\n- A number of front ends that generate operations and allow the state of the market to be queried\n- An operation hub that accepts the operations and ensures they are submitted to order matching engines in a reproducible order\n- A number of identical order matching engines that process the operations and calculate the new state of the market for each one\n- A delta hub that receives the market state deltas and distributes them to the front ends\n\nOn intialization\n\n- Engines will be constructed (perhaps from a previous engine state) and when requested will send the state to the delta hub\n\n```Javascript\nvar Engine = require('currency-market').Engine;\nvar Amount = require('currency-market').Amount;\n\nvar COMMISSION_RATE = new Amount('0.001');\nvar COMMISSION_REFERENCE = '0.1%';\n\nvar engine = new Engine({\n  commission: {\n    account: 'commission'\n    calculate: function(params) {\n      return {\n        amount: params.amount.multiply(COMMISSION_RATE),\n        reference: COMMISSION_REFERENCE\n      };\n    }\n  },\n  json: previousEngineState  \n});\n\n...\n\nsendStateToDeltaHub(JSON.stringify(engine));\n```\n\n- The delta hub will request the state from an engine and forward that to the front ends when they start up\n\n```Javascript\nvar State = require('currency-market').State;\n\ngetStateFromEngine(function(receivedEngineState){\n  var state = new State({\n    commission: {\n      account: 'commission'\n    },\n    json: receivedEngineState  \n  });\n});\n\n...\n\nsendStateToFrontEnd(JSON.stringify(state));\n```\n\n- Front ends will request the state and then construct a state from the JSON state they receive from the delta hub\n\n```Javascript\nvar State = require('currency-market').State;\n\ngetStateFromDeltaHub(function(receivedState){\n  var state = new State({\n    commission: {\n      account: 'commission'\n    },\n    json: receivedState\n  });\n});\n```\n\nThen the life cycle of an operation is as follows\n\n- A front end constructs an operation and sends it to an operation hub\n\n```Javascript\nvar Operation = require('currency-market').Operation;\nvar Amount = require('currency-market').Amount;\n\nvar operation = new Operation({\n  reference: '550e8400-e29b-41d4-a716-446655440000',\n  account: 'Peter',\n  deposit: {\n    currency: 'EUR',\n    amount: new Amount '500'\n  }\n});\n\nsendToOperationHub(JSON.stringify(operation));\n```\n\n- The operation hub receives the operation, accepts it with a seqence number and timestamp and forwards it to the engine instances\n\n```Javascript\nvar Operation = require('currency-market').Operation;\n\nvar operation = new Operation({\n  json: receivedJSON  \n});\n\noperation.accept({\n  sequence: 654852,\n  timestamp: 1371737390976\n});\n\nsendToEngines(JSON.stringify(operation));\n```\n\n- The engines receive the operation, process it and send market state deltas to the delta hub\n\n```Javascript\nvar Operation = require('currency-market').Operation;\n\nvar operation = new Operation({\n  json: receivedJSON  \n});\n\ndelta = engine.apply(operation);\n\nsendToDeltaHub(JSON.stringify(delta));\n```\n\n- The delta hub receives the deltas, processes the first of each one it receives to update its own state and sends that delta on to the front ends\n\n```Javascript\nvar Delta = require('currency-market').Delta;\n\nvar delta = new Delta({\n  json: receivedJSON  \n});\n\nstate.apply(delta);\n\nsendToFrontEnds(JSON.stringify(delta));\n```\n\n- The front ends receive the deltas and apply them to their own state so that they can respond to queries with the new information\n\n```Javascript\nvar Delta = require('currency-market').Delta;\n\nvar delta = new Delta({\n  json: receivedJSON  \n});\n\nstate.apply(delta);\n\nvar funds = state.getAccount('Peter').getBalance('EUR').funds\n```\n\n## API\n\nAll functions complete synchronously and throw errors if they fail.\n\n### `Amount`\n\n`Amount` handles large numerical arithmetic accurately (unlike the built in Javascript number implementation). It is used for all amount and price values and is provided as a utility for applications to apply the same arimthmetic functionality in their own contexts.\n\n`Amount` instances are immutable.\n\nDivisions are carried out to an arbitrary precision of 25 decimal points.\n\n``` Javascript\nvar Amount = require('currency-market').Amount;\n\n// Always initialise from a string representation of a number\nvar amount1000 = new Amount('1000');\nvar amount200 = new Amount('200');\n\n// multiply 2 amounts\nvar amount200000 = amount1000.multiply(amount200);\n\n// add 2 amounts\nvar amount1200 = amount1000.add(amount200);\n\n// subtract 2 amounts\nvar amount800 = amount1000.subtract(amount200);\n\n// divide 2 amounts\nvar amountPoint2 = amount200.divide(amount1000);\n\n// Return the string representation of an amount\nvar str1000 = amount1000.toString();\n\n// Compare 2 values\namount1000.compareTo(amount200) > 0;\namount200.compareTo(amount1000) < 0;\namount200.compareTo(amount200) == 0;\n\n// 2 Identity constants are defined\nvar zero = Amount.ZERO;\nvar one = Amount.ONE;\n```\n\n### `Engine`\n\n```javascript\nvar Engine = require('currency-market').Engine;\n```\n\n`Engine` instances accept operations and return deltas that can be applied to simplified `State` instances.\n\n#### Constructor\n\n```javascript\n// Define a commission rate of 0.5%\nvar COMMISSION_RATE = new Amount('0.005');\n\n// instantiate an engine\nvar engine = new engine({\n  // Optionally specify how commission should be applied to credits resulting from trades.\n  // If this is not specified then no commission will be charged\n  commission: {\n    // The ID of the account to receive the commission\n    account: 'commission',\n    // The callback to use for calculating the commission amount to subtract from a credit\n    // resulting from a trade\n    calculate: function(params) {\n      // A timestamp for the trade being executed\n      var timestamp = params.timestamp;\n      // The ID of the account that is being credited\n      var account = params.account;\n      // The currency of the credited amount\n      var currency = params.currency;\n      // The amount that is being credited as an Amount instance\n      var amount = params.amount;\n\n      // Return an object containing the amount of commission to deduct as an Amount\n      // instance and a reference for the commission rate/type being charged\n      //\n      // Note that it's best to avoid divisions when calculating commissions so as\n      // to avoid rounding errors. Also, as the reference is intended be transmitted along\n      // with market deltas, it should be possible to convert it losslessly to and from JSON\n      return {\n        amount: amount.multiply(COMMISSION_RATE),\n        reference: COMMISSION_RATE + '%'\n      };\n    }\n  }\n});\n```\n\n#### `apply` method\n\nThe `apply` method applies operations and returns the resulting deltas.\n\nOperations and deltas can be converted losslessly to and from JSON for transmission.\n\nIf an operation fails for any reason (eg. not enough funds) then an error will be thrown.\n\nOnly operations that have been accepted using the `Operation.accept` method can be applied to an `Engine` instance.\n\n```Javascript\ntry {\n  var delta  = engine.apply(new Operation({\n    // Operation parameters\n    ...\n  }));\n} catch(error) {\n  // Possible errors will include invalid parameters or insufficient funds to complete the operation\n  ...\n}\n```\n\n#### `JSON.stringify`\n\nEngines can be converted to and from JSON\n\n```Javascript\nvar json = JSON.stringify(engine);\nvar engine = new Engine({\n  commission: {\n    account: 'commission',\n    calculate: function(params) {\n      return {\n        amount: amount.multiply(COMMISSION_RATE),\n        reference: COMMISSION_RATE + '%'\n      };\n    }\n  },\n  json: json\n});\n```\n\n### `Delta`\n\n```javascript\nvar Delta = require('currency-market').Delta;\n```\n\n`Delta` instances are returned by `Engine` instances after successfully applying operations. They can be converted to JSON, transmitted, reconstructed from JSON and applied to `State` instances.\n\nAll deltas have the following properties\n\n```Javascript\n// The delta sequence number. These will be generated consecutively by the engine\n// for successful operations. As such they will not be synchronized with operation sequence\n// numbers due to the possibility of operations throwing errors\nvar sequence = delta.sequence;\n\n// The operation instance as supplied to the `apply` method\nvar operation = delta.operation;\n\n// Additional state change information in a format specific to the operation type\nvar result = delta.result;\n\n```\n\n#### `JSON.stringify`\n\nDeltas can be converted to and from JSON\n\n```Javascript\nvar json = JSON.stringify(delta);\nvar delta = new Delta({\n  json: json\n});\n```\n\n### `Operation`\n\n```javascript\nvar Operation = require('currency-market').Operation;\n```\n\n`Operation` instances are submitted to `Engine` instances to apply operations. They can be converted to JSON, transmitted and reconstructed from JSON\n\nAll operations follow this pattern\n\n```Javascript\nvar operation = new Operation({\n  // Application specified reference that is returned untouched with the operation details included in the delta.\n  // Care should be taken to ensure that this too can be converted to and from JSON\n  reference: '550e8400-e29b-41d4-a716-446655440000',\n  // The ID of the account submitting the operation\n  account: 'Peter',\n  // The operation details, the name of this property will determine the type of the operation\n  // and what additional fields need to be supplied\n  operationType: {\n    // Operation parameters\n    ...\n  }\n});\n```\n\n#### `accept` method\n\nOperations must be accepted before they can be applied to an `Engine` instance to ensure they are associated with a sequence number and a timestamp\n\n```Javascript\noperation.accept({\n  // The operation sequence number. These must be consecutive for consecutive operations\n  sequence: 123456,\n  // The timestamp for the operation as a Unix time since epoch in milliseconds\n  timestamp: 1371737390976\n});\n```\n\n#### `deposit` operation\n\nDeposit funds into an account\n\n```Javascript\nvar operation  = new Operation({\n  reference: '550e8400-e29b-41d4-a716-446655440000',\n  account: 'Peter',\n  // deposit 1000 Euros to account ID 'Peter'\n  deposit: {\n    currency: 'EUR',\n    amount: new Amount('1000')\n  }\n});\n\n// On successful application the `delta.result` will have the following fields\n\n// The new level of funds in the deposited currency as an `Amount` instance\nvar funds = delta.result.funds\n```\n\n#### `withdraw` operation\n\nWithdraw funds from an account\n\n```Javascript\nvar operation  = new Operation({\n  reference: '550e8400-e29b-41d4-a716-446655440000',\n  account: 'Peter',\n  // withdraw 1000 Euros from account ID 'Peter'\n  withdraw: {\n    currency: 'EUR',\n    amount: new Amount('1000')\n  }\n});\n\n// On successful application the `delta.result` will have the following fields\n\n// The new level of funds in the deposited currency as an `Amount` instance\nvar funds = delta.result.funds\n```\n\n#### `submit` operation\n\nSubmit orders to the market. Both bid and offer orders can be submitted and follow this pattern\n\n```Javascript\nvar operation  = new Operation({\n  reference: '550e8400-e29b-41d4-a716-446655440000',\n  account: 'Peter',\n  // Place a bid order for 10 BTC offering 100 Euros per BTC\n  submit: {\n    // order parameters\n    ...\n  }\n});\n\n// On successful application the `delta.result` will have the following fields\n\n// The new level of locked funds in the order's offer currency\nvar lockedFunds = delta.result.lockedFunds\n\n// Note that only one of `nextHigherOrderSequence` or `trades` will be set\n\n// If the order is not at the top of the order book then the sequence number\n// of the next order above it is returned. This is a hint to optimize the\n// insertion of the order into a `State` instance\nvar nextHigherOrderSequence = delta.result.nextHigherOrderSequence;\n\n// If the order was inserted at the top of the order book then an array of trades\n// will be returned. This array will still be set, but will be empty, if no actual \n// trades were made\n//\n// Note that the price at which any trade was executed will be given by the bid or\n// offer price associated with the `right` order and that the volume traded in each\n// currency is most easily referenced by the debit amounts associated with the `left`\n// and `right` accounts in their respective order's offer currencies\nvar trades = delta.result.trades;\n\n  // `left` gives the changes to be applied to the order that was submitted and the\n  // account that submitted it\n  var left = trades[0].left;\n\n    // Only one of `left` or `right` will have a remainder and this\n    // signals the amount of the order that has not yet been executed.\n    // When no remainder is specified it signals that the order was\n    // completely executed. It is possible that neither `left` nor `right`\n    // will have a remainder if they completely satisfy each other\n    var remainder = left.remainder;\n\n      // The remaining bidAmount on the order\n      var bidAmount = remainder.bidAmount;\n\n      // The remaining offerAmount on the order\n      var offerAmount = remainder.offerAmount;\n\n    // The transaction fields signal by how much the account balances have changed\n    // and how much commission was applied\n    var transaction = left.transaction;\n\n      // The changes applied to the balance being debited\n      var debit = transaction.debit;\n\n        // The amount of the order's offer currency debited from the account\n        var amount = debit.amount;\n\n        // The new level of funds in the debited currency\n        var funds = debit.funds;\n\n        // The new level of locked funds in the debited currency\n        var lockedFunds = debit.lockedFunds;\n\n      // The changes applied to the balances being credited\n      var credit = transaction.credit;\n\n        // The amount of the order's bid currency credited to the account\n        var amount = credit.amount;\n\n        // The new level of funds in the credited currency\n        var funds = credit.funds;\n\n        // If the engine was instantiated with commission then the commission\n        // field will be set\n        var commission = credit.commission;\n\n          // The amount of the order's bid currency credited to the commission account\n          var amount = commission.amount;\n\n          // The new level of funds in the order's bid currency in the commission account\n          var funds = commission.funds;\n\n          // The reference associated with the commission calculation\n          var reference = commission.reference;\n\n  // `right` gives the changes to be applied to the order that was matched and the\n  // account that submitted it. This order will always be the order that is currently\n  // at the top of the opposing order book to that which the submitted order was added.\n  // The fields that can be set are the same as for `left`\n  var right = trades[0].right;\n```\n\n##### Bid orders\n\n```Javascript\nvar operation  = new Operation({\n  reference: '550e8400-e29b-41d4-a716-446655440000',\n  account: 'Peter',\n  // Place a bid for 10 BTC offering 100 Euros per BTC\n  submit: {\n    bidCurrency: 'BTC',\n    offerCurrency: 'EUR',\n    bidPrice: new Amount('100'),\n    bidAmount: new Amount('10')\n  }\n});\n```\n\n##### Offer orders\n\n```Javascript\nvar operation  = new Operation({\n  reference: '550e8400-e29b-41d4-a716-446655440000',\n  account: 'Peter',\n  // Place an offer of 1000 EUR bidding 0.01 BTC per EUR\n  submit: {\n    bidCurrency: 'BTC',\n    offerCurrency: 'EUR',\n    offerPrice: new Amount('0.01'),\n    offerAmount: new Amount('1000')\n  }\n});\n```\n\n#### `cancel` operation\n\nOrders can be cancelled using the cancel operation.\n\n```Javascript\nvar operation  = new Operation({\n  reference: '550e8400-e29b-41d4-a716-446655440000',\n  account: 'Peter',\n  // Cancel the order submitted by acount ID 'Peter' with operation sequence 615368 \n  cancel: {\n    sequence: 615368\n  }\n});\n\n// On successful application the `delta.result` will have the following fields\n\n// The new level of locked funds in the order's offer currency\nvar lockedFunds = delta.result.lockedFunds;\n```\n\n#### `JSON.stringify`\n\nOperations can be converted to and from JSON\n\n```Javascript\nvar json = JSON.stringify(operation);\nvar operation = new Operation({\n  json: json\n});\n```\n\n### `State`\n\n```javascript\nvar State = require('currency-market').State;\n```\n\n`State` instances provide simplified access to a market state. They do not contain the logic for matching orders but do accept `Engine` generated deltas to keep them synchronized with `Engine` instances\n\n#### Constructor\n\n```javascript\n// instantiate a state\nvar state = new State({\n  commission:\n    // Note that the commission acount name should match the commission\n    // acount name from the engine to which this state will be synchronised\n    account: 'commission'\n});\n\n// instantiate a state from JSON stringified engine\nvar state = new State({\n  commission:\n    account: 'commission'\n  json: JSON.stringify(engine)\n});\n```\n\n#### `apply` method\n\nThe `apply` method is used to apply deltas generated by `Engine` instances. The delta will be applied synchronously and errors may be thrown\n\n```Javascript\ntry {\n  state.apply(delta);\n} catch(error) {\n  // possible errors include out of sequence deltas \n  ...\n}\n```\n\n#### `JSON.stringify`\n\nStates can be converted to and from JSON\n\n```Javascript\nvar json = JSON.stringify(state);\nvar state = new State({\n  json: json\n});\n```\n\n#### `getBook` method\n\nThe `getBook` method gives access to the order books keyed by bid and offer currency. Each book is an `Array` of orders sorted as they will be matched for execution\n\n```Javascript\nvar book = state.getBook({\n  bidCurrency: 'BTC',\n  offerCurrency: 'EUR'\n});\n\n// Get the top of the order book\nvar order = book[0];\n\n// All orders have the following fields\n//\n// The sequence number\nvar sequence = order.sequence;\n// The timestamp in milliseconds since epoch\nvar timestamp = order.timestamp;\n// The account ID associated with the order\nvar account = order.account;\n// The offer currency\nvar offerCurrency = order.offerCurrency;\n// The bid currency\nvar bidCurrency = order.bidCurrency;\n\n// Bid orders have the following additional fields\n\n// The bid price as an `Amount` instance\nvar bidPrice = order.bidPrice;\n// The bid amount as an `Amount` instance\nvar bidAmount = order.bidAmount;\n\n// Offer orders have the following additional fields\n\n// The offer price as an `Amount` instance\nvar offerPrice = order.offerPrice;\n// The offer amount as an `Amount` instance\nvar offerAmount = order.offerAmount;\n```\n\n#### `getAccount` method\n\nThe `getAccount` method gives access to the accounts as instances of `Account` by account ID\n\n```Javascript\nvar account = state.getAccount('Peter');\n```\n\n##### `Account`\n\nThe `Account` class gives access to the properties of an account\n\n###### `orders` property\n\nThis is a collection of active orders keyed by sequence number (NB. it is an `Object` and not an `Array`)\n\n```Javascript\nvar order = account.orders[5];\n```\n\nThe orders are the same instances as those in the books retrieved with the `getBook` method\n\n###### `getBalance` method\n\nThe `getBalance` method gives access to the balances of funds as instances of `Balance` associated with an account, keyed by currency\n\n```Javascript\nvar balance = account.getBalance('EUR');\n```\n\n##### `Balance`\n\nThe `Balance` class gives access to the levels of funds and locked funds (when orders are outstanding) as `Amount` instances\n\n```Javascript\nvar funds = balance.funds;\nvar lockedFunds = balance.lockedFunds;\n```\n\n## Roadmap\n\n- Instant orders\n  - Market orders\n    - zero priced offers that are rejected if they cannot be completely filled by the market\n      - if a zero price is used then any remainder cannot be left on the book as it may cause a division by zero\n      - partial fills could be executed as long as the remainder is instantly cancelled\n  - Fill or Kill limit orders?\n    - will be tougher (less efficient) than market orders as an average price will have to be calculated?\n- Pluggable rounding policies\n  - Amount factory required?\n  - currently we only round down debits and credits so as not to debit more funds than available\n    - current rounding is done to an arbitrary scale of 25\n- Separate transaction IDs and sequence IDs\n  - Use sequence numbers instead of transaction IDs so the engine knows that it hasn't missed anything?\n  - Use both sequence numbers and transaction IDs?\n    - transaction IDs provide replayability\n      - have to be unique forever (uuid?)\n    - sequence numbers provide integrity checking\n      - may get unweildy if required to be unique forever and could loop instead\n      - where are sequence numbers assigned?\n        - This implies a state somewhere and a centralised component (bottleneck?)\n- Protection against attacks?\n  - entering orders that satisfy each other\n  - entering tiny orders\n  - should this be in another layer?\n\n## Contributing\n\nIn lieu of a formal styleguide, take care to maintain the existing coding style. Add unit tests for any new or changed functionality.\n\nRun tests with\n\n```\n$ npm test\n```\n\nRun performance tests with\n\n```\n$ npm run-script perf\n```\n\n## License\nCopyright &copy; 2013 Peter Halliday  \nLicensed under the MIT license.","readmeFilename":"README.md","_id":"currency-market@0.4.0","dist":{"shasum":"595fcb4bd4eafcea95a1de989b8be129db3e390a","tarball":"https://registry.npmjs.org/currency-market/-/currency-market-0.4.0.tgz","integrity":"sha512-3aydftJXV9AT7G5y5pb+4mhM98xi34TNMjcGaKTFI1zv+PChdILWbi8v2eP/ltpS4PvVUEqWZFswNRwlOT8JYw==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQC34P64BV9FKNysgDKek7bu0TWHS8XYB2kCc5p1c7gcpQIhAIiy+pcMl5zSkQc5TtGQDiaReS+FCviLenAZRDpUAtqc"}]},"_from":".","_npmVersion":"1.2.18","_npmUser":{"name":"pghalliday","email":"pghalliday@gmail.com"},"maintainers":[{"name":"pghalliday","email":"pghalliday@gmail.com"}]},"0.4.1":{"name":"currency-market","description":"A synchronous implementation of a limit order based currency market","version":"0.4.1","homepage":"https://github.com/pghalliday/currency-market","author":{"name":"Peter Halliday","email":"pghalliday@gmail.com","url":"http://stuffpetedoes.blogspot.nl/"},"repository":{"type":"git","url":"git://github.com/pghalliday/currency-market.git"},"bugs":{"url":"https://github.com/pghalliday/currency-market/issues"},"licenses":[{"type":"MIT","url":"https://github.com/pghalliday/currency-market/blob/master/LICENSE-MIT"}],"main":"lib/src/","engines":{"node":">= 0.10.4"},"scripts":{"prepublish":"grunt build","test":"grunt","perf":"grunt perf","travis-cov":{"threshold":100}},"dependencies":{},"devDependencies":{"chai":"~1.7.1","grunt-cli":"~0.1.9","grunt":"~0.4.1","grunt-contrib-coffee":"~0.7.0","grunt-mocha-test":"~0.5.0","grunt-contrib-clean":"~0.4.1","sinon":"~1.7.3","sinon-chai":"~2.4.0","randgen":"~0.0.4","grunt-contrib-copy":"~0.4.1","grunt-blanket":"~0.0.8","travis-cov":"~0.2.4"},"keywords":["currency","trading","limit order","synchronous","market"],"readme":"currency-market\r\n===============\r\n\r\n[![Build Status](https://travis-ci.org/pghalliday/currency-market.png)](https://travis-ci.org/pghalliday/currency-market)\r\n[![Dependency Status](https://gemnasium.com/pghalliday/currency-market.png)](https://gemnasium.com/pghalliday/currency-market)\r\n\r\nA synchronous implementation of a limit order based currency market\r\n\r\n## Installation\r\n\r\n```\r\nnpm install currency-market\r\n```\r\n\r\n## Usage\r\n\r\nThe `currency-market` package is intended to be used by a system of components that need to be synchronized. Those components are\r\n\r\n- A number of front ends that generate operations and allow the state of the market to be queried\r\n- An operation hub that accepts the operations and ensures they are submitted to order matching engines in a reproducible order\r\n- A number of identical order matching engines that process the operations and calculate the new state of the market for each one\r\n- A delta hub that receives the market state deltas and distributes them to the front ends\r\n\r\nOn intialization\r\n\r\n- Engines will be constructed (perhaps from a previous engine state) and when requested will send the state to the delta hub\r\n\r\n```Javascript\r\nvar Engine = require('currency-market').Engine;\r\nvar Amount = require('currency-market').Amount;\r\n\r\nvar COMMISSION_RATE = new Amount('0.001');\r\nvar COMMISSION_REFERENCE = '0.1%';\r\n\r\nvar engine = new Engine({\r\n  commission: {\r\n    account: 'commission'\r\n    calculate: function(params) {\r\n      return {\r\n        amount: params.amount.multiply(COMMISSION_RATE),\r\n        reference: COMMISSION_REFERENCE\r\n      };\r\n    }\r\n  },\r\n  json: previousEngineState  \r\n});\r\n\r\n...\r\n\r\nsendStateToDeltaHub(JSON.stringify(engine));\r\n```\r\n\r\n- The delta hub will request the state from an engine and forward that to the front ends when they start up\r\n\r\n```Javascript\r\nvar State = require('currency-market').State;\r\n\r\ngetStateFromEngine(function(receivedEngineState){\r\n  var state = new State({\r\n    commission: {\r\n      account: 'commission'\r\n    },\r\n    json: receivedEngineState  \r\n  });\r\n});\r\n\r\n...\r\n\r\nsendStateToFrontEnd(JSON.stringify(state));\r\n```\r\n\r\n- Front ends will request the state and then construct a state from the JSON state they receive from the delta hub\r\n\r\n```Javascript\r\nvar State = require('currency-market').State;\r\n\r\ngetStateFromDeltaHub(function(receivedState){\r\n  var state = new State({\r\n    commission: {\r\n      account: 'commission'\r\n    },\r\n    json: receivedState\r\n  });\r\n});\r\n```\r\n\r\nThen the life cycle of an operation is as follows\r\n\r\n- A front end constructs an operation and sends it to an operation hub\r\n\r\n```Javascript\r\nvar Operation = require('currency-market').Operation;\r\nvar Amount = require('currency-market').Amount;\r\n\r\nvar operation = new Operation({\r\n  reference: '550e8400-e29b-41d4-a716-446655440000',\r\n  account: 'Peter',\r\n  deposit: {\r\n    currency: 'EUR',\r\n    amount: new Amount '500'\r\n  }\r\n});\r\n\r\nsendToOperationHub(JSON.stringify(operation));\r\n```\r\n\r\n- The operation hub receives the operation, accepts it with a seqence number and timestamp and forwards it to the engine instances\r\n\r\n```Javascript\r\nvar Operation = require('currency-market').Operation;\r\n\r\nvar operation = new Operation({\r\n  json: receivedJSON  \r\n});\r\n\r\noperation.accept({\r\n  sequence: 654852,\r\n  timestamp: 1371737390976\r\n});\r\n\r\nsendToEngines(JSON.stringify(operation));\r\n```\r\n\r\n- The engines receive the operation, process it and send market state deltas to the delta hub\r\n\r\n```Javascript\r\nvar Operation = require('currency-market').Operation;\r\n\r\nvar operation = new Operation({\r\n  json: receivedJSON  \r\n});\r\n\r\ndelta = engine.apply(operation);\r\n\r\nsendToDeltaHub(JSON.stringify(delta));\r\n```\r\n\r\n- The delta hub receives the deltas, processes the first of each one it receives to update its own state and sends that delta on to the front ends\r\n\r\n```Javascript\r\nvar Delta = require('currency-market').Delta;\r\n\r\nvar delta = new Delta({\r\n  json: receivedJSON  \r\n});\r\n\r\nstate.apply(delta);\r\n\r\nsendToFrontEnds(JSON.stringify(delta));\r\n```\r\n\r\n- The front ends receive the deltas and apply them to their own state so that they can respond to queries with the new information\r\n\r\n```Javascript\r\nvar Delta = require('currency-market').Delta;\r\n\r\nvar delta = new Delta({\r\n  json: receivedJSON  \r\n});\r\n\r\nstate.apply(delta);\r\n\r\nvar funds = state.getAccount('Peter').getBalance('EUR').funds\r\n```\r\n\r\n## API\r\n\r\nAll functions complete synchronously and throw errors if they fail.\r\n\r\n### `Amount`\r\n\r\n`Amount` handles large numerical arithmetic accurately (unlike the built in Javascript number implementation). It is used for all amount and price values and is provided as a utility for applications to apply the same arimthmetic functionality in their own contexts.\r\n\r\n`Amount` instances are immutable.\r\n\r\nDivisions are carried out to an arbitrary precision of 25 decimal points.\r\n\r\n``` Javascript\r\nvar Amount = require('currency-market').Amount;\r\n\r\n// Always initialise from a string representation of a number\r\nvar amount1000 = new Amount('1000');\r\nvar amount200 = new Amount('200');\r\n\r\n// multiply 2 amounts\r\nvar amount200000 = amount1000.multiply(amount200);\r\n\r\n// add 2 amounts\r\nvar amount1200 = amount1000.add(amount200);\r\n\r\n// subtract 2 amounts\r\nvar amount800 = amount1000.subtract(amount200);\r\n\r\n// divide 2 amounts\r\nvar amountPoint2 = amount200.divide(amount1000);\r\n\r\n// Return the string representation of an amount\r\nvar str1000 = amount1000.toString();\r\n\r\n// Compare 2 values\r\namount1000.compareTo(amount200) > 0;\r\namount200.compareTo(amount1000) < 0;\r\namount200.compareTo(amount200) == 0;\r\n\r\n// 2 Identity constants are defined\r\nvar zero = Amount.ZERO;\r\nvar one = Amount.ONE;\r\n```\r\n\r\n### `Engine`\r\n\r\n```javascript\r\nvar Engine = require('currency-market').Engine;\r\n```\r\n\r\n`Engine` instances accept operations and return deltas that can be applied to simplified `State` instances.\r\n\r\n#### Constructor\r\n\r\n```javascript\r\n// Define a commission rate of 0.5%\r\nvar COMMISSION_RATE = new Amount('0.005');\r\n\r\n// instantiate an engine\r\nvar engine = new engine({\r\n  // Optionally specify how commission should be applied to credits resulting from trades.\r\n  // If this is not specified then no commission will be charged\r\n  commission: {\r\n    // The ID of the account to receive the commission\r\n    account: 'commission',\r\n    // The callback to use for calculating the commission amount to subtract from a credit\r\n    // resulting from a trade\r\n    calculate: function(params) {\r\n      // A timestamp for the trade being executed\r\n      var timestamp = params.timestamp;\r\n      // The ID of the account that is being credited\r\n      var account = params.account;\r\n      // The currency of the credited amount\r\n      var currency = params.currency;\r\n      // The amount that is being credited as an Amount instance\r\n      var amount = params.amount;\r\n\r\n      // Return an object containing the amount of commission to deduct as an Amount\r\n      // instance and a reference for the commission rate/type being charged\r\n      //\r\n      // Note that it's best to avoid divisions when calculating commissions so as\r\n      // to avoid rounding errors. Also, as the reference is intended be transmitted along\r\n      // with market deltas, it should be possible to convert it losslessly to and from JSON\r\n      return {\r\n        amount: amount.multiply(COMMISSION_RATE),\r\n        reference: COMMISSION_RATE + '%'\r\n      };\r\n    }\r\n  }\r\n});\r\n```\r\n\r\n#### `apply` method\r\n\r\nThe `apply` method applies operations and returns the resulting deltas.\r\n\r\nOperations and deltas can be converted losslessly to and from JSON for transmission.\r\n\r\nIf an operation fails for any reason (eg. not enough funds) then an error will be thrown.\r\n\r\nOnly operations that have been accepted using the `Operation.accept` method can be applied to an `Engine` instance.\r\n\r\n```Javascript\r\ntry {\r\n  var delta  = engine.apply(new Operation({\r\n    // Operation parameters\r\n    ...\r\n  }));\r\n} catch(error) {\r\n  // Possible errors will include invalid parameters or insufficient funds to complete the operation\r\n  ...\r\n}\r\n```\r\n\r\n#### `JSON.stringify`\r\n\r\nEngines can be converted to and from JSON\r\n\r\n```Javascript\r\nvar json = JSON.stringify(engine);\r\nvar engine = new Engine({\r\n  commission: {\r\n    account: 'commission',\r\n    calculate: function(params) {\r\n      return {\r\n        amount: amount.multiply(COMMISSION_RATE),\r\n        reference: COMMISSION_RATE + '%'\r\n      };\r\n    }\r\n  },\r\n  json: json\r\n});\r\n\r\n// OR\r\n\r\nvar json = JSON.stringify(engine);\r\nvar engine = new Engine({\r\n  commission: {\r\n    account: 'commission',\r\n    calculate: function(params) {\r\n      return {\r\n        amount: amount.multiply(COMMISSION_RATE),\r\n        reference: COMMISSION_RATE + '%'\r\n      };\r\n    }\r\n  },\r\n  exported: JSON.parse(json)\r\n});\r\n```\r\n\r\n### `Delta`\r\n\r\n```javascript\r\nvar Delta = require('currency-market').Delta;\r\n```\r\n\r\n`Delta` instances are returned by `Engine` instances after successfully applying operations. They can be converted to JSON, transmitted, reconstructed from JSON and applied to `State` instances.\r\n\r\nAll deltas have the following properties\r\n\r\n```Javascript\r\n// The delta sequence number. These will be generated consecutively by the engine\r\n// for successful operations. As such they will not be synchronized with operation sequence\r\n// numbers due to the possibility of operations throwing errors\r\nvar sequence = delta.sequence;\r\n\r\n// The operation instance as supplied to the `apply` method\r\nvar operation = delta.operation;\r\n\r\n// Additional state change information in a format specific to the operation type\r\nvar result = delta.result;\r\n\r\n```\r\n\r\n#### `JSON.stringify`\r\n\r\nDeltas can be converted to and from JSON\r\n\r\n```Javascript\r\nvar json = JSON.stringify(delta);\r\nvar delta = new Delta({\r\n  json: json\r\n});\r\n\r\n// OR\r\n\r\nvar json = JSON.stringify(delta);\r\nvar delta = new Delta({\r\n  exported: JSON.parse(json)\r\n});\r\n```\r\n\r\n### `Operation`\r\n\r\n```javascript\r\nvar Operation = require('currency-market').Operation;\r\n```\r\n\r\n`Operation` instances are submitted to `Engine` instances to apply operations. They can be converted to JSON, transmitted and reconstructed from JSON\r\n\r\nAll operations follow this pattern\r\n\r\n```Javascript\r\nvar operation = new Operation({\r\n  // Application specified reference that is returned untouched with the operation details included in the delta.\r\n  // Care should be taken to ensure that this too can be converted to and from JSON\r\n  reference: '550e8400-e29b-41d4-a716-446655440000',\r\n  // The ID of the account submitting the operation\r\n  account: 'Peter',\r\n  // The operation details, the name of this property will determine the type of the operation\r\n  // and what additional fields need to be supplied\r\n  operationType: {\r\n    // Operation parameters\r\n    ...\r\n  }\r\n});\r\n```\r\n\r\n#### `accept` method\r\n\r\nOperations must be accepted before they can be applied to an `Engine` instance to ensure they are associated with a sequence number and a timestamp\r\n\r\n```Javascript\r\noperation.accept({\r\n  // The operation sequence number. These must be consecutive for consecutive operations\r\n  sequence: 123456,\r\n  // The timestamp for the operation as a Unix time since epoch in milliseconds\r\n  timestamp: 1371737390976\r\n});\r\n```\r\n\r\n#### `deposit` operation\r\n\r\nDeposit funds into an account\r\n\r\n```Javascript\r\nvar operation  = new Operation({\r\n  reference: '550e8400-e29b-41d4-a716-446655440000',\r\n  account: 'Peter',\r\n  // deposit 1000 Euros to account ID 'Peter'\r\n  deposit: {\r\n    currency: 'EUR',\r\n    amount: new Amount('1000')\r\n  }\r\n});\r\n\r\n// On successful application the `delta.result` will have the following fields\r\n\r\n// The new level of funds in the deposited currency as an `Amount` instance\r\nvar funds = delta.result.funds\r\n```\r\n\r\n#### `withdraw` operation\r\n\r\nWithdraw funds from an account\r\n\r\n```Javascript\r\nvar operation  = new Operation({\r\n  reference: '550e8400-e29b-41d4-a716-446655440000',\r\n  account: 'Peter',\r\n  // withdraw 1000 Euros from account ID 'Peter'\r\n  withdraw: {\r\n    currency: 'EUR',\r\n    amount: new Amount('1000')\r\n  }\r\n});\r\n\r\n// On successful application the `delta.result` will have the following fields\r\n\r\n// The new level of funds in the deposited currency as an `Amount` instance\r\nvar funds = delta.result.funds\r\n```\r\n\r\n#### `submit` operation\r\n\r\nSubmit orders to the market. Both bid and offer orders can be submitted and follow this pattern\r\n\r\n```Javascript\r\nvar operation  = new Operation({\r\n  reference: '550e8400-e29b-41d4-a716-446655440000',\r\n  account: 'Peter',\r\n  // Place a bid order for 10 BTC offering 100 Euros per BTC\r\n  submit: {\r\n    // order parameters\r\n    ...\r\n  }\r\n});\r\n\r\n// On successful application the `delta.result` will have the following fields\r\n\r\n// The new level of locked funds in the order's offer currency\r\nvar lockedFunds = delta.result.lockedFunds\r\n\r\n// Note that only one of `nextHigherOrderSequence` or `trades` will be set\r\n\r\n// If the order is not at the top of the order book then the sequence number\r\n// of the next order above it is returned. This is a hint to optimize the\r\n// insertion of the order into a `State` instance\r\nvar nextHigherOrderSequence = delta.result.nextHigherOrderSequence;\r\n\r\n// If the order was inserted at the top of the order book then an array of trades\r\n// will be returned. This array will still be set, but will be empty, if no actual \r\n// trades were made\r\n//\r\n// Note that the price at which any trade was executed will be given by the bid or\r\n// offer price associated with the `right` order and that the volume traded in each\r\n// currency is most easily referenced by the debit amounts associated with the `left`\r\n// and `right` accounts in their respective order's offer currencies\r\nvar trades = delta.result.trades;\r\n\r\n  // `left` gives the changes to be applied to the order that was submitted and the\r\n  // account that submitted it\r\n  var left = trades[0].left;\r\n\r\n    // Only one of `left` or `right` will have a remainder and this\r\n    // signals the amount of the order that has not yet been executed.\r\n    // When no remainder is specified it signals that the order was\r\n    // completely executed. It is possible that neither `left` nor `right`\r\n    // will have a remainder if they completely satisfy each other\r\n    var remainder = left.remainder;\r\n\r\n      // The remaining bidAmount on the order\r\n      var bidAmount = remainder.bidAmount;\r\n\r\n      // The remaining offerAmount on the order\r\n      var offerAmount = remainder.offerAmount;\r\n\r\n    // The transaction fields signal by how much the account balances have changed\r\n    // and how much commission was applied\r\n    var transaction = left.transaction;\r\n\r\n      // The changes applied to the balance being debited\r\n      var debit = transaction.debit;\r\n\r\n        // The amount of the order's offer currency debited from the account\r\n        var amount = debit.amount;\r\n\r\n        // The new level of funds in the debited currency\r\n        var funds = debit.funds;\r\n\r\n        // The new level of locked funds in the debited currency\r\n        var lockedFunds = debit.lockedFunds;\r\n\r\n      // The changes applied to the balances being credited\r\n      var credit = transaction.credit;\r\n\r\n        // The amount of the order's bid currency credited to the account\r\n        var amount = credit.amount;\r\n\r\n        // The new level of funds in the credited currency\r\n        var funds = credit.funds;\r\n\r\n        // If the engine was instantiated with commission then the commission\r\n        // field will be set\r\n        var commission = credit.commission;\r\n\r\n          // The amount of the order's bid currency credited to the commission account\r\n          var amount = commission.amount;\r\n\r\n          // The new level of funds in the order's bid currency in the commission account\r\n          var funds = commission.funds;\r\n\r\n          // The reference associated with the commission calculation\r\n          var reference = commission.reference;\r\n\r\n  // `right` gives the changes to be applied to the order that was matched and the\r\n  // account that submitted it. This order will always be the order that is currently\r\n  // at the top of the opposing order book to that which the submitted order was added.\r\n  // The fields that can be set are the same as for `left`\r\n  var right = trades[0].right;\r\n```\r\n\r\n##### Bid orders\r\n\r\n```Javascript\r\nvar operation  = new Operation({\r\n  reference: '550e8400-e29b-41d4-a716-446655440000',\r\n  account: 'Peter',\r\n  // Place a bid for 10 BTC offering 100 Euros per BTC\r\n  submit: {\r\n    bidCurrency: 'BTC',\r\n    offerCurrency: 'EUR',\r\n    bidPrice: new Amount('100'),\r\n    bidAmount: new Amount('10')\r\n  }\r\n});\r\n```\r\n\r\n##### Offer orders\r\n\r\n```Javascript\r\nvar operation  = new Operation({\r\n  reference: '550e8400-e29b-41d4-a716-446655440000',\r\n  account: 'Peter',\r\n  // Place an offer of 1000 EUR bidding 0.01 BTC per EUR\r\n  submit: {\r\n    bidCurrency: 'BTC',\r\n    offerCurrency: 'EUR',\r\n    offerPrice: new Amount('0.01'),\r\n    offerAmount: new Amount('1000')\r\n  }\r\n});\r\n```\r\n\r\n#### `cancel` operation\r\n\r\nOrders can be cancelled using the cancel operation.\r\n\r\n```Javascript\r\nvar operation  = new Operation({\r\n  reference: '550e8400-e29b-41d4-a716-446655440000',\r\n  account: 'Peter',\r\n  // Cancel the order submitted by acount ID 'Peter' with operation sequence 615368 \r\n  cancel: {\r\n    sequence: 615368\r\n  }\r\n});\r\n\r\n// On successful application the `delta.result` will have the following fields\r\n\r\n// The new level of locked funds in the order's offer currency\r\nvar lockedFunds = delta.result.lockedFunds;\r\n```\r\n\r\n#### `JSON.stringify`\r\n\r\nOperations can be converted to and from JSON\r\n\r\n```Javascript\r\nvar json = JSON.stringify(operation);\r\nvar operation = new Operation({\r\n  json: json\r\n});\r\n\r\n// OR\r\n\r\nvar json = JSON.stringify(operation);\r\nvar operation = new Operation({\r\n  exported: JSON.parse(json)\r\n});\r\n```\r\n\r\n### `State`\r\n\r\n```javascript\r\nvar State = require('currency-market').State;\r\n```\r\n\r\n`State` instances provide simplified access to a market state. They do not contain the logic for matching orders but do accept `Engine` generated deltas to keep them synchronized with `Engine` instances\r\n\r\n#### Constructor\r\n\r\n```javascript\r\n// instantiate a state\r\nvar state = new State({\r\n  commission:\r\n    // Note that the commission acount name should match the commission\r\n    // acount name from the engine to which this state will be synchronised\r\n    account: 'commission'\r\n});\r\n\r\n// instantiate a state from JSON stringified engine\r\nvar state = new State({\r\n  commission:\r\n    account: 'commission'\r\n  json: JSON.stringify(engine)\r\n});\r\n```\r\n\r\n#### `apply` method\r\n\r\nThe `apply` method is used to apply deltas generated by `Engine` instances. The delta will be applied synchronously and errors may be thrown\r\n\r\n```Javascript\r\ntry {\r\n  state.apply(delta);\r\n} catch(error) {\r\n  // possible errors include out of sequence deltas \r\n  ...\r\n}\r\n```\r\n\r\n#### `JSON.stringify`\r\n\r\nStates can be converted to and from JSON\r\n\r\n```Javascript\r\nvar json = JSON.stringify(state);\r\nvar state = new State({\r\n  json: json\r\n});\r\n\r\n// OR\r\n\r\nvar json = JSON.stringify(state);\r\nvar state = new State({\r\n  exported: JSON.parse(json)\r\n});\r\n```\r\n\r\n#### `getBook` method\r\n\r\nThe `getBook` method gives access to the order books keyed by bid and offer currency. Each book is an `Array` of orders sorted as they will be matched for execution\r\n\r\n```Javascript\r\nvar book = state.getBook({\r\n  bidCurrency: 'BTC',\r\n  offerCurrency: 'EUR'\r\n});\r\n\r\n// Get the top of the order book\r\nvar order = book[0];\r\n\r\n// All orders have the following fields\r\n//\r\n// The sequence number\r\nvar sequence = order.sequence;\r\n// The timestamp in milliseconds since epoch\r\nvar timestamp = order.timestamp;\r\n// The account ID associated with the order\r\nvar account = order.account;\r\n// The offer currency\r\nvar offerCurrency = order.offerCurrency;\r\n// The bid currency\r\nvar bidCurrency = order.bidCurrency;\r\n\r\n// Bid orders have the following additional fields\r\n\r\n// The bid price as an `Amount` instance\r\nvar bidPrice = order.bidPrice;\r\n// The bid amount as an `Amount` instance\r\nvar bidAmount = order.bidAmount;\r\n\r\n// Offer orders have the following additional fields\r\n\r\n// The offer price as an `Amount` instance\r\nvar offerPrice = order.offerPrice;\r\n// The offer amount as an `Amount` instance\r\nvar offerAmount = order.offerAmount;\r\n```\r\n\r\n#### `getAccount` method\r\n\r\nThe `getAccount` method gives access to the accounts as instances of `Account` by account ID\r\n\r\n```Javascript\r\nvar account = state.getAccount('Peter');\r\n```\r\n\r\n##### `Account`\r\n\r\nThe `Account` class gives access to the properties of an account\r\n\r\n###### `orders` property\r\n\r\nThis is a collection of active orders keyed by sequence number (NB. it is an `Object` and not an `Array`)\r\n\r\n```Javascript\r\nvar order = account.orders[5];\r\n```\r\n\r\nThe orders are the same instances as those in the books retrieved with the `getBook` method\r\n\r\n###### `getBalance` method\r\n\r\nThe `getBalance` method gives access to the balances of funds as instances of `Balance` associated with an account, keyed by currency\r\n\r\n```Javascript\r\nvar balance = account.getBalance('EUR');\r\n```\r\n\r\n##### `Balance`\r\n\r\nThe `Balance` class gives access to the levels of funds and locked funds (when orders are outstanding) as `Amount` instances\r\n\r\n```Javascript\r\nvar funds = balance.funds;\r\nvar lockedFunds = balance.lockedFunds;\r\n```\r\n\r\n## Roadmap\r\n\r\n- Instant orders\r\n  - Market orders\r\n    - zero priced offers that are rejected if they cannot be completely filled by the market\r\n      - if a zero price is used then any remainder cannot be left on the book as it may cause a division by zero\r\n      - partial fills could be executed as long as the remainder is instantly cancelled\r\n  - Fill or Kill limit orders?\r\n    - will be tougher (less efficient) than market orders as an average price will have to be calculated?\r\n- Pluggable rounding policies\r\n  - Amount factory required?\r\n  - currently we only round down debits and credits so as not to debit more funds than available\r\n    - current rounding is done to an arbitrary scale of 25\r\n- Separate transaction IDs and sequence IDs\r\n  - Use sequence numbers instead of transaction IDs so the engine knows that it hasn't missed anything?\r\n  - Use both sequence numbers and transaction IDs?\r\n    - transaction IDs provide replayability\r\n      - have to be unique forever (uuid?)\r\n    - sequence numbers provide integrity checking\r\n      - may get unweildy if required to be unique forever and could loop instead\r\n      - where are sequence numbers assigned?\r\n        - This implies a state somewhere and a centralised component (bottleneck?)\r\n- Protection against attacks?\r\n  - entering orders that satisfy each other\r\n  - entering tiny orders\r\n  - should this be in another layer?\r\n\r\n## Contributing\r\n\r\nIn lieu of a formal styleguide, take care to maintain the existing coding style. Add unit tests for any new or changed functionality.\r\n\r\nRun tests with\r\n\r\n```\r\n$ npm test\r\n```\r\n\r\nRun performance tests with\r\n\r\n```\r\n$ npm run-script perf\r\n```\r\n\r\n## License\r\nCopyright &copy; 2013 Peter Halliday  \r\nLicensed under the MIT license.","readmeFilename":"README.md","_id":"currency-market@0.4.1","dist":{"shasum":"c43925d05b9da3f9a9a8e275c6b4c8f93e715761","tarball":"https://registry.npmjs.org/currency-market/-/currency-market-0.4.1.tgz","integrity":"sha512-EbMdZvTdrvoiixWJB1tD77mocBl88ux5O1bdniy6SIVAbBJEU6jBGl0zJf1SC25Xc4w55qxtgJ7Yibc+5ApdkQ==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQD8YGN3Js+u0hy5mPaI1Yqc3DmHHPWlTB9ivwp+NXd4ewIhAJ/7VyD+Yvdl7u4RqX4ZhZFnu5iZ5srAP2iR41A1szYa"}]},"_from":".","_npmVersion":"1.2.32","_npmUser":{"name":"pghalliday","email":"pghalliday@gmail.com"},"maintainers":[{"name":"pghalliday","email":"pghalliday@gmail.com"}]},"0.4.2":{"name":"currency-market","description":"A synchronous implementation of a limit order based currency market","version":"0.4.2","homepage":"https://github.com/pghalliday/currency-market","author":{"name":"Peter Halliday","email":"pghalliday@gmail.com","url":"http://stuffpetedoes.blogspot.nl/"},"repository":{"type":"git","url":"git://github.com/pghalliday/currency-market.git"},"bugs":{"url":"https://github.com/pghalliday/currency-market/issues"},"licenses":[{"type":"MIT","url":"https://github.com/pghalliday/currency-market/blob/master/LICENSE-MIT"}],"main":"lib/src/","engines":{"node":">= 0.10.4"},"scripts":{"prepublish":"grunt build","test":"grunt","perf":"grunt perf"},"dependencies":{},"devDependencies":{"chai":"~1.7.1","grunt-cli":"~0.1.9","grunt":"~0.4.1","grunt-contrib-coffee":"~0.7.0","grunt-mocha-test":"~0.5.0","grunt-contrib-clean":"~0.4.1","sinon":"~1.7.3","sinon-chai":"~2.4.0","randgen":"~0.0.4","grunt-contrib-copy":"~0.4.1","grunt-blanket":"~0.0.8","travis-cov":"~0.2.4"},"keywords":["currency","trading","limit order","synchronous","market"],"readme":"currency-market\r\n===============\r\n\r\n[![Build Status](https://travis-ci.org/pghalliday/currency-market.png)](https://travis-ci.org/pghalliday/currency-market)\r\n[![Dependency Status](https://gemnasium.com/pghalliday/currency-market.png)](https://gemnasium.com/pghalliday/currency-market)\r\n\r\nA synchronous implementation of a limit order based currency market\r\n\r\n## Installation\r\n\r\n```\r\nnpm install currency-market\r\n```\r\n\r\n## Usage\r\n\r\nThe `currency-market` package is intended to be used by a system of components that need to be synchronized. Those components are\r\n\r\n- A number of front ends that generate operations and allow the state of the market to be queried\r\n- An operation hub that accepts the operations and ensures they are submitted to order matching engines in a reproducible order\r\n- A number of identical order matching engines that process the operations and calculate the new state of the market for each one\r\n- A delta hub that receives the market state deltas and distributes them to the front ends\r\n\r\nOn intialization\r\n\r\n- Engines will be constructed (perhaps from a previous engine state) and when requested will send the state to the delta hub\r\n\r\n```Javascript\r\nvar Engine = require('currency-market').Engine;\r\nvar Amount = require('currency-market').Amount;\r\n\r\nvar COMMISSION_RATE = new Amount('0.001');\r\nvar COMMISSION_REFERENCE = '0.1%';\r\n\r\nvar engine = new Engine({\r\n  commission: {\r\n    account: 'commission'\r\n    calculate: function(params) {\r\n      return {\r\n        amount: params.amount.multiply(COMMISSION_RATE),\r\n        reference: COMMISSION_REFERENCE\r\n      };\r\n    }\r\n  },\r\n  json: previousEngineState  \r\n});\r\n\r\n...\r\n\r\nsendStateToDeltaHub(JSON.stringify(engine));\r\n```\r\n\r\n- The delta hub will request the state from an engine and forward that to the front ends when they start up\r\n\r\n```Javascript\r\nvar State = require('currency-market').State;\r\n\r\ngetStateFromEngine(function(receivedEngineState){\r\n  var state = new State({\r\n    commission: {\r\n      account: 'commission'\r\n    },\r\n    json: receivedEngineState  \r\n  });\r\n});\r\n\r\n...\r\n\r\nsendStateToFrontEnd(JSON.stringify(state));\r\n```\r\n\r\n- Front ends will request the state and then construct a state from the JSON state they receive from the delta hub\r\n\r\n```Javascript\r\nvar State = require('currency-market').State;\r\n\r\ngetStateFromDeltaHub(function(receivedState){\r\n  var state = new State({\r\n    commission: {\r\n      account: 'commission'\r\n    },\r\n    json: receivedState\r\n  });\r\n});\r\n```\r\n\r\nThen the life cycle of an operation is as follows\r\n\r\n- A front end constructs an operation and sends it to an operation hub\r\n\r\n```Javascript\r\nvar Operation = require('currency-market').Operation;\r\nvar Amount = require('currency-market').Amount;\r\n\r\nvar operation = new Operation({\r\n  reference: '550e8400-e29b-41d4-a716-446655440000',\r\n  account: 'Peter',\r\n  deposit: {\r\n    currency: 'EUR',\r\n    amount: new Amount '500'\r\n  }\r\n});\r\n\r\nsendToOperationHub(JSON.stringify(operation));\r\n```\r\n\r\n- The operation hub receives the operation, accepts it with a seqence number and timestamp and forwards it to the engine instances\r\n\r\n```Javascript\r\nvar Operation = require('currency-market').Operation;\r\n\r\nvar operation = new Operation({\r\n  json: receivedJSON  \r\n});\r\n\r\noperation.accept({\r\n  sequence: 654852,\r\n  timestamp: 1371737390976\r\n});\r\n\r\nsendToEngines(JSON.stringify(operation));\r\n```\r\n\r\n- The engines receive the operation, process it and send market state deltas to the delta hub\r\n\r\n```Javascript\r\nvar Operation = require('currency-market').Operation;\r\n\r\nvar operation = new Operation({\r\n  json: receivedJSON  \r\n});\r\n\r\ndelta = engine.apply(operation);\r\n\r\nsendToDeltaHub(JSON.stringify(delta));\r\n```\r\n\r\n- The delta hub receives the deltas, processes the first of each one it receives to update its own state and sends that delta on to the front ends\r\n\r\n```Javascript\r\nvar Delta = require('currency-market').Delta;\r\n\r\nvar delta = new Delta({\r\n  json: receivedJSON  \r\n});\r\n\r\nstate.apply(delta);\r\n\r\nsendToFrontEnds(JSON.stringify(delta));\r\n```\r\n\r\n- The front ends receive the deltas and apply them to their own state so that they can respond to queries with the new information\r\n\r\n```Javascript\r\nvar Delta = require('currency-market').Delta;\r\n\r\nvar delta = new Delta({\r\n  json: receivedJSON  \r\n});\r\n\r\nstate.apply(delta);\r\n\r\nvar funds = state.getAccount('Peter').getBalance('EUR').funds\r\n```\r\n\r\n## API\r\n\r\nAll functions complete synchronously and throw errors if they fail.\r\n\r\n### `Amount`\r\n\r\n`Amount` handles large numerical arithmetic accurately (unlike the built in Javascript number implementation). It is used for all amount and price values and is provided as a utility for applications to apply the same arimthmetic functionality in their own contexts.\r\n\r\n`Amount` instances are immutable.\r\n\r\nDivisions are carried out to an arbitrary precision of 25 decimal points.\r\n\r\n``` Javascript\r\nvar Amount = require('currency-market').Amount;\r\n\r\n// Always initialise from a string representation of a number\r\nvar amount1000 = new Amount('1000');\r\nvar amount200 = new Amount('200');\r\n\r\n// multiply 2 amounts\r\nvar amount200000 = amount1000.multiply(amount200);\r\n\r\n// add 2 amounts\r\nvar amount1200 = amount1000.add(amount200);\r\n\r\n// subtract 2 amounts\r\nvar amount800 = amount1000.subtract(amount200);\r\n\r\n// divide 2 amounts\r\nvar amountPoint2 = amount200.divide(amount1000);\r\n\r\n// Return the string representation of an amount\r\nvar str1000 = amount1000.toString();\r\n\r\n// Compare 2 values\r\namount1000.compareTo(amount200) > 0;\r\namount200.compareTo(amount1000) < 0;\r\namount200.compareTo(amount200) == 0;\r\n\r\n// 2 Identity constants are defined\r\nvar zero = Amount.ZERO;\r\nvar one = Amount.ONE;\r\n```\r\n\r\n### `Engine`\r\n\r\n```javascript\r\nvar Engine = require('currency-market').Engine;\r\n```\r\n\r\n`Engine` instances accept operations and return deltas that can be applied to simplified `State` instances.\r\n\r\n#### Constructor\r\n\r\n```javascript\r\n// Define a commission rate of 0.5%\r\nvar COMMISSION_RATE = new Amount('0.005');\r\n\r\n// instantiate an engine\r\nvar engine = new engine({\r\n  // Optionally specify how commission should be applied to credits resulting from trades.\r\n  // If this is not specified then no commission will be charged\r\n  commission: {\r\n    // The ID of the account to receive the commission\r\n    account: 'commission',\r\n    // The callback to use for calculating the commission amount to subtract from a credit\r\n    // resulting from a trade\r\n    calculate: function(params) {\r\n      // A timestamp for the trade being executed\r\n      var timestamp = params.timestamp;\r\n      // The ID of the account that is being credited\r\n      var account = params.account;\r\n      // The currency of the credited amount\r\n      var currency = params.currency;\r\n      // The amount that is being credited as an Amount instance\r\n      var amount = params.amount;\r\n\r\n      // Return an object containing the amount of commission to deduct as an Amount\r\n      // instance and a reference for the commission rate/type being charged\r\n      //\r\n      // Note that it's best to avoid divisions when calculating commissions so as\r\n      // to avoid rounding errors. Also, as the reference is intended be transmitted along\r\n      // with market deltas, it should be possible to convert it losslessly to and from JSON\r\n      return {\r\n        amount: amount.multiply(COMMISSION_RATE),\r\n        reference: COMMISSION_RATE + '%'\r\n      };\r\n    }\r\n  }\r\n});\r\n```\r\n\r\n#### `apply` method\r\n\r\nThe `apply` method applies operations and returns the resulting deltas.\r\n\r\nOperations and deltas can be converted losslessly to and from JSON for transmission.\r\n\r\nIf an operation fails for any reason (eg. not enough funds) then an error will be thrown.\r\n\r\nOnly operations that have been accepted using the `Operation.accept` method can be applied to an `Engine` instance.\r\n\r\n```Javascript\r\ntry {\r\n  var delta  = engine.apply(new Operation({\r\n    // Operation parameters\r\n    ...\r\n  }));\r\n} catch(error) {\r\n  // Possible errors will include invalid parameters or insufficient funds to complete the operation\r\n  ...\r\n}\r\n```\r\n\r\n#### `JSON.stringify`\r\n\r\nEngines can be converted to and from JSON\r\n\r\n```Javascript\r\nvar json = JSON.stringify(engine);\r\nvar engine = new Engine({\r\n  commission: {\r\n    account: 'commission',\r\n    calculate: function(params) {\r\n      return {\r\n        amount: amount.multiply(COMMISSION_RATE),\r\n        reference: COMMISSION_RATE + '%'\r\n      };\r\n    }\r\n  },\r\n  json: json\r\n});\r\n\r\n// OR\r\n\r\nvar json = JSON.stringify(engine);\r\nvar engine = new Engine({\r\n  commission: {\r\n    account: 'commission',\r\n    calculate: function(params) {\r\n      return {\r\n        amount: amount.multiply(COMMISSION_RATE),\r\n        reference: COMMISSION_RATE + '%'\r\n      };\r\n    }\r\n  },\r\n  exported: JSON.parse(json)\r\n});\r\n```\r\n\r\n### `Delta`\r\n\r\n```javascript\r\nvar Delta = require('currency-market').Delta;\r\n```\r\n\r\n`Delta` instances are returned by `Engine` instances after successfully applying operations. They can be converted to JSON, transmitted, reconstructed from JSON and applied to `State` instances.\r\n\r\nAll deltas have the following properties\r\n\r\n```Javascript\r\n// The delta sequence number. These will be generated consecutively by the engine\r\n// for successful operations. As such they will not be synchronized with operation sequence\r\n// numbers due to the possibility of operations throwing errors\r\nvar sequence = delta.sequence;\r\n\r\n// The operation instance as supplied to the `apply` method\r\nvar operation = delta.operation;\r\n\r\n// Additional state change information in a format specific to the operation type\r\nvar result = delta.result;\r\n\r\n```\r\n\r\n#### `JSON.stringify`\r\n\r\nDeltas can be converted to and from JSON\r\n\r\n```Javascript\r\nvar json = JSON.stringify(delta);\r\nvar delta = new Delta({\r\n  json: json\r\n});\r\n\r\n// OR\r\n\r\nvar json = JSON.stringify(delta);\r\nvar delta = new Delta({\r\n  exported: JSON.parse(json)\r\n});\r\n```\r\n\r\n### `Operation`\r\n\r\n```javascript\r\nvar Operation = require('currency-market').Operation;\r\n```\r\n\r\n`Operation` instances are submitted to `Engine` instances to apply operations. They can be converted to JSON, transmitted and reconstructed from JSON\r\n\r\nAll operations follow this pattern\r\n\r\n```Javascript\r\nvar operation = new Operation({\r\n  // Application specified reference that is returned untouched with the operation details included in the delta.\r\n  // Care should be taken to ensure that this too can be converted to and from JSON\r\n  reference: '550e8400-e29b-41d4-a716-446655440000',\r\n  // The ID of the account submitting the operation\r\n  account: 'Peter',\r\n  // The operation details, the name of this property will determine the type of the operation\r\n  // and what additional fields need to be supplied\r\n  operationType: {\r\n    // Operation parameters\r\n    ...\r\n  }\r\n});\r\n```\r\n\r\n#### `accept` method\r\n\r\nOperations must be accepted before they can be applied to an `Engine` instance to ensure they are associated with a sequence number and a timestamp\r\n\r\n```Javascript\r\noperation.accept({\r\n  // The operation sequence number. These must be consecutive for consecutive operations\r\n  sequence: 123456,\r\n  // The timestamp for the operation as a Unix time since epoch in milliseconds\r\n  timestamp: 1371737390976\r\n});\r\n```\r\n\r\n#### `deposit` operation\r\n\r\nDeposit funds into an account\r\n\r\n```Javascript\r\nvar operation  = new Operation({\r\n  reference: '550e8400-e29b-41d4-a716-446655440000',\r\n  account: 'Peter',\r\n  // deposit 1000 Euros to account ID 'Peter'\r\n  deposit: {\r\n    currency: 'EUR',\r\n    amount: new Amount('1000')\r\n  }\r\n});\r\n\r\n// On successful application the `delta.result` will have the following fields\r\n\r\n// The new level of funds in the deposited currency as an `Amount` instance\r\nvar funds = delta.result.funds\r\n```\r\n\r\n#### `withdraw` operation\r\n\r\nWithdraw funds from an account\r\n\r\n```Javascript\r\nvar operation  = new Operation({\r\n  reference: '550e8400-e29b-41d4-a716-446655440000',\r\n  account: 'Peter',\r\n  // withdraw 1000 Euros from account ID 'Peter'\r\n  withdraw: {\r\n    currency: 'EUR',\r\n    amount: new Amount('1000')\r\n  }\r\n});\r\n\r\n// On successful application the `delta.result` will have the following fields\r\n\r\n// The new level of funds in the deposited currency as an `Amount` instance\r\nvar funds = delta.result.funds\r\n```\r\n\r\n#### `submit` operation\r\n\r\nSubmit orders to the market. Both bid and offer orders can be submitted and follow this pattern\r\n\r\n```Javascript\r\nvar operation  = new Operation({\r\n  reference: '550e8400-e29b-41d4-a716-446655440000',\r\n  account: 'Peter',\r\n  // Place a bid order for 10 BTC offering 100 Euros per BTC\r\n  submit: {\r\n    // order parameters\r\n    ...\r\n  }\r\n});\r\n\r\n// On successful application the `delta.result` will have the following fields\r\n\r\n// The new level of locked funds in the order's offer currency\r\nvar lockedFunds = delta.result.lockedFunds\r\n\r\n// Note that only one of `nextHigherOrderSequence` or `trades` will be set\r\n\r\n// If the order is not at the top of the order book then the sequence number\r\n// of the next order above it is returned. This is a hint to optimize the\r\n// insertion of the order into a `State` instance\r\nvar nextHigherOrderSequence = delta.result.nextHigherOrderSequence;\r\n\r\n// If the order was inserted at the top of the order book then an array of trades\r\n// will be returned. This array will still be set, but will be empty, if no actual \r\n// trades were made\r\n//\r\n// Note that the price at which any trade was executed will be given by the bid or\r\n// offer price associated with the `right` order and that the volume traded in each\r\n// currency is most easily referenced by the debit amounts associated with the `left`\r\n// and `right` accounts in their respective order's offer currencies\r\nvar trades = delta.result.trades;\r\n\r\n  // `left` gives the changes to be applied to the order that was submitted and the\r\n  // account that submitted it\r\n  var left = trades[0].left;\r\n\r\n    // Only one of `left` or `right` will have a remainder and this\r\n    // signals the amount of the order that has not yet been executed.\r\n    // When no remainder is specified it signals that the order was\r\n    // completely executed. It is possible that neither `left` nor `right`\r\n    // will have a remainder if they completely satisfy each other\r\n    var remainder = left.remainder;\r\n\r\n      // The remaining bidAmount on the order\r\n      var bidAmount = remainder.bidAmount;\r\n\r\n      // The remaining offerAmount on the order\r\n      var offerAmount = remainder.offerAmount;\r\n\r\n    // The transaction fields signal by how much the account balances have changed\r\n    // and how much commission was applied\r\n    var transaction = left.transaction;\r\n\r\n      // The changes applied to the balance being debited\r\n      var debit = transaction.debit;\r\n\r\n        // The amount of the order's offer currency debited from the account\r\n        var amount = debit.amount;\r\n\r\n        // The new level of funds in the debited currency\r\n        var funds = debit.funds;\r\n\r\n        // The new level of locked funds in the debited currency\r\n        var lockedFunds = debit.lockedFunds;\r\n\r\n      // The changes applied to the balances being credited\r\n      var credit = transaction.credit;\r\n\r\n        // The amount of the order's bid currency credited to the account\r\n        var amount = credit.amount;\r\n\r\n        // The new level of funds in the credited currency\r\n        var funds = credit.funds;\r\n\r\n        // If the engine was instantiated with commission then the commission\r\n        // field will be set\r\n        var commission = credit.commission;\r\n\r\n          // The amount of the order's bid currency credited to the commission account\r\n          var amount = commission.amount;\r\n\r\n          // The new level of funds in the order's bid currency in the commission account\r\n          var funds = commission.funds;\r\n\r\n          // The reference associated with the commission calculation\r\n          var reference = commission.reference;\r\n\r\n  // `right` gives the changes to be applied to the order that was matched and the\r\n  // account that submitted it. This order will always be the order that is currently\r\n  // at the top of the opposing order book to that which the submitted order was added.\r\n  // The fields that can be set are the same as for `left`\r\n  var right = trades[0].right;\r\n```\r\n\r\n##### Bid orders\r\n\r\n```Javascript\r\nvar operation  = new Operation({\r\n  reference: '550e8400-e29b-41d4-a716-446655440000',\r\n  account: 'Peter',\r\n  // Place a bid for 10 BTC offering 100 Euros per BTC\r\n  submit: {\r\n    bidCurrency: 'BTC',\r\n    offerCurrency: 'EUR',\r\n    bidPrice: new Amount('100'),\r\n    bidAmount: new Amount('10')\r\n  }\r\n});\r\n```\r\n\r\n##### Offer orders\r\n\r\n```Javascript\r\nvar operation  = new Operation({\r\n  reference: '550e8400-e29b-41d4-a716-446655440000',\r\n  account: 'Peter',\r\n  // Place an offer of 1000 EUR bidding 0.01 BTC per EUR\r\n  submit: {\r\n    bidCurrency: 'BTC',\r\n    offerCurrency: 'EUR',\r\n    offerPrice: new Amount('0.01'),\r\n    offerAmount: new Amount('1000')\r\n  }\r\n});\r\n```\r\n\r\n#### `cancel` operation\r\n\r\nOrders can be cancelled using the cancel operation.\r\n\r\n```Javascript\r\nvar operation  = new Operation({\r\n  reference: '550e8400-e29b-41d4-a716-446655440000',\r\n  account: 'Peter',\r\n  // Cancel the order submitted by acount ID 'Peter' with operation sequence 615368 \r\n  cancel: {\r\n    sequence: 615368\r\n  }\r\n});\r\n\r\n// On successful application the `delta.result` will have the following fields\r\n\r\n// The new level of locked funds in the order's offer currency\r\nvar lockedFunds = delta.result.lockedFunds;\r\n```\r\n\r\n#### `JSON.stringify`\r\n\r\nOperations can be converted to and from JSON\r\n\r\n```Javascript\r\nvar json = JSON.stringify(operation);\r\nvar operation = new Operation({\r\n  json: json\r\n});\r\n\r\n// OR\r\n\r\nvar json = JSON.stringify(operation);\r\nvar operation = new Operation({\r\n  exported: JSON.parse(json)\r\n});\r\n```\r\n\r\n### `State`\r\n\r\n```javascript\r\nvar State = require('currency-market').State;\r\n```\r\n\r\n`State` instances provide simplified access to a market state. They do not contain the logic for matching orders but do accept `Engine` generated deltas to keep them synchronized with `Engine` instances\r\n\r\n#### Constructor\r\n\r\n```javascript\r\n// instantiate a state\r\nvar state = new State({\r\n  commission:\r\n    // Note that the commission acount name should match the commission\r\n    // acount name from the engine to which this state will be synchronised\r\n    account: 'commission'\r\n});\r\n\r\n// instantiate a state from JSON stringified engine\r\nvar state = new State({\r\n  commission:\r\n    account: 'commission'\r\n  json: JSON.stringify(engine)\r\n});\r\n```\r\n\r\n#### `apply` method\r\n\r\nThe `apply` method is used to apply deltas generated by `Engine` instances. The delta will be applied synchronously and errors may be thrown\r\n\r\n```Javascript\r\ntry {\r\n  state.apply(delta);\r\n} catch(error) {\r\n  // possible errors include out of sequence deltas \r\n  ...\r\n}\r\n```\r\n\r\n#### `JSON.stringify`\r\n\r\nStates can be converted to and from JSON\r\n\r\n```Javascript\r\nvar json = JSON.stringify(state);\r\nvar state = new State({\r\n  json: json\r\n});\r\n\r\n// OR\r\n\r\nvar json = JSON.stringify(state);\r\nvar state = new State({\r\n  exported: JSON.parse(json)\r\n});\r\n```\r\n\r\n#### `getBook` method\r\n\r\nThe `getBook` method gives access to the order books keyed by bid and offer currency. Each book is an `Array` of orders sorted as they will be matched for execution\r\n\r\n```Javascript\r\nvar book = state.getBook({\r\n  bidCurrency: 'BTC',\r\n  offerCurrency: 'EUR'\r\n});\r\n\r\n// Get the top of the order book\r\nvar order = book[0];\r\n\r\n// All orders have the following fields\r\n//\r\n// The sequence number\r\nvar sequence = order.sequence;\r\n// The timestamp in milliseconds since epoch\r\nvar timestamp = order.timestamp;\r\n// The account ID associated with the order\r\nvar account = order.account;\r\n// The offer currency\r\nvar offerCurrency = order.offerCurrency;\r\n// The bid currency\r\nvar bidCurrency = order.bidCurrency;\r\n\r\n// Bid orders have the following additional fields\r\n\r\n// The bid price as an `Amount` instance\r\nvar bidPrice = order.bidPrice;\r\n// The bid amount as an `Amount` instance\r\nvar bidAmount = order.bidAmount;\r\n\r\n// Offer orders have the following additional fields\r\n\r\n// The offer price as an `Amount` instance\r\nvar offerPrice = order.offerPrice;\r\n// The offer amount as an `Amount` instance\r\nvar offerAmount = order.offerAmount;\r\n```\r\n\r\n#### `getAccount` method\r\n\r\nThe `getAccount` method gives access to the accounts as instances of `Account` by account ID\r\n\r\n```Javascript\r\nvar account = state.getAccount('Peter');\r\n```\r\n\r\n##### `Account`\r\n\r\nThe `Account` class gives access to the properties of an account\r\n\r\n###### `orders` property\r\n\r\nThis is a collection of active orders keyed by sequence number (NB. it is an `Object` and not an `Array`)\r\n\r\n```Javascript\r\nvar order = account.orders[5];\r\n```\r\n\r\nThe orders are the same instances as those in the books retrieved with the `getBook` method\r\n\r\n###### `getBalance` method\r\n\r\nThe `getBalance` method gives access to the balances of funds as instances of `Balance` associated with an account, keyed by currency\r\n\r\n```Javascript\r\nvar balance = account.getBalance('EUR');\r\n```\r\n\r\n##### `Balance`\r\n\r\nThe `Balance` class gives access to the levels of funds and locked funds (when orders are outstanding) as `Amount` instances\r\n\r\n```Javascript\r\nvar funds = balance.funds;\r\nvar lockedFunds = balance.lockedFunds;\r\n```\r\n\r\n## Roadmap\r\n\r\n- When applying a delta to a state we should get back a flag to say whether the delta was applied so that we know if the delta was old or not\r\n- The state should emit an event when a deposit is recorded so that it can also be recorded in more permanent storage\r\n- The state should record the last N deposits for each account so that these can be quickly queried without looking at permanent storage\r\n- The state should emit an event when a withdrawal is recorded so that it can also be recorded in more permanent storage\r\n- The state should record the last N withdrawals for each account so that these can be quickly queried without looking at permanent storage\r\n- The state should emit an event when a trade is recorded so that it can also be recorded in more permanent storage\r\n- The state should record the last N trades for each account so that these can be quickly queried without looking at permanent storage\r\n- Setting commission for an account/balance/globally should be an operation so that changes can be reflected in the history\r\n  - Commission types should be predefined and parameterized\r\n  - The commission account should be fixed?\r\n- Instant orders\r\n  - Market orders\r\n    - zero priced offers that are rejected if they cannot be completely filled by the market\r\n      - if a zero price is used then any remainder cannot be left on the book as it may cause a division by zero\r\n      - partial fills could be executed as long as the remainder is instantly cancelled\r\n  - Fill or Kill limit orders?\r\n    - will be tougher (less efficient) than market orders as an average price will have to be calculated?\r\n- Pluggable rounding policies\r\n  - Amount factory required?\r\n  - currently we only round down debits and credits so as not to debit more funds than available\r\n    - current rounding is done to an arbitrary scale of 25\r\n- Separate transaction IDs and sequence IDs\r\n  - Use sequence numbers instead of transaction IDs so the engine knows that it hasn't missed anything?\r\n  - Use both sequence numbers and transaction IDs?\r\n    - transaction IDs provide replayability\r\n      - have to be unique forever (uuid?)\r\n    - sequence numbers provide integrity checking\r\n      - may get unweildy if required to be unique forever and could loop instead\r\n      - where are sequence numbers assigned?\r\n        - This implies a state somewhere and a centralised component (bottleneck?)\r\n- Protection against attacks?\r\n  - entering orders that satisfy each other\r\n  - entering tiny orders\r\n  - should this be in another layer?\r\n\r\n## Contributing\r\n\r\nIn lieu of a formal styleguide, take care to maintain the existing coding style. Add unit tests for any new or changed functionality.\r\n\r\nRun tests with\r\n\r\n```\r\n$ npm test\r\n```\r\n\r\nRun performance tests with\r\n\r\n```\r\n$ npm run-script perf\r\n```\r\n\r\n## License\r\nCopyright &copy; 2013 Peter Halliday  \r\nLicensed under the MIT license.","readmeFilename":"README.md","_id":"currency-market@0.4.2","dist":{"shasum":"3b33a6d5c22e71da10813af5fc5f58da30fbcfba","tarball":"https://registry.npmjs.org/currency-market/-/currency-market-0.4.2.tgz","integrity":"sha512-8OCKfNMwp+ZYJNErmO0X9/mr7weGtQ57t4ZmAlGDF3JQWbMT+56B8EHmYEgUkPPUTRQ/zZTEycjhjlHVmxHW0Q==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCw2MkMSo1nNC94j0atS/QEVNiZrobWogGshiaxcaqWkgIhAMsADYeGK9WACMxPji42cKKf/3LNYREtDvjCjVCEAB29"}]},"_from":".","_npmVersion":"1.3.2","_npmUser":{"name":"pghalliday","email":"pghalliday@gmail.com"},"maintainers":[{"name":"pghalliday","email":"pghalliday@gmail.com"}]}},"readme":"currency-market\n===============\n\nA synchronous implementation of a limit order based currency market\n\n## Features\n\n- Supports an arbitrary list of currencies\n- Synchronously executes trades as orders are added\n- Emits events when changes are made to the market\n\n## Installation\n\n```\nnpm install currency-market\n```\n\n## API\n\nAll functions complete synchronously and throw errors if they fail.\nEvents are made available for monitoring changes in the market.\n\n```javascript\nvar CurrencyMarket = require('currency-market');\n\n// instantiate a market\nvar currencyMarket = new CurrencyMarket({\n  currencies: [\n    'EUR',\n    'USD',\n    'BTC'\n  ]\n});\n\n// register for events\ncurrencyMarket.on('account', function(account) {\n  console.log(account);\n});\ncurrencyMarket.on('deposit', function(deposit) {\n  console.log(deposit);\n});\ncurrencyMarket.on('withdrawal', function(withdrawal) {\n  console.log(withdrawal);\n});\ncurrencyMarket.on('order', function(order) {\n  console.log(order);\n});\ncurrencyMarket.on('cancellation', function(order) {\n  console.log(order);\n});\ncurrencyMarket.on('trade', function(trade) {\n  console.log(trade);\n});\n\n// add accounts\ncurrencyMarket.register({\n  id: 'Peter'\n});\ncurrencyMarket.register({\n  id: 'Paul'\n});\n\n// make deposits\ncurrencyMarket.deposit({\n  account: 'Peter',\n  currency: 'EUR',\n  amount: '5000'\n});\ncurrencyMarket.deposit({\n  account: 'Paul',\n  currency: 'BTC',\n  amount: '5000'\n});\n\n// make withdrawals\ncurrencyMarket.withdraw({\n  account: 'Peter',\n  currency: 'EUR',\n  amount: '1000'\n});\ncurrencyMarket.withdraw({\n  account: 'Paul',\n  currency: 'BTC',\n  amount: '1000'\n});\n\n// submit orders\ncurrencyMarket.submit({\n  id: '1',\n  timestamp: '1366758222',\n  account: 'Peter',\n  bidCurrency: 'BTC',\n  offerCurrency: 'EUR',\n  bidPrice: '2',\n  bidAmount: '500'\n});\ncurrencyMarket.submit({\n  id: '2',\n  timestamp: '1366758245',\n  account: 'Peter',\n  bidCurrency: 'BTC',\n  offerCurrency: 'EUR',\n  bidPrice: '1',\n  bidAmount: '2000'\n});\ncurrencyMarket.submit({\n  id: '3',\n  timestamp: '1366758256',\n  account: 'Paul',\n  bidCurrency: 'EUR',\n  offerCurrency: 'BTC',\n  offerPrice: '2',\n  offerAmount: '250'\n});\ncurrencyMarket.submit({\n  id: '4',\n  timestamp: '1366758268',\n  account: 'Paul',\n  bidCurrency: 'EUR',\n  offerCurrency: 'BTC',\n  offerPrice: '3',\n  offerAmount: '3000'\n});\n\n// cancel an order\ncurrencyMarket.cancel({\n  id: '1',\n  timestamp: '1366758222',\n  account: 'Peter',\n  bidCurrency: 'BTC',\n  offerCurrency: 'EUR',\n  bidPrice: '2',\n  bidAmount: '250'\n});\n\n// list all the active orders (keyed by id)\nconsole.log(currencyMarket.orders);\n\n// list all the active accounts (keyed by id)\nconsole.log(currencyMarket.accounts);\n\n// list all the active order books \nconsole.log(currencyMarket.books);\n\n// Get the top of an order book\nconsole.log(currencyMarket.books['EUR']['BTC'].highest);\nconsole.log(currencyMarket.books['BTC']['EUR'].highest);\n```\n\n## Roadmap\n\n- Instant orders (execute or cancel)\n- Pluggable rounding policies\n- Pluggable commission schemes\n\n## Contributing\n\nIn lieu of a formal styleguide, take care to maintain the existing coding style. Add unit tests for any new or changed functionality.\n\nThe CoffeeScript source is located in the `src/` directory and tests in the `test/` directory. Do not edit the contents of the `lib/` directory as this is compiled from the CoffeeScript source.\n\nBefore commiting run `npm test` to perform a clean compile of the source and run the tests. This ensures that everything commited is up to date and tested and allows people to `npm install` directly from the git repository (useful for integrating development branches, etc).\n\n## License\nCopyright (c) 2013 Peter Halliday  \nLicensed under the MIT license.","maintainers":[{"name":"pghalliday","email":"pghalliday@gmail.com"}],"time":{"modified":"2022-06-14T05:58:58.434Z","created":"2013-04-23T23:52:19.289Z","0.0.1":"2013-04-23T23:52:22.797Z","0.1.0":"2013-04-27T10:59:38.817Z","0.1.1":"2013-04-29T13:38:48.287Z","0.1.2":"2013-04-29T21:55:19.323Z","0.2.0":"2013-05-06T06:58:15.954Z","0.3.0":"2013-05-09T19:26:24.488Z","0.3.1":"2013-05-23T15:09:23.453Z","0.4.0":"2013-07-08T22:14:03.943Z","0.4.1":"2013-07-10T09:31:42.047Z","0.4.2":"2013-07-24T15:16:44.727Z"},"author":{"name":"Peter Halliday","email":"pghalliday@gmail.com","url":"http://stuffpetedoes.blogspot.nl/"},"repository":{"type":"git","url":"git://github.com/pghalliday/currency-market.git"}}