├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── __init__.py ├── apps ├── __init__.py ├── frauder │ └── main.py ├── mailer │ ├── __init__.py │ ├── main.py │ ├── mandrill.py │ ├── templates │ │ ├── customer-verification-submit-en.txt │ │ ├── order-execution-en.txt │ │ ├── password-reset-en.txt │ │ ├── welcome-en.txt │ │ ├── withdraw-cancelled-en.txt │ │ ├── withdraw-confirmation-bank-transfer-en.txt │ │ ├── withdraw-confirmation-bitcoin-en.txt │ │ └── your-account-has-been-verified-en.txt │ └── util.py ├── main.py ├── tests.py ├── trade │ ├── __init__.py │ ├── decorators.py │ ├── errors.py │ ├── execution.py │ ├── main.py │ ├── market_data_publisher.py │ ├── models.py │ ├── session.py │ ├── session_manager.py │ ├── tests │ │ ├── __init__.py │ │ └── test_model.py │ ├── trade_application.py │ ├── views.py │ └── zmq_client.py └── ws_gateway │ ├── __init__.py │ ├── deposit_hander.py │ ├── deposit_receipt_webhook_handler.py │ ├── instrument_helper.py │ ├── main.py │ ├── market_data_helper.py │ ├── models.py │ ├── process_deposit_handler.py │ ├── rest_api_handler.py │ ├── tests │ ├── __init__.py │ └── test_signals.py │ ├── util.py │ └── verification_webhook_handler.py ├── config ├── __init__.py ├── bitex.ini.example ├── bootstrap │ ├── __init__.py │ ├── bootstrap.ini │ ├── bootstrap.py │ └── demo.ini ├── init.d │ ├── blinktrade_api_receive │ ├── blinktrade_mailer │ ├── blinktrade_trade │ └── blinktrade_ws_gateway └── nginx.conf.example ├── db └── README ├── libs ├── __init__.py ├── bitcoinrpc │ ├── __init__.py │ └── authproxy.py ├── characters │ ├── .gitignore │ ├── AUTHORS │ ├── LICENSE │ ├── README.md │ ├── characters │ │ ├── __init__.py │ │ ├── charset.py │ │ └── hex.py │ └── setup.py ├── coinkit │ ├── .gitignore │ ├── AUTHORS │ ├── LICENSE │ ├── README.md │ ├── coinkit │ │ ├── __init__.py │ │ ├── b58check.py │ │ ├── entropy.py │ │ ├── keypair.py │ │ ├── passphrase.py │ │ ├── utils.py │ │ ├── wallet.py │ │ └── words.py │ ├── requirements.txt │ ├── setup.py │ └── tests │ │ └── unit_tests.py ├── jsonrpc │ ├── __init__.py │ ├── _tests │ │ ├── __init__.py │ │ ├── test_cgiwrapper.py │ │ ├── test_json.py │ │ ├── test_modpywrapper.py │ │ ├── test_proxy.py │ │ └── test_serviceHandler.py │ ├── cgiwrapper.py │ ├── json.py │ ├── modpywrapper.py │ ├── proxy.py │ └── serviceHandler.py ├── onetimepass │ └── __init__.py ├── pusherclient │ ├── __init__.py │ ├── channel.py │ └── connection.py ├── pyboleto │ ├── __init__.py │ ├── bank │ │ ├── __init__.py │ │ ├── bancodobrasil.py │ │ ├── banrisul.py │ │ ├── bradesco.py │ │ ├── caixa.py │ │ ├── hsbc.py │ │ ├── itau.py │ │ ├── real.py │ │ └── santander.py │ ├── data.py │ ├── media │ │ ├── logo_bancobradesco.jpg │ │ ├── logo_bancocaixa.jpg │ │ ├── logo_bancohsbc.jpg │ │ ├── logo_bancoreal.jpg │ │ ├── logo_banrisul.jpg │ │ ├── logo_bb.jpg │ │ ├── logo_itau.jpg │ │ └── logo_santander.jpg │ └── pdf.py ├── six.py ├── websocket.py └── ws4py │ ├── __init__.py │ ├── client │ ├── __init__.py │ ├── geventclient.py │ ├── threadedclient.py │ └── tornadoclient.py │ ├── compat.py │ ├── exc.py │ ├── framing.py │ ├── manager.py │ ├── messaging.py │ ├── server │ ├── __init__.py │ ├── cherrypyserver.py │ ├── geventserver.py │ ├── wsgirefserver.py │ └── wsgiutils.py │ ├── streaming.py │ ├── utf8validator.py │ └── websocket.py ├── logs └── README ├── requirements.txt ├── static ├── 404.html ├── 422.html ├── 500.html ├── admin.html ├── bitcointoyou.html ├── blinktrade.html ├── chart.html ├── coinstra.html ├── comprabitcoin.html ├── cryptos.html ├── css │ ├── Dialog.css │ ├── bootstrap-combined.min.css │ ├── bootstrap-docs.css │ ├── default.uni-form.css │ ├── docs.css │ ├── escrow_style.css │ ├── font-awesome.css │ ├── font-awesome.min.css │ ├── fuelux.css │ ├── sticky.css │ └── style.css ├── demo.html ├── demostracion.html ├── escrow.html ├── font │ ├── FontAwesome.otf │ ├── fontawesome-webfont.eot │ ├── fontawesome-webfont.svg │ ├── fontawesome-webfont.ttf │ └── fontawesome-webfont.woff ├── guaranibitcoin.html ├── guaranibitcoin_tos.html ├── images │ ├── UrduBit.png │ ├── UrduBitBeta.png │ ├── UrduBitFront.png │ ├── UrduBitFrontBeta.png │ ├── bitcoin-center-black.png │ ├── bitcoin-center.png │ ├── bitcoin32.png │ ├── bitcoin530.png │ ├── bitcoin64.png │ ├── bitex.png │ ├── bitex2.png │ ├── blinktrade-demo.png │ ├── blinktrade.png │ ├── coinstrabeta.png │ ├── coinstrabeta2.png │ ├── comprabitcoin2.png │ ├── cryptos-white.png │ ├── cryptos.png │ ├── favicon.ico │ ├── guaranibitcoinbeta.png │ ├── guaranibitcoinbeta2.png │ ├── preload.gif │ ├── screenshot.png │ ├── surbitcoin.png │ ├── surbitcoin_logo.png │ ├── surbitcoin_logo_ven.png │ ├── surbitcoinbeta.png │ ├── surbitcoinbeta2.png │ └── ubuntubitx-logo.png ├── img │ ├── bitcoin_wallpaper_libertas_aequitas_vertas_2-copie.png │ ├── glyphicons-halflings-white.png │ ├── glyphicons-halflings.png │ ├── logo.png │ └── screenshot.png ├── js │ ├── bitex.compiled.pt_BR.js │ ├── bitex_app_admin.compiled.pt_BR.js │ ├── bitex_app_bitex.compiled.pt_BR.js │ ├── bitex_app_markets.compiled.en_US.js │ ├── datagrid.js │ ├── externs │ │ └── parsley.js │ ├── parsley-standalone.min.js │ ├── parsley.extend.min.js │ ├── parsley.min.js │ ├── sticky.js │ └── sticky.min.js ├── satoshi_square.html ├── surbitcoin.html ├── surbitcoin_maintenance.html ├── surbitcoin_tos.html ├── tos.html ├── ubuntubitx.html └── urdubit.html └── tools ├── __init__.py ├── arbitrage ├── __init__.py ├── arbitrage.ini ├── arbitrator.py ├── b2u.py ├── basebit.py ├── bitfinex.py ├── bitinvest.py ├── bitstamp.py ├── client.py ├── hitbtc.py ├── itbit.py ├── mb.py ├── order_book_processor.py └── util.py └── latency_analyser └── gw_latency_analyser.py /.gitignore: -------------------------------------------------------------------------------- 1 | *.py[cod] 2 | 3 | # C extensions 4 | *.so 5 | 6 | # Packages 7 | *.egg 8 | *.egg-info 9 | dist 10 | build 11 | eggs 12 | parts 13 | bin 14 | var 15 | sdist 16 | develop-eggs 17 | .installed.cfg 18 | lib 19 | lib64 20 | 21 | # Installer logs 22 | pip-log.txt 23 | 24 | # logs 25 | *.log 26 | 27 | # Unit test / coverage reports 28 | .coverage 29 | .tox 30 | nosetests.xml 31 | 32 | # Translations 33 | *.mo 34 | 35 | # Mr Developer 36 | .mr.developer.cfg 37 | .project 38 | .pydevproject 39 | .idea 40 | 41 | # OS files 42 | .DS_Store 43 | *.sqlite 44 | jsdev/bitex/templates/templates.soy.js 45 | static/satoshi_square.bkp.html 46 | static/js/bitex_app_satoshi_square.compiled.en_US.js 47 | static/js/bitex_app_blink_trade.compiled.en_US.js 48 | static/js/bitex_app_blink_trade.compiled.es.js 49 | static/js/bitex_app_merchant.compiled.en_US.js 50 | *.soy.js 51 | logs/ 52 | *.iml 53 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: python 2 | python: 3 | - "2.7" 4 | # command to install dependencies 5 | install: 6 | - "pip install -r requirements.txt" 7 | jdk: 8 | - openjdk7 9 | script: 10 | - cd jsdev 11 | - ./build_release.sh 12 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | #This documentation is outdated. 2 | You must be a Senior Python Developer in order to understand what is going on. Don't try to run an exchange without an expert. 3 | 4 | BlinkTrade 5 | ===== 6 | 7 | BlinkTrade - Open Source Exchange Platform 8 | 9 | [How to install on Google Compute Engine](https://github.com/blinktrade/bitex/wiki/HOW-TO-DEPLOY-BLINKTRADE-ON-GOOGLE-COMPUTE-ENGINE) 10 | 11 | [![Build Status](https://travis-ci.org/blinktrade/bitex.svg?branch=master)](https://travis-ci.org/blinktrade/bitex) 12 | 13 | #Get Started 14 | 15 | ``` 16 | $ pip install -r requirements.txt 17 | ``` 18 | 19 | #Build and Run 20 | 21 | Download and install the pyblinktrade package from https://github.com/blinktrade/pyblinktrade 22 | 23 | ``` 24 | cd ~ 25 | cd pyblinktrade 26 | chmod +x setup.py 27 | sudo ./setup.py install 28 | ``` 29 | 30 | Download and install the frontend project from https://github.com/blinktrade/frontend.git 31 | 32 | ``` 33 | $ cd ./jsdev 34 | $ ./build_release.sh # Or ./build_release.bat [Windows] 35 | 36 | $ ./apps/trade/main.py 37 | $ ./apps/ws_gateway/main.py 38 | $ ./apps/mailer/main.py 39 | ``` 40 | 41 | # Applications - Trade 42 | Matching engine and the core of the BitEx platform 43 | 44 | # Applications - Ws Gateway 45 | The HTTP/WebSocket gateway is based on Tornado. It relays HTTP or websocket API 46 | requests to the trade engine in order to place orders or fetching market data. 47 | 48 | # Applications - Mailer 49 | The mailing application... sends mail. To that end, 50 | it uses Mailchimp's transaction email solution, Mandrill. 51 | 52 | E-mail templates are stored under the templates/ dir, 53 | and which template to use (and the data to fill it out) 54 | are supplied by listening on the zeromq socket. 55 | 56 | # Translating 57 | 58 | ``` 59 | cd ./jsdev/tools 60 | $ python extract_messages.py > /tmp/file_to_be_translated.xml 61 | 62 | # translate the xml 63 | $ cp /tmp/file_to_be_translated.xml ./jsdev/translations/pt_BR.xtb 64 | 65 | # edit the build_release.sh to include the translated version. 66 | $ vi ./jsdev/build_release.sh 67 | 68 | $ ./jsdev/build_release.sh # recompile the application using the translated file 69 | 70 | # translated the html static page 71 | # vi ./static/statoshi_square.html 72 | ``` 73 | 74 | #Why the name of the folder is Bitex ? 75 | 76 | Bitex stands for Bitcoin EXchange and it was the first that we came up it name of our platform, by mid 2014 a company called bitex.la was formed in Argentina and we were forced to change our name, this source code it is not related in any form to bitex.la. 77 | 78 | ## Contributing 79 | 80 | 1. Fork it! 81 | 2. Create your feature branch: `git checkout -b my-new-feature` 82 | 3. Commit your changes: `git commit -am 'Add some feature'` 83 | 4. Push to the branch: `git push origin my-new-feature` 84 | 5. Submit a pull request 85 | 86 | #License 87 | 88 | **Code released under [the GNU GPL license](https://github.com/pinhopro/bitex/blob/master/LICENSE).** 89 | 90 | Copyright 2014 BitEx, LTDA. BitEx is a trademark maintained by BitEx, LTDA. 91 | 92 | **VIOLATORS OF THE GNU GPL LICENSE WILL BE PROSECUTED TO THE FULL EXTENT OF THE LAW** 93 | **FREE SOFTWARE FOR FREE PEOPLE** 94 | -------------------------------------------------------------------------------- /__init__.py: -------------------------------------------------------------------------------- 1 | __author__ = 'rodrigo' 2 | -------------------------------------------------------------------------------- /apps/__init__.py: -------------------------------------------------------------------------------- 1 | __author__ = 'rodrigo' 2 | -------------------------------------------------------------------------------- /apps/mailer/__init__.py: -------------------------------------------------------------------------------- 1 | __author__ = 'rodrigo' 2 | -------------------------------------------------------------------------------- /apps/mailer/templates/customer-verification-submit-en.txt: -------------------------------------------------------------------------------- 1 | template-name=customer-verification-submit-en 2 | template-slug=customer-verification-submit-en 3 | temaplate-defaults-from-address=support@blinktrade.zendesk.com 4 | template-defaults-from-name=BlinkTrade 5 | template-defaults-subject=Your account has been sent for verification 6 | 7 | Hi *|username|*,
8 |
9 | Your data has been sent, we will validate your account shortly. 10 | .
11 |
12 | Thank you
13 | BlinkTrade 14 | -------------------------------------------------------------------------------- /apps/mailer/templates/order-execution-en.txt: -------------------------------------------------------------------------------- 1 | template-name=order-execution-en 2 | template-slug=order-execution-en 3 | temaplate-defaults-from-address=support@blinktrade.zendesk.com 4 | template-defaults-from-name=BlinkTrade 5 | template-defaults-subject=Your order *|order_id|* was executed. 6 | 7 | Hi *|username|*,
8 |
9 | Your order was executed.
10 |
11 | Number: *|order_id|*
12 | Ejecuciono Number: *|trade_id|*
13 | Command executed in: *|executed_when|* (UTC)
14 | Quantity: *|qty|*
15 | Price: *|price|*
16 | Total: *|total|*
17 |
18 | Thank you
19 | BlinkTrade
-------------------------------------------------------------------------------- /apps/mailer/templates/password-reset-en.txt: -------------------------------------------------------------------------------- 1 | template-name=password-reset-en 2 | template-slug=password-reset-en 3 | temaplate-defaults-from-address=support@blinktrade.zendesk.com 4 | template-defaults-from-name=BlinkTrade 5 | template-defaults-subject=Instructions to reset your password 6 | 7 | Hi *|username|*
8 |
9 | Enter the following security code to reset your password. *|Token|*
10 |
11 | Thank you
12 | BlinkTrade
-------------------------------------------------------------------------------- /apps/mailer/templates/welcome-en.txt: -------------------------------------------------------------------------------- 1 | template-name=welcome-en 2 | template-slug=welcome-en 3 | temaplate-defaults-from-address=support@blinktrade.zendesk.com 4 | template-defaults-from-name=BlinkTrade 5 | template-defaults-subject=Hi *|USERNAME|*, Welcome to BlinkTrade 6 | 7 | Hi *|USERNAME|*
8 |  
9 | Welcome to BlinkTrade
10 |  
11 | Thank you
12 | BlinkTrade
-------------------------------------------------------------------------------- /apps/mailer/templates/withdraw-cancelled-en.txt: -------------------------------------------------------------------------------- 1 | template-name=withdraw-cancelled-en 2 | template-slug=withdraw-cancelled-en 3 | temaplate-defaults-from-address=support@blinktrade.zendesk.com 4 | template-defaults-from-name=BlinkTrade 5 | template-defaults-subject=Your withdrawal request *|amount|* *|currency|* was canceled 6 | 7 | Hi *|username|*
8 |
9 | Your withdrawal request made ​​on *|created|* UTC to the value of *|amount|* *|currency|* was canceled for the following reason:
10 |
11 | Error code: *|reason_id|*
12 | Description: *|reason|*
13 |
14 | Thank you
15 | BlinkTrade -------------------------------------------------------------------------------- /apps/mailer/templates/withdraw-confirmation-bank-transfer-en.txt: -------------------------------------------------------------------------------- 1 | template-name=withdraw-confirmation-bank-transfer-en 2 | template-slug=withdraw-confirmation-bank-transfer-en 3 | temaplate-defaults-from-address=support@blinktrade.zendesk.com 4 | template-defaults-from-name=BlinkTrade 5 | template-defaults-subject=Confirm the withdraw order *|currency|* 6 | 7 | Hi *|username|*
8 |
9 | This is your confirmation code
10 | *|confirmation_token|*
11 |
12 | Attention this confirmation code is valid to confirm your withdraw order
13 | Facts: *|created|*
UTC 14 | Value: *|amount|*
15 | Currency: *|currency|*
16 | Destination: *|wallet|*
17 |
18 | Attention:
19 | This procedure is necessary to increase the security of the system, because if your BlinkTrade password is compromised, the attacker does not make the order Put Stone retirement bitcoins without access to their email account.
20 |
21 | Thank you
-------------------------------------------------------------------------------- /apps/mailer/templates/withdraw-confirmation-bitcoin-en.txt: -------------------------------------------------------------------------------- 1 | template-name=withdraw-confirmation-bitcoin-en 2 | template-slug=withdraw-confirmation-bitcoin-en 3 | temaplate-defaults-from-address=support@blinktrade.zendesk.com 4 | template-defaults-from-name=BlinkTrade 5 | template-defaults-subject=Confirm the withdraw order *|currency|* 6 | 7 | Hi *|username|*
8 |
9 | This is your confirmation code
10 | *|confirmation_token|*
11 |
12 | Attention this confirmation code is valid to confirm your withdraw order
13 | Facts: *|created|*
UTC 14 | Value: *|amount|*
15 | Currency: *|currency|*
16 | Destination: *|wallet|*
17 |
18 | Attention:
19 | This procedure is necessary to increase the security of the system, because if your BlinkTrade password is compromised, the attacker does not make the order Put Stone retirement bitcoins without access to their email account.
20 |
21 | Thank you
-------------------------------------------------------------------------------- /apps/mailer/templates/your-account-has-been-verified-en.txt: -------------------------------------------------------------------------------- 1 | template-name=your-account-has-been-verified-en 2 | template-slug=your-account-has-been-verified-en 3 | temaplate-defaults-from-address=support@blinktrade.zendesk.com 4 | template-defaults-from-name=BlinkTrade 5 | template-defaults-subject=Your account has been verified 6 | 7 | Hi *|username|*,
8 |
9 | Your account has been verified.
10 |
11 | Thank you,
12 | BlinkTrade -------------------------------------------------------------------------------- /apps/mailer/util.py: -------------------------------------------------------------------------------- 1 | from smtplib import SMTP 2 | from email.MIMEText import MIMEText 3 | from email.Header import Header 4 | from email.Utils import parseaddr, formataddr 5 | 6 | 7 | def send_email(sender, recipient, subject, body, content_type='plain'): 8 | """Send an email. 9 | 10 | All arguments should be Unicode strings (plain ASCII works as well). 11 | 12 | Only the real name part of sender and recipient addresses may contain 13 | non-ASCII characters. 14 | 15 | The email will be properly MIME encoded and delivered though SMTP to 16 | localhost port 25. This is easy to change if you want something different. 17 | 18 | The charset of the email will be the first one out of US-ASCII, ISO-8859-1 19 | and UTF-8 that can represent all the characters occurring in the email. 20 | """ 21 | 22 | # Header class is smart enough to try US-ASCII, then the charset we 23 | # provide, then fall back to UTF-8. 24 | header_charset = 'ISO-8859-1' 25 | 26 | # We must choose the body charset manually 27 | for body_charset in 'US-ASCII', 'ISO-8859-1', 'UTF-8': 28 | try: 29 | body.encode(body_charset) 30 | except UnicodeError: 31 | pass 32 | else: 33 | break 34 | 35 | # Split real name (which is optional) and email address parts 36 | sender_name, sender_addr = parseaddr(sender) 37 | recipient_name, recipient_addr = parseaddr(recipient) 38 | 39 | # We must always pass Unicode strings to Header, otherwise it will 40 | # use RFC 2047 encoding even on plain ASCII strings. 41 | sender_name = str(Header(unicode(sender_name), header_charset)) 42 | recipient_name = str(Header(unicode(recipient_name), header_charset)) 43 | 44 | # Make sure email addresses do not contain non-ASCII characters 45 | sender_addr = sender_addr.encode('ascii') 46 | recipient_addr = recipient_addr.encode('ascii') 47 | 48 | # Create the message ('plain' stands for Content-Type: text/plain) 49 | msg = MIMEText(body.encode(body_charset), content_type, body_charset) 50 | msg['From'] = formataddr((sender_name, sender_addr)) 51 | msg['To'] = formataddr((recipient_name, recipient_addr)) 52 | msg['Subject'] = Header(unicode(subject), header_charset) 53 | 54 | try: 55 | # Send the message via SMTP to localhost:25 56 | smtp = SMTP("127.0.0.1") 57 | smtp.ehlo() 58 | smtp.sendmail(sender_addr, recipient, msg.as_string()) 59 | smtp.quit() 60 | except Exception as ex: 61 | pass 62 | -------------------------------------------------------------------------------- /apps/main.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import sys 4 | import os 5 | import ConfigParser 6 | import json 7 | import multiprocessing 8 | import time 9 | import logging 10 | import argparse 11 | from appdirs import site_config_dir 12 | from functools import partial 13 | 14 | from Queue import Queue 15 | from threading import Thread 16 | 17 | 18 | ROOT_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), "../")) 19 | sys.path.insert(0, os.path.join(ROOT_PATH, 'libs')) 20 | sys.path.insert(0, os.path.join(ROOT_PATH, 'apps')) 21 | 22 | from pyblinktrade.project_options import ProjectOptions 23 | 24 | 25 | def trade_instance(instance_name, project_options): 26 | from trade.trade_application import TradeApplication 27 | app = TradeApplication.instance() 28 | app.initialize(project_options, instance_name) 29 | app.run() 30 | 31 | 32 | def ws_gateway_instance(instance_name, project_options): 33 | from ws_gateway.main import run_application 34 | run_application(project_options, instance_name) 35 | 36 | def mailer_instance(instance_name, project_options): 37 | from mailer.main import run_application 38 | run_application(project_options, instance_name) 39 | 40 | 41 | def main(): 42 | parser = argparse.ArgumentParser(description="Blinktrade") 43 | parser.add_argument('-c', 44 | "--config", 45 | action="store", 46 | dest="config", 47 | help='Configuration file', type=str) 48 | arguments = parser.parse_args() 49 | 50 | 51 | candidates = [ os.path.join(site_config_dir('blinktrade'), 'bitex.ini'), 52 | os.path.expanduser('~/.blinktrade/bitex.ini'), 53 | arguments.config ] 54 | 55 | config = ConfigParser.SafeConfigParser() 56 | config.read( candidates ) 57 | 58 | processes = [] 59 | for section_name in config.sections(): 60 | project_options = ProjectOptions(config, section_name) 61 | if section_name[:5] == 'trade': 62 | p = multiprocessing.Process(name=section_name, target=partial(trade_instance,section_name, project_options ) ) 63 | elif section_name[:10] == 'ws_gateway': 64 | p = multiprocessing.Process(name=section_name, target=partial(ws_gateway_instance,section_name, project_options ) ) 65 | elif section_name[:6] == 'mailer': 66 | p = multiprocessing.Process(name=section_name, target=partial(mailer_instance,section_name, project_options ) ) 67 | else: 68 | raise RuntimeError("Invalid section name") 69 | processes.append(p) 70 | 71 | # start all sub processes 72 | for p in processes: 73 | p.daemon = True 74 | p.start() 75 | 76 | # wait for them to finish 77 | for p in processes: 78 | logging.debug('waiting %s', p.name ) 79 | p.join() 80 | 81 | 82 | if __name__ == '__main__': 83 | main() 84 | -------------------------------------------------------------------------------- /apps/tests.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import unittest 4 | 5 | from trade.tests import * 6 | from ws_gateway.tests import * 7 | 8 | if __name__ == '__main__': 9 | unittest.main() 10 | -------------------------------------------------------------------------------- /apps/trade/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | def get_now(timezone=None): 3 | import datetime 4 | return datetime.datetime.now(timezone) 5 | -------------------------------------------------------------------------------- /apps/trade/decorators.py: -------------------------------------------------------------------------------- 1 | from errors import * 2 | 3 | def login_required(func): 4 | def decorator(session,*args, **kwargs): 5 | if session.user is None : 6 | raise NotAuthorizedError() 7 | return func(session, *args, **kwargs) 8 | return decorator 9 | 10 | def staff_user_required(func): 11 | def decorator(session,*args, **kwargs): 12 | if session.user is None or session.user.is_staff == False: 13 | raise NotAuthorizedError() 14 | return func(session, *args, **kwargs) 15 | return decorator 16 | 17 | def broker_user_required(func): 18 | def decorator(session,*args, **kwargs): 19 | if session.user is None or session.user.is_broker == False: 20 | raise NotAuthorizedError() 21 | return func(session, *args, **kwargs) 22 | return decorator 23 | 24 | def system_user_required(func): 25 | def decorator(session,*args, **kwargs): 26 | if session.user is None or session.user.is_system == False: 27 | raise NotAuthorizedError() 28 | return func(session, *args, **kwargs) 29 | return decorator 30 | 31 | def verified_user_required(func): 32 | def decorator(session,*args, **kwargs): 33 | if session.user is None or session.user.verified < 2: 34 | raise NotAuthorizedError() 35 | return func(session, *args, **kwargs) 36 | return decorator 37 | 38 | 39 | 40 | def verify_permission(func): 41 | def decorator(session, msg): 42 | if '*' in session.permission_list: 43 | return func(session, msg) 44 | 45 | if msg.type not in session.permission_list: 46 | raise NotAuthorizedError() 47 | 48 | 49 | msg_permission_filter_list = session.permission_list[msg.type] 50 | if not msg_permission_filter_list: 51 | return func(session, msg) 52 | 53 | def pass_filter(msg, field, operator, value): 54 | if operator == 'eq': 55 | if not msg.has(field): 56 | return False 57 | if msg.get(field) != value: 58 | return False 59 | elif operator == 'in': 60 | if not msg.has(field): 61 | return False 62 | if msg.get(field) not in value: 63 | return False 64 | elif operator == 'ne': 65 | if msg.has(field): 66 | if msg.get(field) == value: 67 | return False 68 | elif operator == 'gt': 69 | if not msg.has(field): 70 | return False 71 | if msg.get(field) <= value: 72 | return False 73 | elif operator == 'ge': 74 | if not msg.has(field): 75 | return False 76 | if msg.get(field) < value: 77 | return False 78 | elif operator == 'lt': 79 | if not msg.has(field): 80 | return False 81 | if msg.get(field) >= value: 82 | return False 83 | elif operator == 'le': 84 | if not msg.has(field): 85 | return False 86 | if msg.get(field) > value: 87 | return False 88 | return True 89 | 90 | 91 | passed_one_of_the_filters = False 92 | for permission_filter in msg_permission_filter_list: 93 | passed_on_all_the_filters = True 94 | for x in xrange(0, len(permission_filter), 3): 95 | field = permission_filter[x+0] 96 | operator = permission_filter[x+1] 97 | value = permission_filter[x+2] 98 | 99 | if not pass_filter(msg, field, operator, value): 100 | passed_on_all_the_filters = False 101 | break 102 | 103 | if not passed_on_all_the_filters: 104 | continue 105 | 106 | passed_one_of_the_filters = True 107 | break 108 | 109 | if not passed_one_of_the_filters: 110 | raise NotAuthorizedError 111 | 112 | return func(session, msg) 113 | return decorator 114 | -------------------------------------------------------------------------------- /apps/trade/errors.py: -------------------------------------------------------------------------------- 1 | __author__ = 'rodrigo' 2 | 3 | 4 | 5 | class TradeRuntimeError(RuntimeError): 6 | error_description = "Unknow error" 7 | 8 | class DuplicateSession(TradeRuntimeError): 9 | error_description = "Duplicated session" 10 | 11 | class UserAlreadyLogged(TradeRuntimeError): 12 | error_description = "User is already logged in" 13 | 14 | class InvalidOptCodeError(TradeRuntimeError): 15 | error_description = "Invalid message opt_code" 16 | 17 | class InvalidSessionError(TradeRuntimeError): 18 | error_description = "Invalid session" 19 | 20 | class SessionTimeoutError(TradeRuntimeError): 21 | error_description = "Session timeout" 22 | 23 | class InvalidMessageError(TradeRuntimeError): 24 | error_description = "Invalid message" 25 | 26 | class NotAuthorizedError(TradeRuntimeError): 27 | error_description = "Not authorized" 28 | 29 | class InvalidClientIDError(TradeRuntimeError): 30 | error_description = "Invalid Client ID" 31 | 32 | class InvalidParameter(TradeRuntimeError): 33 | error_description = "Invalid Parameter" 34 | 35 | class InvalidApiKeyError(TradeRuntimeError): 36 | error_description = "ApiKey is not valid" 37 | 38 | class ApiKeyIsNotRevocableError(TradeRuntimeError): 39 | error_description = "ApiKey is not revocable" 40 | -------------------------------------------------------------------------------- /apps/trade/main.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import os 3 | import sys 4 | import ConfigParser 5 | import argparse 6 | from appdirs import site_config_dir 7 | 8 | ROOT_PATH = os.path.abspath( os.path.join(os.path.dirname(__file__), "../../")) 9 | sys.path.insert( 0, os.path.join(ROOT_PATH, 'libs')) 10 | sys.path.insert( 0, os.path.join(ROOT_PATH, 'apps')) 11 | 12 | from pyblinktrade.project_options import ProjectOptions 13 | from trade_application import TradeApplication 14 | 15 | def main(): 16 | parser = argparse.ArgumentParser(description="Blinktrade Trade application") 17 | parser.add_argument('-i', "--instance", 18 | action="store", 19 | dest="instance", 20 | help='Instance name', 21 | type=str) 22 | parser.add_argument('-c', "--config", 23 | action="store", 24 | dest="config", 25 | default=os.path.expanduser('~/.blinktrade/bitex.ini'), 26 | help='Configuration file', type=str) 27 | arguments = parser.parse_args() 28 | 29 | if not arguments.instance: 30 | parser.print_help() 31 | return 32 | 33 | 34 | candidates = [ os.path.join(site_config_dir('blinktrade'), 'bitex.ini'), 35 | os.path.expanduser('~/.blinktrade/bitex.ini'), 36 | arguments.config] 37 | config = ConfigParser.SafeConfigParser() 38 | config.read( candidates ) 39 | 40 | options = ProjectOptions(config, arguments.instance) 41 | 42 | if not options.trade_in or \ 43 | not options.trade_pub or \ 44 | not options.trade_log or \ 45 | not options.global_email_language or \ 46 | not options.sqlalchemy_connection_string or \ 47 | not options.sqlalchemy_engine: 48 | raise RuntimeError("Invalid configuration file") 49 | 50 | application = TradeApplication.instance() 51 | application.initialize(options, arguments.instance) 52 | application.run() 53 | 54 | if __name__ == "__main__": 55 | main() 56 | -------------------------------------------------------------------------------- /apps/trade/session_manager.py: -------------------------------------------------------------------------------- 1 | import datetime 2 | 3 | 4 | from session import Session 5 | from errors import * 6 | 7 | class SessionManager(object): 8 | def __init__(self, timeout_limit=0): 9 | self.sessions = {} 10 | self.timeout_limit = timeout_limit 11 | 12 | self.publish_queue = [] 13 | 14 | def open_session(self, session_id, msg): 15 | if session_id in self.sessions: 16 | return 'CLS,' + session_id 17 | 18 | remote_ip = None 19 | client_version = None 20 | if msg: 21 | remote_ip = msg.get('RemoteIp', None) 22 | client_version = msg.get('ClientVersion', None) 23 | 24 | self.sessions[session_id] = [0, datetime.datetime.now(), Session( session_id, remote_ip, client_version ) ] 25 | return 'OPN,' + session_id 26 | 27 | def close_session(self, session_id): 28 | if session_id not in self.sessions: 29 | return 'CLS,' + session_id 30 | del self.sessions[session_id] 31 | return 'CLS,' + session_id 32 | 33 | def process_message(self, msg_header, session_id, msg): 34 | if msg_header == 'OPN': 35 | return self.open_session(session_id, msg) 36 | 37 | elif msg_header == 'CLS': 38 | return self.close_session(session_id) 39 | 40 | # wrong opt_code 41 | if msg_header != 'REQ': 42 | self.close_session(session_id) 43 | raise InvalidOptCodeError() 44 | 45 | # wrong session id 46 | if session_id not in self.sessions: 47 | self.close_session(session_id) 48 | raise InvalidSessionError() 49 | 50 | 51 | # Check if the session is expired 52 | session_time = self.sessions[session_id][1] 53 | if self.timeout_limit: 54 | if datetime.timedelta(seconds=self.timeout_limit) + session_time < datetime.datetime.now(): 55 | raise SessionTimeoutError() 56 | 57 | self.sessions[session_id][0] += 1 # increment the number of received messages 58 | self.sessions[session_id][1] = datetime.datetime.now() # update session time, so we can timeout old sessions. 59 | 60 | if not msg: 61 | raise InvalidMessageError() 62 | 63 | session = self.sessions[session_id][2] 64 | response = session.process_message(msg) 65 | 66 | if session.should_end: 67 | self.close_session(session_id) 68 | return 'CLS,' + response 69 | 70 | return 'REP,' + response 71 | 72 | -------------------------------------------------------------------------------- /apps/trade/tests/__init__.py: -------------------------------------------------------------------------------- 1 | from test_model import * -------------------------------------------------------------------------------- /apps/ws_gateway/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blinktrade/bitex/a4896e7faef9c4aa0ca5325f18b77db67003764e/apps/ws_gateway/__init__.py -------------------------------------------------------------------------------- /apps/ws_gateway/deposit_receipt_webhook_handler.py: -------------------------------------------------------------------------------- 1 | import tornado.ioloop 2 | import tornado.web 3 | import tornado.httpclient 4 | import datetime 5 | import json 6 | 7 | class DepositReceiptWebHookHandler(tornado.web.RequestHandler): 8 | def __init__(self, application, request, **kwargs): 9 | super(DepositReceiptWebHookHandler, self).__init__(application, request, **kwargs) 10 | 11 | def post(self, *args, **kwargs): 12 | submissionID = self.get_argument('submissionID') 13 | 14 | raw_request = json.loads(self.get_argument('rawRequest')) 15 | deposit_id = None 16 | deposit_receipt = None 17 | for key, value in raw_request.iteritems(): 18 | if 'deposit_id' in key: 19 | deposit_id = value 20 | elif 'depositReceipt' in key: 21 | deposit_receipt = value 22 | 23 | import random 24 | req_id = random.randrange(600000,900000) 25 | 26 | message = { 27 | 'MsgType': 'B0', 28 | 'ProcessDepositReqID':req_id, 29 | 'Action': 'CONFIRM', 30 | 'DepositID': deposit_id, 31 | 'Data': { 32 | 'DepositReceipt': deposit_receipt, 33 | 'SubmissionID': submissionID 34 | } 35 | } 36 | 37 | self.application.application_trade_client.sendJSON(message) 38 | self.write('*ok*') 39 | -------------------------------------------------------------------------------- /apps/ws_gateway/instrument_helper.py: -------------------------------------------------------------------------------- 1 | from datetime import datetime 2 | from pyblinktrade.signals import Signal 3 | 4 | import time 5 | 6 | signal_publish_security_status = Signal() 7 | 8 | class InstrumentStatusHelper(object): 9 | """" InstrumentStatusHelper. """ 10 | 11 | def __init__(self, symbol = "ALL"): 12 | self.symbol = str(symbol) 13 | self.last_trades = [] 14 | self.volume_price = 0 15 | self.volume_size = 0 16 | self.last_price = 0 17 | self.max_price = 0 18 | self.min_price = None 19 | self.bid = None 20 | self.ask = None 21 | self.timestamp_last_update = int(time.time() * 1000) 22 | 23 | def set_best_bid(self, bid ): 24 | if self.bid != bid: 25 | self.timestamp_last_update = int(time.time() * 1000) 26 | self.bid = bid 27 | signal_publish_security_status('SECURITY_STATUS', self) 28 | 29 | def set_best_ask(self, ask ): 30 | if self.ask != ask: 31 | self.timestamp_last_update = int(time.time() * 1000) 32 | self.ask = ask 33 | signal_publish_security_status('SECURITY_STATUS', self) 34 | 35 | def _subtract_trade(self, trade): 36 | volume_price = int( 37 | trade['price'] * 38 | trade['size'] / 39 | 1.e8) 40 | 41 | self.volume_price -= volume_price 42 | self.volume_size -= trade['size'] 43 | 44 | if self.max_price == trade['price']: 45 | if self.last_trades: 46 | max_price_record = max(self.last_trades, key=lambda x:x['price']) 47 | if max_price_record: 48 | self.max_price = max_price_record['price'] 49 | else: 50 | self.max_price = 0 51 | else: 52 | self.max_price = 0 53 | 54 | if self.min_price == trade['price']: 55 | if self.last_trades: 56 | min_price = min(self.last_trades, key=lambda x:x['price']) 57 | if min_price: 58 | self.min_price = min_price['price'] 59 | 60 | def _add_trade(self, trade): 61 | volume_price = int( trade['price'] * trade['size'] / 1.e8) 62 | self.volume_price += volume_price 63 | self.volume_size += trade['size'] 64 | 65 | if trade['price'] > self.max_price: 66 | self.max_price = trade['price'] 67 | 68 | if self.min_price is None or trade['price'] < self.min_price: 69 | self.min_price = trade['price'] 70 | 71 | def push_trade(self, trade): 72 | while True: 73 | if len(self.last_trades) > 0: 74 | d1 = datetime.strptime(self.last_trades[-1]['trade_date'] + ' ' + self.last_trades[-1]['trade_time'], '%Y-%m-%d %H:%M:%S') 75 | d2 = datetime.strptime(trade['trade_date'] + ' ' + trade['trade_time'], '%Y-%m-%d %H:%M:%S') 76 | if (d2 - d1).days > 0: 77 | removed_trade = self.last_trades.pop() 78 | self._subtract_trade(removed_trade) 79 | continue 80 | break 81 | 82 | self.last_trades.insert(0,trade) 83 | self._add_trade(trade) 84 | self.last_price = trade['price'] 85 | 86 | signal_publish_security_status('SECURITY_STATUS', self) 87 | -------------------------------------------------------------------------------- /apps/ws_gateway/process_deposit_handler.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import os 3 | sys.path.insert(0, os.path.join( os.path.dirname(__file__), '../' ) ) 4 | 5 | import tornado.ioloop 6 | import tornado.web 7 | import tornado.httpclient 8 | import datetime 9 | import json 10 | 11 | from trade.zmq_client import TradeClientException 12 | 13 | class ProcessDepositHandler(tornado.web.RequestHandler): 14 | def __init__(self, application, request, **kwargs): 15 | super(ProcessDepositHandler, self).__init__(application, request, **kwargs) 16 | self.remote_ip = request.headers.get('X-Forwarded-For', request.headers.get('X-Real-Ip', request.remote_ip)) 17 | 18 | def get(self, *args, **kwargs): 19 | secret = self.get_argument("s", default=None, strip=False) 20 | if not secret: 21 | raise tornado.httpclient.HTTPError( 404 ) 22 | 23 | fwd_fee = int(self.get_argument("fwd_fee", default=0, strip=False)) 24 | input_fee = int(self.get_argument("input_fee", default=0, strip=False)) 25 | value = int(self.get_argument("value", default=0, strip=False)) 26 | input_address = self.get_argument("input_address", default=None, strip=False) 27 | input_transaction_hash = self.get_argument("input_transaction_hash", default=None, strip=False) 28 | transaction_hash = self.get_argument("transaction_hash", default=None, strip=False) 29 | confirmations = self.get_argument("confirmations", default=0, strip=False) 30 | payee_addresses = self.get_argument("payee_addresses", default=None, strip=False) 31 | 32 | import random 33 | req_id = random.randrange(600000,900000) 34 | 35 | payee_addresses_json = None 36 | if payee_addresses: 37 | try: 38 | payee_addresses_json = json.loads(payee_addresses) 39 | except Exception,e: 40 | pass 41 | 42 | 43 | 44 | process_deposit_message = { 45 | 'MsgType': 'B0', 46 | 'ProcessDepositReqID':req_id, 47 | 'Action': 'COMPLETE', 48 | 'Secret': secret, 49 | 'Amount': value, 50 | 'Data': { 51 | 'Confirmations': int(confirmations), 52 | 'InputAddress': input_address, 53 | 'InputTransactionHash': input_transaction_hash, 54 | 'TransactionHash': transaction_hash, 55 | } 56 | } 57 | 58 | if fwd_fee: 59 | process_deposit_message['Data']['ForwardFee'] = fwd_fee 60 | 61 | if input_fee: 62 | process_deposit_message['Data']['InputFee'] = input_fee 63 | 64 | if payee_addresses_json: 65 | process_deposit_message['Data']['PayeeAddresses'] = json.dumps(payee_addresses_json) 66 | 67 | try: 68 | response_msg = self.application.application_trade_client.sendJSON(process_deposit_message) 69 | except TradeClientException, e: 70 | self.write_error(400) 71 | return 72 | 73 | if response_msg.get('Status') == '4': 74 | self.write("*ok*") 75 | self.write("") 76 | -------------------------------------------------------------------------------- /apps/ws_gateway/rest_api_handler.py: -------------------------------------------------------------------------------- 1 | import tornado.web 2 | import tornado.httpclient 3 | import calendar 4 | import json 5 | 6 | from market_data_helper import MarketDataSubscriber 7 | 8 | class RestApiHandler(tornado.web.RequestHandler): 9 | def head(self, version, symbol, resource): 10 | self._process_request(version, symbol, resource) 11 | 12 | def get(self, version, symbol, resource): 13 | self._process_request(version, symbol, resource) 14 | 15 | def _send_tiker(self, symbol): 16 | md_subscriber = MarketDataSubscriber.get(symbol, self.application) 17 | 18 | ticker = { 19 | "pair": symbol, 20 | "high": md_subscriber.inst_status.max_price / 1e8, 21 | "low": md_subscriber.inst_status.min_price / 1e8, 22 | "last": md_subscriber.inst_status.last_price / 1e8, 23 | "vol_" + symbol[3:].lower(): md_subscriber.inst_status.volume_price / 1e8, 24 | "vol": md_subscriber.inst_status.volume_size / 1e8, 25 | "buy": md_subscriber.inst_status.bid / 1e8, 26 | "sell": md_subscriber.inst_status.ask / 1e8 27 | } 28 | self.write( json.dumps(ticker)) 29 | 30 | def _send_order_book(self, symbol): 31 | md_subscriber = MarketDataSubscriber.get(symbol, self.application.db_session) 32 | 33 | bids = [] 34 | asks = [] 35 | 36 | for order in md_subscriber.buy_side: 37 | bids.append([order['price']/1e8, order['qty']/1e8, order['user_id']]) 38 | 39 | for order in md_subscriber.sell_side: 40 | asks.append([order['price']/1e8, order['qty']/1e8, order['user_id']]) 41 | 42 | self.write( 43 | { 44 | 'pair': symbol, 45 | 'bids': bids, 46 | 'asks': asks 47 | } 48 | ) 49 | 50 | def _send_trades(self, symbol, since): 51 | md_subscriber = MarketDataSubscriber.get(symbol, self.application) 52 | trades = [] 53 | 54 | for trade in md_subscriber.get_trades(symbol, since): 55 | trades.append({ 56 | 'tid': trade.id, 57 | 'price': trade.price/1e8, 58 | 'amount': trade.size/1e8, 59 | 'date': calendar.timegm(trade.created.timetuple()), 60 | }) 61 | 62 | self.write(json.dumps(trades)) 63 | 64 | def _process_request(self, version, symbol, resource): 65 | currency = self.get_argument("crypto_currency", default='BTC', strip=False) 66 | since = self.get_argument("since", default=0, strip=False) 67 | callback = self.get_argument("callback", default='', strip=False) 68 | if not callback: 69 | callback = self.get_argument("jsonp", default='', strip=False) 70 | 71 | instrument = '%s%s'%(currency, symbol) 72 | 73 | if callback: 74 | self.write( callback + '(' ) 75 | if version == 'v1': 76 | if resource == 'orderbook': 77 | self._send_order_book(instrument) 78 | elif resource == 'trades': 79 | self._send_trades(instrument, float(since)) 80 | elif resource == 'ticker': 81 | self._send_tiker(instrument) 82 | else: 83 | self.send_error(404) 84 | else: 85 | self.send_error(404) 86 | 87 | if callback: 88 | self.write( ');' ) 89 | -------------------------------------------------------------------------------- /apps/ws_gateway/tests/__init__.py: -------------------------------------------------------------------------------- 1 | from test_signals import * -------------------------------------------------------------------------------- /apps/ws_gateway/util.py: -------------------------------------------------------------------------------- 1 | __author__ = 'rodrigo' 2 | 3 | import pycountry 4 | 5 | def get_country_code(country_name): 6 | try: 7 | return pycountry.countries.get(name=country_name).alpha2 8 | except KeyError: 9 | jotform_countries_that_are_not_in_pycountry = { 10 | "The Bahamas" : "BS", 11 | "Bolivia" : 'BO', 12 | "Brunei": "BN", 13 | "People's Republic of China": "CN", 14 | "Republic of China": "CN", 15 | "Cote d'Ivoire": "CI", 16 | "Falkland Islands": "FK", 17 | "The Gambia": "GM", 18 | "Iran": "IR", 19 | "North Korea": "KP", 20 | "South Korea": "KR", 21 | "Kosovo": "XK", 22 | "Laos": "LA", 23 | "Macau": "MO", 24 | "Macedonia": "MK", 25 | "Micronesia": "FM", 26 | "Moldova": "MD", 27 | "Nagorno-Karabakh":"AZ", 28 | "Netherlands Antilles": "AN", 29 | "Turkish Republic of Northern Cyprus": "CY", 30 | "Northern Mariana":"MP", 31 | "Palestine": "PS", 32 | "Pitcairn Islands": "PN", 33 | "Russia":"RU", 34 | "Saint Barthelemy": "BL", 35 | "Saint Helena":"SH", 36 | "Saint Martin" : "MF", 37 | "Somaliland" : "SO", 38 | "South Ossetia": "GE", 39 | "Svalbard":"SJ", 40 | "Syria":"SY", 41 | "Taiwan":"TW", 42 | "Tanzania":"TZ", 43 | "Transnistria Pridnestrovie":"MD", 44 | "Tristan da Cunha":"SH", 45 | "Vatican City":"VA", 46 | "Venezuela":"VE", 47 | "Vietnam":"VN", 48 | "British Virgin Islands": "VG", 49 | "US Virgin Islands": "VI" 50 | } 51 | try: 52 | return jotform_countries_that_are_not_in_pycountry[country_name] 53 | except KeyError: 54 | return country_name 55 | 56 | 57 | -------------------------------------------------------------------------------- /config/__init__.py: -------------------------------------------------------------------------------- 1 | __author__ = 'rodrigo' 2 | -------------------------------------------------------------------------------- /config/bitex.ini.example: -------------------------------------------------------------------------------- 1 | [DEFAULT] 2 | project_root_demo=/opt/blinktrade/bitex 3 | host_demo = yourexchange.com 4 | trade_in_demo = ipc:///tmp/trade_in_api_testnet 5 | trade_pub_demo = ipc:///tmp/trade_pub_api_testnet 6 | 7 | [trade_demo] 8 | project_root=%(project_root_demo)s 9 | db_echo = False 10 | trade_in = %(trade_in_demo)s 11 | trade_pub = %(trade_pub_demo)s 12 | trade_log = %(project_root)s/logs/trade_testnet.log 13 | session_timeout_limit = 0 14 | test_mode = False 15 | dev_mode = False 16 | satoshi_mode = False 17 | global_email_language = en 18 | sqlalchemy_engine=sqlite 19 | sqlalchemy_connection_string=%(project_root)s/db/bitex.sqlite 20 | url_payment_processor = http://host_of_api_receive.com/api/receive 21 | 22 | [ws_gateway_8445_demo] 23 | port = 8445 24 | project_root=%(project_root_demo)s 25 | session_timeout_limit = 0 26 | callback_url = https://%(host_demo)s/process_deposit?s= 27 | trade_in = %(trade_in_demo)s 28 | trade_pub = %(trade_pub_demo)s 29 | db_echo = False 30 | gateway_log = %(project_root)s/logs/ws_gateway_testnet_%(port)s.log 31 | sqlalchemy_engine=sqlite 32 | sqlalchemy_connection_string=%(project_root)s/db/bitex.ws_gateway_%(port)s_testnet.sqlite 33 | allowed_origins=["*"] 34 | 35 | 36 | [mailer_demo] 37 | project_root=%(project_root_demo)s 38 | trade_in = %(trade_in_demo)s 39 | trade_pub = %(trade_pub_demo)s 40 | mailer_username=mailer 41 | mailer_password=password_for_the_mailer_user_here 42 | mailer_log = %(project_root)s/logs/mailer_testnet.log 43 | mailchimp_apikey = your_key 44 | mailchimp_newsletter_list_id = your_list_id 45 | mandrill_apikey = your_key 46 | -------------------------------------------------------------------------------- /config/bootstrap/__init__.py: -------------------------------------------------------------------------------- 1 | __author__ = 'rodrigo' 2 | -------------------------------------------------------------------------------- /config/bootstrap/bootstrap.ini: -------------------------------------------------------------------------------- 1 | [database] 2 | sqlalchemy_engine=sqlite 3 | sqlalchemy_connection_string=~/.blinktrade/demo/db/bitex.demo.sqlite 4 | 5 | [user_root] 6 | id=-1 7 | username=root 8 | email=root@blinktrade.com 9 | country_code=US 10 | state=NY 11 | verified=3 12 | is_staff=yes 13 | is_system=yes 14 | is_broker=yes 15 | email_lang=en 16 | 17 | [user_blinktrade] 18 | id=8999999 19 | username=blinktrade 20 | email=admin@blinktrade.com 21 | country_code=US 22 | state=NY 23 | verified=2 24 | is_staff=yes 25 | is_broker=yes 26 | email_lang=en 27 | 28 | [user_mailer] 29 | id=100 30 | username=mailer 31 | email=mailer@blinktrade.com 32 | password=abc12345 33 | country_code=US 34 | state=NY 35 | verified=3 36 | is_system=yes 37 | email_lang=en 38 | broker_id=8999999 39 | broker_username=blinktrade 40 | 41 | 42 | [broker_root] 43 | user_verification_jotform=https://secure.jotform.us/form/31441083828150 44 | user_upload_jotform=https://secure.jotform.us/form/40783223144146 45 | id=-1 46 | short_name=root 47 | business_name=Blinktrade Inc 48 | address=40 Broad St 49 | signup_label={MSG_NOTIFY_NEW_BROKER} 50 | state=SP 51 | lang=en 52 | zip_code=10004 53 | city=New York 54 | country=United States 55 | country_code=US 56 | phone_number_1=+1 (646) 480-0222' 57 | skype='blinktrade', 58 | mandrill_api_key="" 59 | mailer_from_name="BlinkTrade" 60 | mailer_from_email="support@blinktrade.com" 61 | mailer_signature="BlinkTrade" 62 | mailchimp_list_id="" 63 | email='support@blinktrade.com', 64 | verification_jotform=%(user_verification_jotform)s?user_id={{UserID}}&username={{Username}}&broker_id={{BrokerID}}&broker_username={{BrokerUsername}}&email={{Email}} 65 | upload_jotform=%(user_upload_jotform)s?user_id={{UserID}}&username={{Username}}&broker_id={{BrokerID}}&broker_username={{BrokerUsername}}&deposit_method={{DepositMethod}}&control_number={{ControlNumber}}&deposit_id={{DepositID}} 66 | currencies= 67 | is_broker_hub=yes 68 | support_url=https://www.facebook.com/groups/blinktrade.support/ 69 | tos_url=/tos.html 70 | status=1 71 | ranking=0 72 | accounts={} 73 | withdraw_structure={} 74 | crypto_currencies=[] 75 | fee_structure=[] 76 | accept_customers_from=[["*"],[ "CU", "SO", "SD", "NG", "IR", "KP" ]] 77 | 78 | [broker_blinktrade] 79 | user_verification_jotform=https://secure.jotform.us/form/42275925807866 80 | user_upload_jotform=https://secure.jotform.us/form/42276525292861 81 | id=8999999 82 | short_name=blinktrade 83 | business_name=Blinktrade, Inc. 84 | address=40 Broad St 85 | signup_label={MSG_BROKER_APPLY} 86 | state=NY 87 | zip_code=10004 88 | city=New York 89 | lang=en 90 | country=United States 91 | country_code=US 92 | phone_number_1=+1 (646) 480-0222 93 | skype=blinktrade 94 | mandrill_api_key="" 95 | mailer_from_name="BlinkTrade" 96 | mailer_from_email="support@blinktrade.com" 97 | mailer_signature="BlinkTrade" 98 | mailchimp_list_id="" 99 | email=support@blinktrade.com 100 | verification_jotform=%(user_verification_jotform)s??user_id={{UserID}}&username={{Username}}&broker_id={{BrokerID}}&broker_username={{BrokerUsername}}&email={{Email}} 101 | upload_jotform=%(user_upload_jotform)s?user_id={{UserID}}&username={{Username}}&broker_id={{BrokerID}}&broker_username={{BrokerUsername}}&deposit_method={{DepositMethod}}&control_number={{ControlNumber}}&deposit_id={{DepositID}} 102 | currencies= 103 | withdraw_structure={ 104 | "BTC": [{ 105 | "method":"bitcoin", 106 | "description":"Bitcoin withdraw", 107 | "disclaimer": "All withdraws are processed at 23:00 GMT.", 108 | "percent_fee":0, 109 | "fixed_fee":0, 110 | "fields": [ 111 | {"side":"client", "name": "Wallet" , "validator":"validateAddress", "type":"text" , "value":"" , "label":"Wallet", "placeholder":"" }, 112 | {"side":"broker", "name": "TransactionID" , "validator":"validateAlphaNum", "type":"text" , "value":"" , "label":"TransactionID", "placeholder":"" } 113 | ] 114 | }] 115 | } 116 | crypto_currencies=[ 117 | { 118 | "CurrencyCode": "BTC", 119 | "CurrencyDescription":"Bitcoin", 120 | "Confirmations":[ [0, 2100000000000000, 3 ] ], 121 | "Wallets": [ 122 | { "type":"cold", "address":"16tdTifYyEMYGMqaFjgqS6oLQ7ZZLt4E8r", "multisig":false,"signatures":[], "managed_by":"Blinktrade" }, 123 | { "type":"hot", "address":"1LFHd1VnA923Ljvz6SrmuoC2fTe5rF2w4Q", "multisig":false,"signatures":[], "managed_by":"Blinktrade" } 124 | ] 125 | } 126 | ] 127 | is_broker_hub=yes 128 | support_url=https://www.facebook.com/groups/blinktrade.support/ 129 | tos_url=/tos.html 130 | status=1 131 | ranking=1 132 | accounts={} 133 | fee_structure=[] 134 | accept_customers_from=[["*"],[ "CU", "SO", "SD", "NG", "IR", "KP" ]] -------------------------------------------------------------------------------- /config/init.d/blinktrade_api_receive: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | ### BEGIN INIT INFO 3 | # Provides: blinktrade_api_receive 4 | # Required-Start: $network $remote_fs $local_fs 5 | # Required-Stop: $network $remote_fs $local_fs 6 | # Default-Start: 2 3 4 5 7 | # Default-Stop: 0 1 6 8 | # Short-Description: Stop/start blinktrade_api_receive 9 | ### END INIT INFO 10 | 11 | # Author: Sergey Budnevitch 12 | 13 | PATH=/sbin:/usr/sbin:/bin:/usr/bin:/opt/bitex/apps/api_receive/ 14 | DESC=blinktrade_api_receive 15 | NAME=blinktrade_api_receive 16 | CONFFILE=/opt/bitex/config/demo_api_receive.conf 17 | DAEMON=/opt/bitex/apps/api_receive/main.py 18 | PIDFILE=/var/run/$NAME.pid 19 | SCRIPTNAME=/etc/init.d/$NAME 20 | SLEEPSEC=1 21 | UPGRADEWAITLOOPS=5 22 | 23 | [ -x $DAEMON ] || exit 0 24 | 25 | [ -r /etc/default/$NAME ] && . /etc/default/$NAME 26 | 27 | DAEMON_ARGS="--config=$CONFFILE $DAEMON_ARGS" 28 | 29 | . /lib/init/vars.sh 30 | 31 | . /lib/lsb/init-functions 32 | 33 | do_start() 34 | { 35 | start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON -- \ 36 | $DAEMON_ARGS 37 | RETVAL="$?" 38 | return "$RETVAL" 39 | } 40 | 41 | do_stop() 42 | { 43 | # Return 44 | # 0 if daemon has been stopped 45 | # 1 if daemon was already stopped 46 | # 2 if daemon could not be stopped 47 | # other if a failure occurred 48 | start-stop-daemon --stop --quiet --oknodo --retry=TERM/30/KILL/5 --pidfile $PIDFILE --name $NAME 49 | RETVAL="$?" 50 | rm -f $PIDFILE 51 | return "$RETVAL" 52 | } 53 | 54 | do_reload() { 55 | # 56 | start-stop-daemon --stop --signal HUP --quiet --pidfile $PIDFILE --name $NAME 57 | RETVAL="$?" 58 | return "$RETVAL" 59 | } 60 | 61 | do_configtest() { 62 | if [ "$#" -ne 0 ]; then 63 | case "$1" in 64 | -q) 65 | FLAG=$1 66 | ;; 67 | *) 68 | ;; 69 | esac 70 | shift 71 | fi 72 | $DAEMON -t $FLAG -c $CONFFILE 73 | RETVAL="$?" 74 | return $RETVAL 75 | } 76 | 77 | do_upgrade() { 78 | OLDBINPIDFILE=$PIDFILE.oldbin 79 | 80 | do_configtest -q || return 6 81 | start-stop-daemon --stop --signal USR2 --quiet --pidfile $PIDFILE --name $NAME 82 | RETVAL="$?" 83 | 84 | for i in `/usr/bin/seq $UPGRADEWAITLOOPS`; do 85 | sleep $SLEEPSEC 86 | if [ -f $OLDBINPIDFILE -a -f $PIDFILE ]; then 87 | start-stop-daemon --stop --signal QUIT --quiet --pidfile $OLDBINPIDFILE --name $NAME 88 | RETVAL="$?" 89 | return 90 | fi 91 | done 92 | 93 | echo $"Upgrade failed!" 94 | RETVAL=1 95 | return $RETVAL 96 | } 97 | 98 | case "$1" in 99 | start) 100 | [ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC " "$NAME" 101 | do_start 102 | case "$?" in 103 | 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;; 104 | 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;; 105 | esac 106 | ;; 107 | stop) 108 | [ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME" 109 | do_stop 110 | case "$?" in 111 | 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;; 112 | 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;; 113 | esac 114 | ;; 115 | status) 116 | status_of_proc -p "$PIDFILE" "$DAEMON" "$NAME" && exit 0 || exit $? 117 | ;; 118 | configtest) 119 | do_configtest 120 | ;; 121 | upgrade) 122 | do_upgrade 123 | ;; 124 | reload|force-reload) 125 | log_daemon_msg "Reloading $DESC" "$NAME" 126 | do_reload 127 | log_end_msg $? 128 | ;; 129 | restart|force-reload) 130 | log_daemon_msg "Restarting $DESC" "$NAME" 131 | do_configtest -q || exit $RETVAL 132 | do_stop 133 | case "$?" in 134 | 0|1) 135 | do_start 136 | case "$?" in 137 | 0) log_end_msg 0 ;; 138 | 1) log_end_msg 1 ;; # Old process is still running 139 | *) log_end_msg 1 ;; # Failed to start 140 | esac 141 | ;; 142 | *) 143 | # Failed to stop 144 | log_end_msg 1 145 | ;; 146 | esac 147 | ;; 148 | *) 149 | echo "Usage: $SCRIPTNAME {start|stop|status|restart|reload|force-reload|upgrade|configtest}" >&2 150 | exit 3 151 | ;; 152 | esac 153 | 154 | exit $RETVAL 155 | -------------------------------------------------------------------------------- /config/init.d/blinktrade_mailer: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | ### BEGIN INIT INFO 3 | # Provides: blinktrade_mailer 4 | # Required-Start: $network $remote_fs $local_fs 5 | # Required-Stop: $network $remote_fs $local_fs 6 | # Default-Start: 2 3 4 5 7 | # Default-Stop: 0 1 6 8 | # Short-Description: Stop/start blinktrade_mailer 9 | ### END INIT INFO 10 | 11 | # Author: Sergey Budnevitch 12 | 13 | PATH=/sbin:/usr/sbin:/bin:/usr/bin:/opt/bitex/apps/mailer/ 14 | DESC=blinktrade_mailer 15 | NAME=blinktrade_mailer 16 | CONFFILE=/opt/bitex/config/demo_mailer.conf 17 | DAEMON=/opt/bitex/apps/mailer/main.py 18 | PIDFILE=/var/run/$NAME.pid 19 | SCRIPTNAME=/etc/init.d/$NAME 20 | SLEEPSEC=1 21 | UPGRADEWAITLOOPS=5 22 | 23 | [ -x $DAEMON ] || exit 0 24 | 25 | [ -r /etc/default/$NAME ] && . /etc/default/$NAME 26 | 27 | DAEMON_ARGS="--config=$CONFFILE $DAEMON_ARGS" 28 | 29 | . /lib/init/vars.sh 30 | 31 | . /lib/lsb/init-functions 32 | 33 | do_start() 34 | { 35 | start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON -- \ 36 | $DAEMON_ARGS 37 | RETVAL="$?" 38 | return "$RETVAL" 39 | } 40 | 41 | do_stop() 42 | { 43 | # Return 44 | # 0 if daemon has been stopped 45 | # 1 if daemon was already stopped 46 | # 2 if daemon could not be stopped 47 | # other if a failure occurred 48 | start-stop-daemon --stop --quiet --oknodo --retry=TERM/30/KILL/5 --pidfile $PIDFILE --name $NAME 49 | RETVAL="$?" 50 | rm -f $PIDFILE 51 | return "$RETVAL" 52 | } 53 | 54 | do_reload() { 55 | # 56 | start-stop-daemon --stop --signal HUP --quiet --pidfile $PIDFILE --name $NAME 57 | RETVAL="$?" 58 | return "$RETVAL" 59 | } 60 | 61 | do_configtest() { 62 | if [ "$#" -ne 0 ]; then 63 | case "$1" in 64 | -q) 65 | FLAG=$1 66 | ;; 67 | *) 68 | ;; 69 | esac 70 | shift 71 | fi 72 | $DAEMON -t $FLAG -c $CONFFILE 73 | RETVAL="$?" 74 | return $RETVAL 75 | } 76 | 77 | do_upgrade() { 78 | OLDBINPIDFILE=$PIDFILE.oldbin 79 | 80 | do_configtest -q || return 6 81 | start-stop-daemon --stop --signal USR2 --quiet --pidfile $PIDFILE --name $NAME 82 | RETVAL="$?" 83 | 84 | for i in `/usr/bin/seq $UPGRADEWAITLOOPS`; do 85 | sleep $SLEEPSEC 86 | if [ -f $OLDBINPIDFILE -a -f $PIDFILE ]; then 87 | start-stop-daemon --stop --signal QUIT --quiet --pidfile $OLDBINPIDFILE --name $NAME 88 | RETVAL="$?" 89 | return 90 | fi 91 | done 92 | 93 | echo $"Upgrade failed!" 94 | RETVAL=1 95 | return $RETVAL 96 | } 97 | 98 | case "$1" in 99 | start) 100 | [ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC " "$NAME" 101 | do_start 102 | case "$?" in 103 | 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;; 104 | 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;; 105 | esac 106 | ;; 107 | stop) 108 | [ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME" 109 | do_stop 110 | case "$?" in 111 | 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;; 112 | 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;; 113 | esac 114 | ;; 115 | status) 116 | status_of_proc -p "$PIDFILE" "$DAEMON" "$NAME" && exit 0 || exit $? 117 | ;; 118 | configtest) 119 | do_configtest 120 | ;; 121 | upgrade) 122 | do_upgrade 123 | ;; 124 | reload|force-reload) 125 | log_daemon_msg "Reloading $DESC" "$NAME" 126 | do_reload 127 | log_end_msg $? 128 | ;; 129 | restart|force-reload) 130 | log_daemon_msg "Restarting $DESC" "$NAME" 131 | do_configtest -q || exit $RETVAL 132 | do_stop 133 | case "$?" in 134 | 0|1) 135 | do_start 136 | case "$?" in 137 | 0) log_end_msg 0 ;; 138 | 1) log_end_msg 1 ;; # Old process is still running 139 | *) log_end_msg 1 ;; # Failed to start 140 | esac 141 | ;; 142 | *) 143 | # Failed to stop 144 | log_end_msg 1 145 | ;; 146 | esac 147 | ;; 148 | *) 149 | echo "Usage: $SCRIPTNAME {start|stop|status|restart|reload|force-reload|upgrade|configtest}" >&2 150 | exit 3 151 | ;; 152 | esac 153 | 154 | exit $RETVAL 155 | -------------------------------------------------------------------------------- /config/init.d/blinktrade_trade: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | ### BEGIN INIT INFO 3 | # Provides: blinktrade_trade 4 | # Required-Start: $network $remote_fs $local_fs 5 | # Required-Stop: $network $remote_fs $local_fs 6 | # Default-Start: 2 3 4 5 7 | # Default-Stop: 0 1 6 8 | # Short-Description: Stop/start blinktrade_trade 9 | ### END INIT INFO 10 | 11 | # Author: Sergey Budnevitch 12 | 13 | PATH=/sbin:/usr/sbin:/bin:/usr/bin:/opt/bitex/apps/trade/ 14 | DESC=blinktrade_trade 15 | NAME=blinktrade_trade 16 | CONFFILE=/opt/bitex/config/demo_trade.conf 17 | DAEMON=/opt/bitex/apps/trade/main.py 18 | PIDFILE=/var/run/$NAME.pid 19 | SCRIPTNAME=/etc/init.d/$NAME 20 | SLEEPSEC=1 21 | UPGRADEWAITLOOPS=5 22 | 23 | [ -x $DAEMON ] || exit 0 24 | 25 | [ -r /etc/default/$NAME ] && . /etc/default/$NAME 26 | 27 | DAEMON_ARGS="--config=$CONFFILE $DAEMON_ARGS" 28 | 29 | . /lib/init/vars.sh 30 | 31 | . /lib/lsb/init-functions 32 | 33 | do_start() 34 | { 35 | start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON -- \ 36 | $DAEMON_ARGS 37 | RETVAL="$?" 38 | return "$RETVAL" 39 | } 40 | 41 | do_stop() 42 | { 43 | # Return 44 | # 0 if daemon has been stopped 45 | # 1 if daemon was already stopped 46 | # 2 if daemon could not be stopped 47 | # other if a failure occurred 48 | start-stop-daemon --stop --quiet --oknodo --retry=TERM/30/KILL/5 --pidfile $PIDFILE --name $NAME 49 | RETVAL="$?" 50 | rm -f $PIDFILE 51 | return "$RETVAL" 52 | } 53 | 54 | do_reload() { 55 | # 56 | start-stop-daemon --stop --signal HUP --quiet --pidfile $PIDFILE --name $NAME 57 | RETVAL="$?" 58 | return "$RETVAL" 59 | } 60 | 61 | do_configtest() { 62 | if [ "$#" -ne 0 ]; then 63 | case "$1" in 64 | -q) 65 | FLAG=$1 66 | ;; 67 | *) 68 | ;; 69 | esac 70 | shift 71 | fi 72 | $DAEMON -t $FLAG -c $CONFFILE 73 | RETVAL="$?" 74 | return $RETVAL 75 | } 76 | 77 | do_upgrade() { 78 | OLDBINPIDFILE=$PIDFILE.oldbin 79 | 80 | do_configtest -q || return 6 81 | start-stop-daemon --stop --signal USR2 --quiet --pidfile $PIDFILE --name $NAME 82 | RETVAL="$?" 83 | 84 | for i in `/usr/bin/seq $UPGRADEWAITLOOPS`; do 85 | sleep $SLEEPSEC 86 | if [ -f $OLDBINPIDFILE -a -f $PIDFILE ]; then 87 | start-stop-daemon --stop --signal QUIT --quiet --pidfile $OLDBINPIDFILE --name $NAME 88 | RETVAL="$?" 89 | return 90 | fi 91 | done 92 | 93 | echo $"Upgrade failed!" 94 | RETVAL=1 95 | return $RETVAL 96 | } 97 | 98 | case "$1" in 99 | start) 100 | [ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC " "$NAME" 101 | do_start 102 | case "$?" in 103 | 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;; 104 | 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;; 105 | esac 106 | ;; 107 | stop) 108 | [ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME" 109 | do_stop 110 | case "$?" in 111 | 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;; 112 | 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;; 113 | esac 114 | ;; 115 | status) 116 | status_of_proc -p "$PIDFILE" "$DAEMON" "$NAME" && exit 0 || exit $? 117 | ;; 118 | configtest) 119 | do_configtest 120 | ;; 121 | upgrade) 122 | do_upgrade 123 | ;; 124 | reload|force-reload) 125 | log_daemon_msg "Reloading $DESC" "$NAME" 126 | do_reload 127 | log_end_msg $? 128 | ;; 129 | restart|force-reload) 130 | log_daemon_msg "Restarting $DESC" "$NAME" 131 | do_configtest -q || exit $RETVAL 132 | do_stop 133 | case "$?" in 134 | 0|1) 135 | do_start 136 | case "$?" in 137 | 0) log_end_msg 0 ;; 138 | 1) log_end_msg 1 ;; # Old process is still running 139 | *) log_end_msg 1 ;; # Failed to start 140 | esac 141 | ;; 142 | *) 143 | # Failed to stop 144 | log_end_msg 1 145 | ;; 146 | esac 147 | ;; 148 | *) 149 | echo "Usage: $SCRIPTNAME {start|stop|status|restart|reload|force-reload|upgrade|configtest}" >&2 150 | exit 3 151 | ;; 152 | esac 153 | 154 | exit $RETVAL 155 | -------------------------------------------------------------------------------- /config/init.d/blinktrade_ws_gateway: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | ### BEGIN INIT INFO 3 | # Provides: blinktrade_ws_gateway 4 | # Required-Start: $network $remote_fs $local_fs 5 | # Required-Stop: $network $remote_fs $local_fs 6 | # Default-Start: 2 3 4 5 7 | # Default-Stop: 0 1 6 8 | # Short-Description: Stop/start blinktrade_ws_gateway 9 | ### END INIT INFO 10 | 11 | # Author: Sergey Budnevitch 12 | 13 | PATH=/sbin:/usr/sbin:/bin:/usr/bin:/opt/bitex/apps/ws_gateway/ 14 | DESC=blinktrade_ws_gateway 15 | NAME=blinktrade_ws_gateway 16 | CONFFILE=/opt/bitex/config/demo_ws_gateway.conf 17 | DAEMON=/opt/bitex/apps/ws_gateway/main.py 18 | PIDFILE=/var/run/$NAME.pid 19 | SCRIPTNAME=/etc/init.d/$NAME 20 | SLEEPSEC=1 21 | UPGRADEWAITLOOPS=5 22 | 23 | [ -x $DAEMON ] || exit 0 24 | 25 | [ -r /etc/default/$NAME ] && . /etc/default/$NAME 26 | 27 | DAEMON_ARGS="--config=$CONFFILE $DAEMON_ARGS" 28 | 29 | . /lib/init/vars.sh 30 | 31 | . /lib/lsb/init-functions 32 | 33 | do_start() 34 | { 35 | start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON -- \ 36 | $DAEMON_ARGS 37 | RETVAL="$?" 38 | return "$RETVAL" 39 | } 40 | 41 | do_stop() 42 | { 43 | # Return 44 | # 0 if daemon has been stopped 45 | # 1 if daemon was already stopped 46 | # 2 if daemon could not be stopped 47 | # other if a failure occurred 48 | start-stop-daemon --stop --quiet --oknodo --retry=TERM/30/KILL/5 --pidfile $PIDFILE --name $NAME 49 | RETVAL="$?" 50 | rm -f $PIDFILE 51 | return "$RETVAL" 52 | } 53 | 54 | do_reload() { 55 | # 56 | start-stop-daemon --stop --signal HUP --quiet --pidfile $PIDFILE --name $NAME 57 | RETVAL="$?" 58 | return "$RETVAL" 59 | } 60 | 61 | do_configtest() { 62 | if [ "$#" -ne 0 ]; then 63 | case "$1" in 64 | -q) 65 | FLAG=$1 66 | ;; 67 | *) 68 | ;; 69 | esac 70 | shift 71 | fi 72 | $DAEMON -t $FLAG -c $CONFFILE 73 | RETVAL="$?" 74 | return $RETVAL 75 | } 76 | 77 | do_upgrade() { 78 | OLDBINPIDFILE=$PIDFILE.oldbin 79 | 80 | do_configtest -q || return 6 81 | start-stop-daemon --stop --signal USR2 --quiet --pidfile $PIDFILE --name $NAME 82 | RETVAL="$?" 83 | 84 | for i in `/usr/bin/seq $UPGRADEWAITLOOPS`; do 85 | sleep $SLEEPSEC 86 | if [ -f $OLDBINPIDFILE -a -f $PIDFILE ]; then 87 | start-stop-daemon --stop --signal QUIT --quiet --pidfile $OLDBINPIDFILE --name $NAME 88 | RETVAL="$?" 89 | return 90 | fi 91 | done 92 | 93 | echo $"Upgrade failed!" 94 | RETVAL=1 95 | return $RETVAL 96 | } 97 | 98 | case "$1" in 99 | start) 100 | [ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC " "$NAME" 101 | do_start 102 | case "$?" in 103 | 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;; 104 | 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;; 105 | esac 106 | ;; 107 | stop) 108 | [ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME" 109 | do_stop 110 | case "$?" in 111 | 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;; 112 | 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;; 113 | esac 114 | ;; 115 | status) 116 | status_of_proc -p "$PIDFILE" "$DAEMON" "$NAME" && exit 0 || exit $? 117 | ;; 118 | configtest) 119 | do_configtest 120 | ;; 121 | upgrade) 122 | do_upgrade 123 | ;; 124 | reload|force-reload) 125 | log_daemon_msg "Reloading $DESC" "$NAME" 126 | do_reload 127 | log_end_msg $? 128 | ;; 129 | restart|force-reload) 130 | log_daemon_msg "Restarting $DESC" "$NAME" 131 | do_configtest -q || exit $RETVAL 132 | do_stop 133 | case "$?" in 134 | 0|1) 135 | do_start 136 | case "$?" in 137 | 0) log_end_msg 0 ;; 138 | 1) log_end_msg 1 ;; # Old process is still running 139 | *) log_end_msg 1 ;; # Failed to start 140 | esac 141 | ;; 142 | *) 143 | # Failed to stop 144 | log_end_msg 1 145 | ;; 146 | esac 147 | ;; 148 | *) 149 | echo "Usage: $SCRIPTNAME {start|stop|status|restart|reload|force-reload|upgrade|configtest}" >&2 150 | exit 3 151 | ;; 152 | esac 153 | 154 | exit $RETVAL 155 | -------------------------------------------------------------------------------- /config/nginx.conf.example: -------------------------------------------------------------------------------- 1 | #user nobody; 2 | worker_processes 1; 3 | 4 | events { 5 | worker_connections 1024; 6 | } 7 | 8 | http { 9 | include mime.types; 10 | default_type application/octet-stream; 11 | 12 | sendfile on; 13 | #tcp_nopush on; 14 | 15 | keepalive_timeout 650; 16 | 17 | gzip on; 18 | 19 | 20 | map $http_upgrade $connection_upgrade { 21 | default upgrade; 22 | '' close; 23 | } 24 | 25 | upstream ws_gateway { 26 | server localhost:8443; 27 | server localhost:8444; 28 | server localhost:8445; 29 | } 30 | 31 | 32 | server { 33 | listen 80; 34 | return 301 https://$host$request_uri; 35 | } 36 | 37 | 38 | server { 39 | listen 443; 40 | server_name localhost; 41 | 42 | ssl on; 43 | ssl_certificate /Users/rodrigo/.blinktrade/demo/ssl/server.crt; 44 | ssl_certificate_key /Users/rodrigo/.blinktrade/demo/ssl/server.key; 45 | 46 | ssl_session_timeout 5m; 47 | 48 | ssl_protocols SSLv2 SSLv3 TLSv1; 49 | ssl_ciphers HIGH:!aNULL:!MD5; 50 | ssl_prefer_server_ciphers on; 51 | 52 | location /api/ { 53 | proxy_pass http://ws_gateway; 54 | proxy_set_header X-Real-IP $remote_addr; 55 | proxy_set_header Host $host; 56 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 57 | proxy_redirect off; 58 | } 59 | 60 | location /_webhook/ { 61 | proxy_pass http://ws_gateway; 62 | proxy_set_header X-Real-IP $remote_addr; 63 | proxy_set_header Host $host; 64 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 65 | proxy_redirect off; 66 | } 67 | 68 | location /get_deposit/ { 69 | proxy_pass http://ws_gateway; 70 | proxy_set_header X-Real-IP $remote_addr; 71 | proxy_set_header Host $host; 72 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 73 | 74 | rewrite /get_deposit(.*) /get_deposit$1 break; 75 | proxy_redirect off; 76 | 77 | } 78 | 79 | location /process_deposit/ { 80 | proxy_pass http://ws_gateway; 81 | proxy_set_header X-Real-IP $remote_addr; 82 | proxy_set_header Host $host; 83 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 84 | proxy_redirect off; 85 | 86 | } 87 | 88 | location /trade/ { 89 | rewrite /trade/(.*) /$1 break; 90 | 91 | proxy_pass http://ws_gateway; 92 | proxy_http_version 1.1; 93 | proxy_redirect off; 94 | 95 | proxy_set_header Host $host; 96 | proxy_set_header X-Real-IP $remote_addr; 97 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 98 | proxy_set_header Upgrade $http_upgrade; 99 | proxy_set_header Connection $connection_upgrade; 100 | proxy_read_timeout 3000s; 101 | } 102 | } 103 | } 104 | 105 | -------------------------------------------------------------------------------- /db/README: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blinktrade/bitex/a4896e7faef9c4aa0ca5325f18b77db67003764e/db/README -------------------------------------------------------------------------------- /libs/__init__.py: -------------------------------------------------------------------------------- 1 | __author__ = 'rodrigo' 2 | -------------------------------------------------------------------------------- /libs/bitcoinrpc/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blinktrade/bitex/a4896e7faef9c4aa0ca5325f18b77db67003764e/libs/bitcoinrpc/__init__.py -------------------------------------------------------------------------------- /libs/characters/.gitignore: -------------------------------------------------------------------------------- 1 | *.py[cod] 2 | 3 | # C extensions 4 | *.so 5 | 6 | # Packages 7 | *.egg 8 | *.egg-info 9 | dist 10 | build 11 | eggs 12 | parts 13 | bin 14 | var 15 | sdist 16 | develop-eggs 17 | .installed.cfg 18 | lib 19 | lib64 20 | __pycache__ 21 | 22 | # Installer logs 23 | pip-log.txt 24 | 25 | # Unit test / coverage reports 26 | .coverage 27 | .tox 28 | nosetests.xml 29 | 30 | # Translations 31 | *.mo 32 | 33 | # Mr Developer 34 | .mr.developer.cfg 35 | .project 36 | .pydevproject 37 | -------------------------------------------------------------------------------- /libs/characters/AUTHORS: -------------------------------------------------------------------------------- 1 | characters is maintained by Halfmoon Labs and various contributors. 2 | 3 | Development Leads 4 | ```````````````` 5 | 6 | - Ryan Shea (https://github.com/rxl) 7 | - Muneeb Ali (https://github.com/muneeb-ali) 8 | 9 | Patches and Suggestions 10 | ```````````````` 11 | -------------------------------------------------------------------------------- /libs/characters/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Halfmoon Labs 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /libs/characters/README.md: -------------------------------------------------------------------------------- 1 | characters 2 | ========== 3 | 4 | Tools for manipulating characters, strings, and character sets. 5 | -------------------------------------------------------------------------------- /libs/characters/characters/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Characters 4 | ~~~~~ 5 | 6 | :copyright: (c) 2014 by Halfmoon Labs 7 | :license: MIT, see LICENSE for more details. 8 | """ 9 | 10 | __version__ = '0.1.0' 11 | 12 | from .charset import change_charset, charset_to_int, int_to_charset 13 | from .hex import hex_to_int, int_to_hex, is_hex 14 | -------------------------------------------------------------------------------- /libs/characters/characters/charset.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Characters 4 | ~~~~~ 5 | 6 | :copyright: (c) 2014 by Halfmoon Labs 7 | :license: MIT, see LICENSE for more details. 8 | """ 9 | 10 | import re 11 | import string 12 | 13 | def int_to_charset(val, charset): 14 | """ Turn a non-negative integer into a string. 15 | """ 16 | if not val >= 0: 17 | raise ValueError('"val" must be a non-negative integer.') 18 | if val == 0: return charset[0] 19 | output = "" 20 | while val > 0: 21 | val, digit = divmod(val, len(charset)) 22 | output += charset[digit] 23 | # reverse the characters in the output and return 24 | return output[::-1] 25 | 26 | def charset_to_int(s, charset): 27 | """ Turn a string into a non-negative integer. 28 | """ 29 | output = 0 30 | for char in s: 31 | output = output * len(charset) + charset.index(char) 32 | return output 33 | 34 | def change_charset(s, original_charset, target_charset): 35 | """ Convert a string from one charset to another. 36 | """ 37 | if not isinstance(s, str): 38 | raise ValueError('"s" must be a string.') 39 | 40 | intermediate_integer = charset_to_int(s, original_charset) 41 | output_string = int_to_charset(intermediate_integer, target_charset) 42 | return output_string 43 | -------------------------------------------------------------------------------- /libs/characters/characters/hex.py: -------------------------------------------------------------------------------- 1 | import string 2 | from .charset import charset_to_int, int_to_charset 3 | 4 | def hex_to_int(s): 5 | return charset_to_int(s, string.hexdigits[0:16]) 6 | 7 | def int_to_hex(val): 8 | return int_to_charset(val, string.hexdigits[0:16]) 9 | 10 | def is_hex(s): 11 | try: 12 | int(s, 16) 13 | except ValueError: 14 | return False 15 | else: 16 | return True 17 | 18 | -------------------------------------------------------------------------------- /libs/characters/setup.py: -------------------------------------------------------------------------------- 1 | """ 2 | Characters 3 | ============== 4 | 5 | """ 6 | 7 | from setuptools import setup 8 | 9 | setup( 10 | name='characters', 11 | version='0.1.0', 12 | url='https://github.com/halfmoonlabs/characters', 13 | license='MIT', 14 | author='Halfmoon Labs', 15 | author_email='hello@halfmoon.io', 16 | description='Tools for manipulating characters, strings, and character sets.', 17 | packages=[ 18 | 'characters', 19 | ], 20 | zip_safe=False, 21 | install_requires=[ 22 | ], 23 | classifiers=[ 24 | 'Intended Audience :: Developers', 25 | 'License :: OSI Approved :: MIT License', 26 | 'Operating System :: OS Independent', 27 | 'Programming Language :: Python', 28 | ], 29 | ) 30 | -------------------------------------------------------------------------------- /libs/coinkit/.gitignore: -------------------------------------------------------------------------------- 1 | *.py[cod] 2 | 3 | # C extensions 4 | *.so 5 | 6 | # Packages 7 | *.egg 8 | *.egg-info 9 | dist 10 | build 11 | eggs 12 | parts 13 | bin 14 | var 15 | sdist 16 | develop-eggs 17 | .installed.cfg 18 | lib 19 | lib64 20 | __pycache__ 21 | 22 | # Installer logs 23 | pip-log.txt 24 | 25 | # Unit test / coverage reports 26 | .coverage 27 | .tox 28 | nosetests.xml 29 | 30 | # Translations 31 | *.mo 32 | 33 | # Mr Developer 34 | .mr.developer.cfg 35 | .project 36 | .pydevproject 37 | 38 | ignore -------------------------------------------------------------------------------- /libs/coinkit/AUTHORS: -------------------------------------------------------------------------------- 1 | Coinkit is maintained by Halfmoon Labs and various contributors. 2 | 3 | Development Leads 4 | ```````````````` 5 | 6 | - Ryan Shea (https://github.com/rxl) 7 | - Muneeb Ali (https://github.com/muneeb-ali) 8 | 9 | Patches and Suggestions 10 | ```````````````` 11 | 12 | - Adam Brown (https://github.com/DeftNerd) 13 | - Michael Flaxman (https://github.com/mflaxman) 14 | -------------------------------------------------------------------------------- /libs/coinkit/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Halfmoon Labs 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /libs/coinkit/README.md: -------------------------------------------------------------------------------- 1 | Coinkit 2 | ===== 3 | 4 | Tools for Bitcoin and other cryptocurrencies. 5 | 6 | ## Sample Usage 7 | 8 | ### Keypairs 9 | 10 | #### Random keypairs 11 | 12 | >>> from coinkit import BitcoinKeypair 13 | >>> keypair = BitcoinKeypair() 14 | >>> keypair.private_key() 15 | '91149ee24f1ee9a6f42c3dd64c2287781c8c57a6e8e929c80976e586d5322a3d' 16 | >>> keypair.public_key() 17 | '042c6b7e6da7633c8f226891cc7fa8e5ec84f8eacc792a46786efc869a408d29539a5e6f8de3f71c0014e8ea71691c7b41f45c083a074fef7ab5c321753ba2b3fe' 18 | >>> keypair.wif_pk() 19 | '5JvBUBPzU42Y7BHD7thTnySXQXMk8XEJGGQGcyBw7CCkw8RAH7m' 20 | >>> keypair.address() 21 | '13mtgVARiB1HiRyCHnKTi6rEwyje5TYKBW' 22 | 23 | #### Custom keypairs 24 | 25 | >>> hex_private_key = '91149ee24f1ee9a6f42c3dd64c2287781c8c57a6e8e929c80976e586d5322a3d' 26 | >>> keypair = BitcoinKeypair(hex_private_key) 27 | 28 | #### Random brain wallet keypairs 29 | 30 | >>> keypair = BitcoinKeypair.from_passphrase() 31 | >>> keypair.passphrase() 32 | 'shepherd mais pack rate enamel horace diva filesize maximum really roar mall' 33 | >>> keypair.address() 34 | '13mtgVARiB1HiRyCHnKTi6rEwyje5TYKBW' 35 | 36 | #### Custom brain wallet keypairs 37 | 38 | >>> passphrase = 'shepherd mais pack rate enamel horace diva filesize maximum really roar mall' 39 | >>> keypair = BitcoinKeypair.from_passphrase(passphrase) 40 | 41 | #### Altcoin keypairs 42 | 43 | >>> from coinkit import LitecoinKeypair 44 | >>> litecoin_keypair = LitecoinKeypair() 45 | >>> litecoin_keypair.address() 46 | 'LMzqwhUFnqFLyEfMTvJkz7v1AC6v8N9Qcd' 47 | 48 | ### Wallets 49 | 50 | #### Sequential Deterministic Wallets 51 | 52 | >>> from coinkit import SDWallet, BitcoinKeypair 53 | >>> passphrase = 'shepherd mais pack rate enamel horace diva filesize maximum really roar mall' 54 | >>> wallet = SDWallet(passphrase) 55 | >>> bitcoin_keypair_1 = wallet.keypair(1, BitcoinKeypair) 56 | >>> bitcoin_keypair_1.passphrase() 57 | 'shepherd mais pack rate enamel horace diva filesize maximum really roar mall bitcoin1' 58 | >>> bitcoin_keypair_1.address() 59 | '1DS2vmsqTwtXp1DfmDHi55Aqc6w4LBUC9k' 60 | 61 | ### Utilities 62 | 63 | #### Random passphrases 64 | 65 | >>> from coinkit import random_160bit_passphrase 66 | >>> random_160bit_passphrase() 67 | 'shepherd mais pack rate enamel horace diva filesize maximum really roar mall' 68 | 69 | ## Supported currencies 70 | 71 | - Litecoin 72 | - Namecoin 73 | - Peercoin 74 | - Primecoin 75 | - Testnet 76 | - Worldcoin 77 | - Megacoin 78 | - Feathercoin 79 | - Terracoin 80 | - Novacoin 81 | - Dogecoin 82 | - Anoncoin 83 | - Protoshares 84 | - Ixcoin 85 | - Memorycoin 86 | - Infinitecoin 87 | - Cryptogenic Bullion 88 | - Quarkcoin 89 | - Netcoin 90 | - Earthcoin 91 | 92 | ## Developers 93 | 94 | **Q:** Can I contribute to Coinkit? 95 | 96 | **A:** Of course! Any and all are encouraged to contribute. Just fork a copy of the repo and get started on something that you think would improve the current offering. 97 | 98 | **Q:** What should I work on? 99 | 100 | **A:** That's up to you! For a quick project, consider adding support for a new cryptocurrency (should only require two lines of code, not including the unit tests). 101 | 102 | Meanwhile, for something a bit more ambitious, check the issues section for outstanding feature requests. 103 | 104 | ## Notice 105 | 106 | Coinkit is still in Alpha. It's developers will not be held responsible for loss of bitcoins resulting from the use of this software. 107 | 108 | Developers using Coinkit are encouraged to inspect the code for themselves and perform their own tests. 109 | 110 | That said, we are committed to ensuring that this library behaves exactly as it is supposed to under all conditions, and have plans to ramp up our testing efforts going forward. 111 | -------------------------------------------------------------------------------- /libs/coinkit/coinkit/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Coinkit 4 | ~~~~~ 5 | 6 | :copyright: (c) 2014 by Halfmoon Labs 7 | :license: MIT, see LICENSE for more details. 8 | """ 9 | 10 | __version__ = '0.4.1' 11 | 12 | from .entropy import random_secret_exponent 13 | from .passphrase import random_256bit_passphrase, random_160bit_passphrase 14 | from .b58check import b58check_encode, b58check_decode, b58check_unpack, \ 15 | b58check_version_byte, is_b58check 16 | from .utils import is_secret_exponent, is_256bit_hex_string, \ 17 | is_wif_pk, is_b58check_address, extract_pk_as_int 18 | from .wallet import SDWallet 19 | from .keypair import * -------------------------------------------------------------------------------- /libs/coinkit/coinkit/b58check.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Coinkit 4 | ~~~~~ 5 | 6 | :copyright: (c) 2014 by Halfmoon Labs 7 | :license: MIT, see LICENSE for more details. 8 | """ 9 | 10 | import re 11 | import binascii 12 | from hashlib import sha256 13 | 14 | from characters.charset import change_charset 15 | 16 | HEX_KEYSPACE = "0123456789abcdef" 17 | B58_KEYSPACE = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz" 18 | 19 | def bin_sha256(s): 20 | return sha256(s).digest() 21 | 22 | def bin_checksum(s): 23 | """ Takes in a binary string and returns a checksum. """ 24 | return bin_sha256(bin_sha256(s))[:4] 25 | 26 | def b58check_encode(bin_s, version_byte=0): 27 | """ Takes in a binary string and converts it to a base 58 check string. """ 28 | # append the version byte to the beginning 29 | bin_s = chr(int(version_byte)) + bin_s 30 | # calculate the number of leading zeros 31 | num_leading_zeros = len(re.match(r'^\x00*', bin_s).group(0)) 32 | # add in the checksum add the end 33 | bin_s = bin_s + bin_checksum(bin_s) 34 | # convert from b2 to b16 35 | hex_s = binascii.hexlify(bin_s) 36 | # convert from b16 to b58 37 | b58_s = change_charset(hex_s, HEX_KEYSPACE, B58_KEYSPACE) 38 | 39 | return B58_KEYSPACE[0] * num_leading_zeros + b58_s 40 | 41 | def b58check_unpack(b58_s): 42 | """ Takes in a base 58 check string and returns: the version byte, the 43 | original encoded binary string, and the checksum. 44 | """ 45 | num_leading_zeros = len(re.match(r'^1*', b58_s).group(0)) 46 | # convert from b58 to b16 47 | hex_s = change_charset(b58_s, B58_KEYSPACE, HEX_KEYSPACE) 48 | # convert from b16 to b2 49 | bin_s = binascii.unhexlify(hex_s) 50 | # add in the leading zeros 51 | bin_s = '\x00' * num_leading_zeros + bin_s 52 | # make sure the newly calculated checksum equals the embedded checksum 53 | newly_calculated_checksum = bin_checksum(bin_s[:-4]) 54 | embedded_checksum = bin_s[-4:] 55 | assert(newly_calculated_checksum == embedded_checksum) 56 | # return values 57 | version_byte = bin_s[:1] 58 | encoded_value = bin_s[1:-4] 59 | checksum = bin_s[-4:] 60 | return version_byte, encoded_value, checksum 61 | 62 | def b58check_decode(b58_s): 63 | """ Takes in a base 58 check string and returns the original encoded binary 64 | string. 65 | """ 66 | version_byte, encoded_value, checksum = b58check_unpack(b58_s) 67 | return encoded_value 68 | 69 | def b58check_version_byte(b58_s): 70 | """ Takes in a base 58 check string and returns the version byte as an 71 | integer. """ 72 | version_byte, encoded_value, checksum = b58check_unpack(b58_s) 73 | return ord(version_byte) 74 | 75 | def is_b58check(b58_s): 76 | version_byte, binary_s, checksum = b58check_unpack(b58_s) 77 | return (b58_s == b58check_encode(binary_s, 78 | version_byte=ord(version_byte))) 79 | -------------------------------------------------------------------------------- /libs/coinkit/coinkit/entropy.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Coinkit 4 | ~~~~~ 5 | 6 | :copyright: (c) 2014 by Halfmoon Labs 7 | :license: MIT, see LICENSE for more details. 8 | """ 9 | 10 | import os 11 | import binascii 12 | 13 | def dev_random_entropy(numbytes): 14 | return open("/dev/random", "rb").read(numbytes) 15 | 16 | def dev_urandom_entropy(numbytes): 17 | return open("/dev/urandom", "rb").read(numbytes) 18 | 19 | def get_entropy(numbytes): 20 | if os.name == 'nt': 21 | return os.urandom(numbytes) 22 | else: 23 | return dev_random_entropy(numbytes) 24 | 25 | def random_secret_exponent(curve_order): 26 | """ Generates a random secret exponent. """ 27 | # run a rejection sampling algorithm to ensure the random int is less 28 | # than the curve order 29 | while True: 30 | # generate a random 256 bit hex string 31 | random_hex = binascii.hexlify(get_entropy(32)) 32 | random_int = int(random_hex, 16) 33 | if random_int >= 1 and random_int < curve_order: 34 | break 35 | return random_int 36 | -------------------------------------------------------------------------------- /libs/coinkit/coinkit/passphrase.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Coinkit 4 | ~~~~~ 5 | 6 | :copyright: (c) 2014 by Halfmoon Labs 7 | :license: MIT, see LICENSE for more details. 8 | """ 9 | 10 | from .entropy import get_entropy 11 | from .words import TOP_ENGLISH_WORDS 12 | from math import pow, ceil, log 13 | 14 | def random_passphrase_from_wordlist(phrase_length, wordlist): 15 | """ An extremely entropy efficient passphrase generator. 16 | 17 | This function: 18 | -Pulls entropy from the safer alternative to /dev/urandom: /dev/random 19 | -Doesn't rely on random.seed (words are selected right from the entropy) 20 | -Only requires 2 entropy bytes/word for word lists of up to 65536 words 21 | """ 22 | 23 | passphrase_words = [] 24 | 25 | numbytes_of_entropy = phrase_length * 2 26 | entropy = list(get_entropy(numbytes_of_entropy)) 27 | 28 | bytes_per_word = int(ceil(log(len(wordlist), 2) / 8)) 29 | 30 | if (phrase_length * bytes_per_word > 64): 31 | raise Exception("Error! This operation requires too much entropy. \ 32 | Try a shorter phrase length or word list.") 33 | 34 | for i in range(phrase_length): 35 | current_entropy = entropy[i*bytes_per_word:(i+1)*bytes_per_word] 36 | index = int(''.join(current_entropy).encode('hex'), 16) % len(wordlist) 37 | word = wordlist[index] 38 | passphrase_words.append(word) 39 | 40 | return " ".join(passphrase_words) 41 | 42 | def random_160bit_passphrase(): 43 | return random_passphrase_from_wordlist(12, TOP_ENGLISH_WORDS[0:10500]) 44 | 45 | def random_256bit_passphrase(): 46 | return random_passphrase_from_wordlist(16, TOP_ENGLISH_WORDS[0:65536]) 47 | -------------------------------------------------------------------------------- /libs/coinkit/coinkit/utils.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Coinkit 4 | ~~~~~ 5 | 6 | :copyright: (c) 2014 by Halfmoon Labs 7 | :license: MIT, see LICENSE for more details. 8 | """ 9 | 10 | import os 11 | import re 12 | import random 13 | import binascii 14 | 15 | """ Format checking """ 16 | 17 | from characters.hex import is_hex 18 | 19 | from .b58check import is_b58check, b58check_decode 20 | 21 | def is_secret_exponent(val, curve_order): 22 | return (isinstance(val, (int, long)) and val >= 1 and val < curve_order) 23 | 24 | def is_256bit_hex_string(val): 25 | return (isinstance(val, str) and len(val) == 64 and is_hex(val)) 26 | 27 | def is_wif_pk(val): 28 | return (len(val) >= 51 and len(val) <= 51 and is_b58check(val)) 29 | 30 | def is_b58check_address(val): 31 | return is_b58check(val) 32 | #return (len(val) >= 27 and len(val) <= 34 and is_b58check(val)) 33 | 34 | def extract_pk_as_int(pk, curve_order): 35 | if isinstance(pk, int): 36 | secret_exponent = pk 37 | elif is_256bit_hex_string(pk): 38 | secret_exponent = int(pk, 16) 39 | elif is_wif_pk(pk): 40 | secret_exponent = int(binascii.hexlify(b58check_decode(pk)), 16) 41 | else: 42 | raise ValueError("Private key is not in a valid format (int, wif, or hex).") 43 | 44 | # make sure that: 1 <= secret_exponent < curve_order 45 | if is_secret_exponent(secret_exponent, curve_order): 46 | return secret_exponent 47 | else: 48 | raise IndexError("Secret exponent is outside of the valid range. Must be >= 1 and < the curve order.") 49 | 50 | -------------------------------------------------------------------------------- /libs/coinkit/coinkit/wallet.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Coinkit 4 | ~~~~~ 5 | 6 | :copyright: (c) 2014 by Halfmoon Labs 7 | :license: MIT, see LICENSE for more details. 8 | """ 9 | 10 | from inspect import isclass 11 | from .keypair import * 12 | from .passphrase import random_256bit_passphrase, random_160bit_passphrase 13 | 14 | def is_cryptocurrency_keypair_class(cls): 15 | if not isclass(cls): 16 | return False 17 | if cls.__name__ == 'BitcoinKeypair': 18 | return True 19 | if len(cls.__bases__) > 0 and cls.__bases__[0].__name__ == 'BitcoinKeypair': 20 | return True 21 | 22 | _messages = { 23 | "SHORT_PASSPHRASE": "Warning! Passphrase must be at least %s characters.", 24 | "INVALID_KEYPAIR_CLASS": "Class must be a valid currency keypair class.", 25 | } 26 | 27 | class SDWallet(): 28 | """ A sequential deterministic wallet. 29 | """ 30 | 31 | def __init__(self, passphrase=None): 32 | """ Create wallet from a passphrase input. """ 33 | if not passphrase: 34 | passphrase = random_160bit_passphrase() 35 | 36 | self._passphrase = passphrase 37 | 38 | def passphrase(self): 39 | return self._passphrase 40 | 41 | def keypair(self, i, keypair_class): 42 | """ Return the keypair that corresponds to the provided sequence number 43 | and keypair class (BitcoinKeypair, etc.). 44 | """ 45 | 46 | # Make sure keypair_class is a valid cryptocurrency keypair 47 | if not is_cryptocurrency_keypair_class(keypair_class): 48 | raise Exception(_messages["INVALID_KEYPAIR_CLASS"]) 49 | 50 | currency_name = keypair_class.__name__.lower().replace('keypair', '') 51 | 52 | k = keypair_class.from_passphrase( 53 | self._passphrase + " " + currency_name + str(i)) 54 | 55 | return k 56 | 57 | class HDWallet(): 58 | """ A hierarchical deterministic wallet in accordance with BIP 32. 59 | """ 60 | 61 | def __init__(self): 62 | raise NotImplementedError() 63 | 64 | 65 | -------------------------------------------------------------------------------- /libs/coinkit/requirements.txt: -------------------------------------------------------------------------------- 1 | ecdsa>=0.10 2 | characters>=0.1 -------------------------------------------------------------------------------- /libs/coinkit/setup.py: -------------------------------------------------------------------------------- 1 | """ 2 | Coinkit 3 | ============== 4 | 5 | """ 6 | 7 | from setuptools import setup 8 | 9 | setup( 10 | name='coinkit', 11 | version='0.4.1', 12 | url='https://github.com/halfmoonlabs/coinkit', 13 | license='MIT', 14 | author='Halfmoon Labs', 15 | author_email='hello@halfmoon.io', 16 | description='Tools for Bitcoin & other cryptocurrencies (incl. Litecoin, Namecoin, Peercoin, Primecoin, Dogecoin, Worldcoin, Megacoin, Anoncoin, Feathercoin, Terracoin, and Novacoin).', 17 | keywords='bitcoin btc litecoin namecoin peercoin primecoin cryptocurrency', 18 | packages=[ 19 | 'coinkit', 20 | ], 21 | zip_safe=False, 22 | install_requires=[ 23 | 'ecdsa>=0.10', 24 | 'characters>=0.1' 25 | ], 26 | classifiers=[ 27 | 'Intended Audience :: Developers', 28 | 'License :: OSI Approved :: MIT License', 29 | 'Operating System :: OS Independent', 30 | 'Programming Language :: Python', 31 | 'Topic :: Internet', 32 | 'Topic :: Security :: Cryptography', 33 | 'Topic :: Software Development :: Libraries :: Python Modules', 34 | ], 35 | ) 36 | -------------------------------------------------------------------------------- /libs/jsonrpc/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | """ 3 | Copyright (c) 2007 Jan-Klaas Kollhof 4 | 5 | This file is part of jsonrpc. 6 | 7 | jsonrpc is free software; you can redistribute it and/or modify 8 | it under the terms of the GNU Lesser General Public License as published by 9 | the Free Software Foundation; either version 2.1 of the License, or 10 | (at your option) any later version. 11 | 12 | This software is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU Lesser General Public License for more details. 16 | 17 | You should have received a copy of the GNU Lesser General Public License 18 | along with this software; if not, write to the Free Software 19 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 20 | """ 21 | 22 | from jsonrpc.json import loads, dumps, JSONEncodeException, JSONDecodeException 23 | from jsonrpc.proxy import ServiceProxy, JSONRPCException 24 | from jsonrpc.serviceHandler import ServiceMethod, ServiceHandler, ServiceMethodNotFound, ServiceException 25 | from jsonrpc.cgiwrapper import handleCGI 26 | from jsonrpc.modpywrapper import handler -------------------------------------------------------------------------------- /libs/jsonrpc/_tests/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | """ 3 | Copyright (c) 2007 Jan-Klaas Kollhof 4 | 5 | This file is part of jsonrpc. 6 | 7 | jsonrpc is free software; you can redistribute it and/or modify 8 | it under the terms of the GNU Lesser General Public License as published by 9 | the Free Software Foundation; either version 2.1 of the License, or 10 | (at your option) any later version. 11 | 12 | This software is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU Lesser General Public License for more details. 16 | 17 | You should have received a copy of the GNU Lesser General Public License 18 | along with this software; if not, write to the Free Software 19 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 20 | """ 21 | -------------------------------------------------------------------------------- /libs/jsonrpc/_tests/test_cgiwrapper.py: -------------------------------------------------------------------------------- 1 | 2 | """ 3 | Copyright (c) 2007 Jan-Klaas Kollhof 4 | 5 | This file is part of jsonrpc. 6 | 7 | jsonrpc is free software; you can redistribute it and/or modify 8 | it under the terms of the GNU Lesser General Public License as published by 9 | the Free Software Foundation; either version 2.1 of the License, or 10 | (at your option) any later version. 11 | 12 | This software is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU Lesser General Public License for more details. 16 | 17 | You should have received a copy of the GNU Lesser General Public License 18 | along with this software; if not, write to the Free Software 19 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 20 | """ 21 | import unittest 22 | import jsonrpc 23 | from types import * 24 | 25 | class Service(object): 26 | @jsonrpc.ServiceMethod 27 | def echo(self, arg): 28 | return arg 29 | 30 | 31 | class TestCGIWrapper(unittest.TestCase): 32 | 33 | def setUp(self): 34 | pass 35 | 36 | def tearDown(self): 37 | pass 38 | 39 | def test_runCGIHandler(self): 40 | from StringIO import StringIO 41 | 42 | json=u'{"method":"echo","params":["foobar"], "id":""}' 43 | fin=StringIO(json) 44 | fout=StringIO() 45 | 46 | env = {"CONTENT_LENGTH":len(json)} 47 | 48 | jsonrpc.handleCGI(service=Service(), fin=fin, fout=fout, env=env) 49 | 50 | data = StringIO(fout.getvalue()) 51 | data.readline() 52 | data.readline() 53 | data = data.read() 54 | self.assertEquals(jsonrpc.loads(data), {"result":"foobar", "error":None, "id":""}) 55 | 56 | -------------------------------------------------------------------------------- /libs/jsonrpc/_tests/test_modpywrapper.py: -------------------------------------------------------------------------------- 1 | 2 | """ 3 | Copyright (c) 2007 Jan-Klaas Kollhof 4 | 5 | This file is part of jsonrpc. 6 | 7 | jsonrpc is free software; you can redistribute it and/or modify 8 | it under the terms of the GNU Lesser General Public License as published by 9 | the Free Software Foundation; either version 2.1 of the License, or 10 | (at your option) any later version. 11 | 12 | This software is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU Lesser General Public License for more details. 16 | 17 | You should have received a copy of the GNU Lesser General Public License 18 | along with this software; if not, write to the Free Software 19 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 20 | """ 21 | import unittest 22 | import jsonrpc 23 | from types import * 24 | 25 | class Service(object): 26 | @jsonrpc.ServiceMethod 27 | def echo(self, arg): 28 | return arg 29 | 30 | 31 | class ApacheRequestMockup(object): 32 | 33 | def __init__(self, filename, fin, fout): 34 | self.fin=fin 35 | self.fout = fout 36 | self.filename = filename 37 | 38 | def write(self,data): 39 | self.fout.write(data) 40 | 41 | def flush(self): 42 | pass 43 | 44 | def read(self): 45 | return self.fin.read() 46 | 47 | class ModPyMockup(object): 48 | def __init__(self): 49 | self.apache=ApacheModuleMockup() 50 | 51 | class ApacheModuleMockup(object): 52 | def __getattr__(self, name): 53 | return name 54 | 55 | def import_module(self, moduleName, log=1): 56 | return Service() 57 | 58 | 59 | 60 | class TestModPyWrapper(unittest.TestCase): 61 | 62 | def setUp(self): 63 | import sys 64 | sys.modules['mod_python'] =ModPyMockup() 65 | 66 | def tearDown(self): 67 | pass 68 | 69 | def test_runHandler(self): 70 | from StringIO import StringIO 71 | 72 | json=u'{"method":"echo","params":["foobar"], "id":""}' 73 | fin=StringIO(json) 74 | fout=StringIO() 75 | req = ApacheRequestMockup(__file__ , fin, fout) 76 | 77 | jsonrpc.handler(req) 78 | 79 | data = fout.getvalue() 80 | 81 | self.assertEquals(jsonrpc.loads(data), {"result":"foobar", "error":None, "id":""}) 82 | 83 | def test_ServiceImplementationNotFound(self): 84 | from StringIO import StringIO 85 | 86 | json=u'{"method":"echo","params":["foobar"], "id":""}' 87 | fin=StringIO(json) 88 | fout=StringIO() 89 | req = ApacheRequestMockup("foobar" , fin, fout) 90 | 91 | rslt = jsonrpc.handler(req) 92 | self.assertEquals(rslt, "OK") 93 | data = fout.getvalue() 94 | 95 | self.assertEquals(jsonrpc.loads(data), {u'id': '', u'result': None, u'error': {u'message': '', u'name': u'ServiceImplementaionNotFound'}} ) 96 | 97 | 98 | 99 | -------------------------------------------------------------------------------- /libs/jsonrpc/_tests/test_proxy.py: -------------------------------------------------------------------------------- 1 | 2 | """ 3 | Copyright (c) 2007 Jan-Klaas Kollhof 4 | 5 | This file is part of jsonrpc. 6 | 7 | jsonrpc is free software; you can redistribute it and/or modify 8 | it under the terms of the GNU Lesser General Public License as published by 9 | the Free Software Foundation; either version 2.1 of the License, or 10 | (at your option) any later version. 11 | 12 | This software is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU Lesser General Public License for more details. 16 | 17 | You should have received a copy of the GNU Lesser General Public License 18 | along with this software; if not, write to the Free Software 19 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 20 | """ 21 | 22 | import unittest 23 | import jsonrpc 24 | 25 | import urllib 26 | 27 | from StringIO import StringIO 28 | 29 | class TestProxy(unittest.TestCase): 30 | 31 | def urlopen(self, url, data): 32 | self.postdata = data 33 | return StringIO(self.respdata) 34 | 35 | def setUp(self): 36 | self.postdata="" 37 | self.urllib_openurl = urllib.urlopen 38 | urllib.urlopen = self.urlopen 39 | 40 | def tearDown(self): 41 | urllib.urlopen = self.urllib_openurl 42 | 43 | def test_ProvidesProxyMethod(self): 44 | s = jsonrpc.ServiceProxy("http://localhost/") 45 | self.assert_(callable(s.echo)) 46 | 47 | def test_MethodCallCallsService(self): 48 | 49 | s = jsonrpc.ServiceProxy("http://localhost/") 50 | 51 | self.respdata='{"result":"foobar","error":null,"id":""}' 52 | echo = s.echo("foobar") 53 | self.assertEquals(self.postdata, jsonrpc.dumps({"method":"echo", 'params':['foobar'], 'id':'jsonrpc'})) 54 | self.assertEquals(echo, 'foobar') 55 | 56 | self.respdata='{"result":null,"error":"MethodNotFound","id":""}' 57 | try: 58 | s.echo("foobar") 59 | except jsonrpc.JSONRPCException,e: 60 | self.assertEquals(e.error, "MethodNotFound") 61 | -------------------------------------------------------------------------------- /libs/jsonrpc/cgiwrapper.py: -------------------------------------------------------------------------------- 1 | import sys, os 2 | from jsonrpc import ServiceHandler 3 | 4 | class CGIServiceHandler(ServiceHandler): 5 | def __init__(self, service): 6 | if service == None: 7 | import __main__ as service 8 | 9 | ServiceHandler.__init__(self, service) 10 | 11 | def handleRequest(self, fin=None, fout=None, env=None): 12 | if fin==None: 13 | fin = sys.stdin 14 | if fout==None: 15 | fout = sys.stdout 16 | if env == None: 17 | env = os.environ 18 | 19 | try: 20 | contLen=int(env['CONTENT_LENGTH']) 21 | data = fin.read(contLen) 22 | except Exception, e: 23 | data = "" 24 | 25 | resultData = ServiceHandler.handleRequest(self, data) 26 | 27 | response = "Content-Type: text/plain\n" 28 | response += "Content-Length: %d\n\n" % len(resultData) 29 | response += resultData 30 | 31 | #on windows all \n are converted to \r\n if stdout is a terminal and is not set to binary mode :( 32 | #this will then cause an incorrect Content-length. 33 | #I have only experienced this problem with apache on Win so far. 34 | if sys.platform == "win32": 35 | try: 36 | import msvcrt 37 | msvcrt.setmode(fout.fileno(), os.O_BINARY) 38 | except: 39 | pass 40 | #put out the response 41 | fout.write(response) 42 | fout.flush() 43 | 44 | def handleCGI(service=None, fin=None, fout=None, env=None): 45 | CGIServiceHandler(service).handleRequest(fin, fout, env) -------------------------------------------------------------------------------- /libs/jsonrpc/modpywrapper.py: -------------------------------------------------------------------------------- 1 | import sys, os 2 | from jsonrpc import ServiceHandler, ServiceException 3 | 4 | 5 | class ServiceImplementaionNotFound(ServiceException): 6 | pass 7 | 8 | 9 | class ModPyServiceHandler(ServiceHandler): 10 | def __init__(self, req): 11 | self.req = req 12 | ServiceHandler.__init__(self, None) 13 | 14 | 15 | def findServiceEndpoint(self, name): 16 | req = self.req 17 | 18 | (modulePath, fileName) = os.path.split(req.filename) 19 | (moduleName, ext) = os.path.splitext(fileName) 20 | 21 | if not os.path.exists(os.path.join(modulePath, moduleName + ".py")): 22 | raise ServiceImplementaionNotFound() 23 | else: 24 | if not modulePath in sys.path: 25 | sys.path.insert(0, modulePath) 26 | 27 | from mod_python import apache 28 | module = apache.import_module(moduleName, log=1) 29 | 30 | if hasattr(module, "service"): 31 | self.service = module.service 32 | elif hasattr(module, "Service"): 33 | self.service = module.Service() 34 | else: 35 | self.service = module 36 | 37 | return ServiceHandler.findServiceEndpoint(self, name) 38 | 39 | 40 | def handleRequest(self, data): 41 | self.req.content_type = "text/plain" 42 | data = self.req.read() 43 | resultData = ServiceHandler.handleRequest(self, data) 44 | self.req.write(resultData) 45 | self.req.flush() 46 | 47 | def handler(req): 48 | from mod_python import apache 49 | ModPyServiceHandler(req).handleRequest(req) 50 | return apache.OK 51 | 52 | 53 | -------------------------------------------------------------------------------- /libs/jsonrpc/proxy.py: -------------------------------------------------------------------------------- 1 | 2 | """ 3 | Copyright (c) 2007 Jan-Klaas Kollhof 4 | 5 | This file is part of jsonrpc. 6 | 7 | jsonrpc is free software; you can redistribute it and/or modify 8 | it under the terms of the GNU Lesser General Public License as published by 9 | the Free Software Foundation; either version 2.1 of the License, or 10 | (at your option) any later version. 11 | 12 | This software is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU Lesser General Public License for more details. 16 | 17 | You should have received a copy of the GNU Lesser General Public License 18 | along with this software; if not, write to the Free Software 19 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 20 | """ 21 | 22 | import urllib 23 | from jsonrpc.json import dumps, loads 24 | 25 | class JSONRPCException(Exception): 26 | def __init__(self, rpcError): 27 | Exception.__init__(self) 28 | self.error = rpcError 29 | 30 | class ServiceProxy(object): 31 | def __init__(self, serviceURL, serviceName=None): 32 | self.__serviceURL = serviceURL 33 | self.__serviceName = serviceName 34 | 35 | def __getattr__(self, name): 36 | if self.__serviceName != None: 37 | name = "%s.%s" % (self.__serviceName, name) 38 | return ServiceProxy(self.__serviceURL, name) 39 | 40 | def __call__(self, *args): 41 | postdata = dumps({"method": self.__serviceName, 'params': args, 'id':'jsonrpc'}) 42 | respdata = urllib.urlopen(self.__serviceURL, postdata).read() 43 | resp = loads(respdata) 44 | if resp['error'] != None: 45 | raise JSONRPCException(resp['error']) 46 | else: 47 | return resp['result'] 48 | 49 | 50 | -------------------------------------------------------------------------------- /libs/jsonrpc/serviceHandler.py: -------------------------------------------------------------------------------- 1 | 2 | """ 3 | Copyright (c) 2007 Jan-Klaas Kollhof 4 | 5 | This file is part of jsonrpc. 6 | 7 | jsonrpc is free software; you can redistribute it and/or modify 8 | it under the terms of the GNU Lesser General Public License as published by 9 | the Free Software Foundation; either version 2.1 of the License, or 10 | (at your option) any later version. 11 | 12 | This software is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU Lesser General Public License for more details. 16 | 17 | You should have received a copy of the GNU Lesser General Public License 18 | along with this software; if not, write to the Free Software 19 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 20 | """ 21 | 22 | from jsonrpc import loads, dumps, JSONEncodeException 23 | 24 | 25 | def ServiceMethod(fn): 26 | fn.IsServiceMethod = True 27 | return fn 28 | 29 | class ServiceException(Exception): 30 | pass 31 | 32 | class ServiceRequestNotTranslatable(ServiceException): 33 | pass 34 | 35 | class BadServiceRequest(ServiceException): 36 | pass 37 | 38 | class ServiceMethodNotFound(ServiceException): 39 | def __init__(self, name): 40 | self.methodName=name 41 | 42 | class ServiceHandler(object): 43 | 44 | def __init__(self, service): 45 | self.service=service 46 | 47 | def handleRequest(self, json): 48 | err=None 49 | result = None 50 | id_='' 51 | 52 | try: 53 | req = self.translateRequest(json) 54 | except ServiceRequestNotTranslatable, e: 55 | err = e 56 | req={'id':id_} 57 | 58 | if err==None: 59 | try: 60 | id_ = req['id'] 61 | methName = req['method'] 62 | args = req['params'] 63 | except: 64 | err = BadServiceRequest(json) 65 | 66 | if err == None: 67 | try: 68 | meth = self.findServiceEndpoint(methName) 69 | except Exception, e: 70 | err = e 71 | 72 | if err == None: 73 | try: 74 | result = self.invokeServiceEndpoint(meth, args) 75 | except Exception, e: 76 | err = e 77 | 78 | resultdata = self.translateResult(result, err, id_) 79 | 80 | return resultdata 81 | 82 | def translateRequest(self, data): 83 | try: 84 | req = loads(data) 85 | except: 86 | raise ServiceRequestNotTranslatable(data) 87 | return req 88 | 89 | def findServiceEndpoint(self, name): 90 | try: 91 | meth = getattr(self.service, name) 92 | if getattr(meth, "IsServiceMethod"): 93 | return meth 94 | else: 95 | raise ServiceMethodNotFound(name) 96 | except AttributeError: 97 | raise ServiceMethodNotFound(name) 98 | 99 | def invokeServiceEndpoint(self, meth, args): 100 | return meth(*args) 101 | 102 | def translateResult(self, rslt, err, id_): 103 | if err != None: 104 | err = {"name": err.__class__.__name__, "message":err.message} 105 | rslt = None 106 | 107 | try: 108 | data = dumps({"result":rslt,"id":id_,"error":err}) 109 | except JSONEncodeException, e: 110 | err = {"name": "JSONEncodeException", "message":"Result Object Not Serializable"} 111 | data = dumps({"result":None, "id":id_,"error":err}) 112 | 113 | return data -------------------------------------------------------------------------------- /libs/pusherclient/__init__.py: -------------------------------------------------------------------------------- 1 | from channel import Channel 2 | from connection import Connection 3 | import hashlib 4 | import thread 5 | import hmac 6 | import logging 7 | 8 | try: 9 | import simplejson as json 10 | except: 11 | import json 12 | 13 | 14 | VERSION = "0.2.0" 15 | 16 | 17 | class Pusher(object): 18 | host = "ws.pusherapp.com" 19 | client_id = 'PythonPusherClient' 20 | protocol = 6 21 | 22 | def __init__(self, key, secure=True, secret=None, user_data=None, log_level=logging.INFO): 23 | self.key = key 24 | self.secret = secret 25 | self.user_data = user_data or {} 26 | 27 | self.channels = {} 28 | 29 | self.connection = Connection(self._connection_handler, self._build_url(key, secure), log_level=log_level) 30 | 31 | def connect(self): 32 | """Connect to Pusher""" 33 | thread.start_new_thread(self.connection.run, ()) 34 | 35 | def disconnect(self): 36 | """Disconnect from Pusher""" 37 | self.connection.disconnect() 38 | self.channels = {} 39 | 40 | def subscribe(self, channel_name): 41 | """Subscribe to a channel 42 | 43 | :param channel_name: The name of the channel to subscribe to. 44 | :type channel_name: str 45 | 46 | :rtype : Channel 47 | """ 48 | data = {'channel': channel_name} 49 | 50 | if channel_name.startswith('presence-'): 51 | data['auth'] = self._generate_presence_key( 52 | self.connection.socket_id, 53 | self.key, 54 | channel_name, 55 | self.secret, 56 | self.user_data 57 | ) 58 | data['channel_data'] = json.dumps(self.user_data) 59 | elif channel_name.startswith('private-'): 60 | data['auth'] = self._generate_private_key( 61 | self.connection.socket_id, 62 | self.key, 63 | channel_name, 64 | self.secret 65 | ) 66 | 67 | self.connection.send_event('pusher:subscribe', data) 68 | 69 | self.channels[channel_name] = Channel(channel_name, self.connection) 70 | 71 | return self.channels[channel_name] 72 | 73 | def unsubscribe(self, channel_name): 74 | """Unsubscribe from a channel 75 | 76 | :param channel_name: The name of the channel to unsubscribe from. 77 | :type channel_name: str 78 | """ 79 | if channel_name in self.channels: 80 | self.connection.send_event( 81 | 'pusher:unsubscribe', { 82 | 'channel': channel_name, 83 | } 84 | ) 85 | del self.channels[channel_name] 86 | 87 | def channel(self, channel_name): 88 | """Get an existing channel object by name 89 | 90 | :param channel_name: The name of the channel you want to retrieve 91 | :type channel_name: str 92 | 93 | :rtype: Channel or None 94 | """ 95 | return self.channels.get(channel_name) 96 | 97 | def _connection_handler(self, event_name, data, channel_name): 98 | if channel_name in self.channels: 99 | self.channels[channel_name]._handle_event(event_name, data) 100 | 101 | @staticmethod 102 | def _generate_private_key(socket_id, key, channel_name, secret): 103 | auth_key = "" 104 | 105 | if socket_id and key and channel_name and secret: 106 | subject = "%s:%s" % (socket_id, channel_name) 107 | h = hmac.new(secret, subject, hashlib.sha256) 108 | auth_key = "%s:%s" % (key, h.hexdigest()) 109 | 110 | return auth_key 111 | 112 | @staticmethod 113 | def _generate_presence_key(socket_id, key, channel_name, secret, user_data): 114 | auth_key = "" 115 | 116 | if socket_id and key and channel_name and secret and user_data: 117 | subject = "%s:%s:%s" % (socket_id, channel_name, json.dumps(user_data)) 118 | h = hmac.new(secret, subject, hashlib.sha256) 119 | auth_key = "%s:%s" % (key, h.hexdigest()) 120 | 121 | return auth_key 122 | 123 | @classmethod 124 | def _build_url(cls, key, secure): 125 | path = "/app/%s?client=%s&version=%s&protocol=%s" % ( 126 | key, 127 | cls.client_id, 128 | VERSION, 129 | cls.protocol 130 | ) 131 | 132 | return "%s://%s:%s%s" % ( 133 | "wss" if secure else "ws", 134 | cls.host, 135 | 443 if secure else 80, 136 | path 137 | ) -------------------------------------------------------------------------------- /libs/pusherclient/channel.py: -------------------------------------------------------------------------------- 1 | class Channel(object): 2 | def __init__(self, channel_name, connection): 3 | self.name = channel_name 4 | 5 | self.connection = connection 6 | 7 | self.event_callbacks = {} 8 | 9 | def bind(self, event_name, callback): 10 | """Bind an event to a callback 11 | 12 | :param event_name: The name of the event to bind to. 13 | :type event_name: str 14 | 15 | :param callback: The callback to notify of this event. 16 | """ 17 | if event_name not in self.event_callbacks.keys(): 18 | self.event_callbacks[event_name] = [] 19 | 20 | self.event_callbacks[event_name].append(callback) 21 | 22 | def trigger(self, event_name, data): 23 | """Trigger an event on this channel. Only available for private or 24 | presence channels 25 | 26 | :param event_name: The name of the event. Must begin with 'client-'' 27 | :type event_name: str 28 | 29 | :param data: The data to send with the event. 30 | """ 31 | if self.connection: 32 | if event_name.startswith("client-"): 33 | if self.name.startswith("private-") or self.name.startswith("presence-"): 34 | self.connection.send_event(event_name, data, channel_name=self.name) 35 | 36 | def _handle_event(self, event_name, data): 37 | if event_name in self.event_callbacks.keys(): 38 | for callback in self.event_callbacks[event_name]: 39 | callback(data) -------------------------------------------------------------------------------- /libs/pyboleto/__init__.py: -------------------------------------------------------------------------------- 1 | __version__ = '0.2.11' 2 | -------------------------------------------------------------------------------- /libs/pyboleto/bank/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from ..data import BoletoException 3 | BANCOS_IMPLEMENTADOS = { 4 | '001': 'bancodobrasil.BoletoBB', 5 | '041': 'banrisul.BoletoBanrisul', 6 | '237': 'bradesco.BoletoBradesco', 7 | '104': 'caixa.BoletoCaixa', 8 | '399': 'hsbc.BoletoHsbc', 9 | '341': 'itau.BoletoItau', 10 | '356': 'real.BoletoReal', 11 | } 12 | 13 | 14 | def get_class_for_codigo(banco_codigo): 15 | """Retorna a classe que implementa o banco 16 | 17 | :param banco_codigo: 18 | :type banco_codigo: string 19 | :return: Classo do Banco subclasse de :class:`pyboleto.data.BoletoData` 20 | :rtype: :class:`pyboleto.data.BoletoData` 21 | """ 22 | try: 23 | banco = BANCOS_IMPLEMENTADOS[banco_codigo].split('.') 24 | except KeyError: 25 | raise(BoletoException('Este banco não é suportado.')) 26 | 27 | mod = __import__('pyboleto.bank.' + banco[0], 28 | globals(), locals(), [banco[1]]) 29 | 30 | return getattr(mod, banco[1]) 31 | -------------------------------------------------------------------------------- /libs/pyboleto/bank/bancodobrasil.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from ..data import BoletoData, custom_property 3 | 4 | 5 | class BoletoBB(BoletoData): 6 | ''' 7 | Gera Dados necessários para criação de boleto para o Banco do Brasil 8 | ''' 9 | 10 | agencia_cedente = custom_property('agencia_cedente', 4) 11 | conta_cedente = custom_property('conta_cedente', 8) 12 | 13 | def __init__(self, format_convenio, format_nnumero): 14 | ''' 15 | Construtor para boleto do Banco deo Brasil 16 | 17 | Args: 18 | format_convenio Formato do convenio 6, 7 ou 8 19 | format_nnumero Formato nosso numero 1 ou 2 20 | ''' 21 | super(BoletoBB, self).__init__() 22 | 23 | self.codigo_banco = "001" 24 | self.carteira = 18 25 | self.logo_image = "logo_bb.jpg" 26 | 27 | # Size of convenio 6, 7 or 8 28 | self.format_convenio = format_convenio 29 | 30 | # Nosso Numero format. 1 or 2 31 | # 1: Nosso Numero with 5 positions 32 | # 2: Nosso Numero with 17 positions 33 | self.format_nnumero = format_nnumero 34 | 35 | def format_nosso_numero(self): 36 | return "%s%s-%s" % ( 37 | self.convenio, 38 | self.nosso_numero, 39 | self.dv_nosso_numero 40 | ) 41 | 42 | # Nosso numero (sem dv) sao 11 digitos 43 | def _get_nosso_numero(self): 44 | return self._nosso_numero 45 | 46 | def _set_nosso_numero(self, val): 47 | val = str(val) 48 | if self.format_convenio == 6: 49 | if self.format_nnumero == 1: 50 | nn = val.zfill(5) 51 | elif self.format_nnumero == 2: 52 | nn = val.zfill(17) 53 | elif self.format_convenio == 7: 54 | nn = val.zfill(10) 55 | elif self.format_convenio == 8: 56 | nn = val.zfill(9) 57 | self._nosso_numero = nn 58 | 59 | nosso_numero = property(_get_nosso_numero, _set_nosso_numero) 60 | 61 | def _get_convenio(self): 62 | return self._convenio 63 | 64 | def _set_convenio(self, val): 65 | self._convenio = str(val).ljust(self.format_convenio, '0') 66 | convenio = property(_get_convenio, _set_convenio) 67 | 68 | @property 69 | def agencia_conta_cedente(self): 70 | return "%s-%s / %s-%s" % ( 71 | self.agencia_cedente, 72 | self.modulo11(self.agencia_cedente), 73 | self.conta_cedente, 74 | self.modulo11(self.conta_cedente) 75 | ) 76 | 77 | @property 78 | def dv_nosso_numero(self): 79 | return self.modulo11(self.convenio + self.nosso_numero) 80 | 81 | @property 82 | def campo_livre(self): 83 | if self.format_convenio in (7, 8): 84 | content = "000000%s%s%s" % (self.convenio, 85 | self.nosso_numero, 86 | self.carteira) 87 | elif self.format_convenio == 6: 88 | if self.format_nnumero == 1: 89 | content = "%s%s%s%s%s" % (self.convenio, 90 | self.nosso_numero, 91 | self.agencia_cedente, 92 | self.conta_cedente, 93 | self.carteira) 94 | if self.format_nnumero == 2: 95 | content = "%2s%s%2s" % (self.convenio, 96 | self.nosso_numero, 97 | '21' # numero do serviço 98 | ) 99 | return content 100 | -------------------------------------------------------------------------------- /libs/pyboleto/bank/banrisul.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from ..data import BoletoData, custom_property 3 | 4 | 5 | class BoletoBanrisul(BoletoData): 6 | conta_cedente = custom_property('conta_cedente', 6) 7 | nosso_numero = custom_property('nosso_numero', 8) 8 | 9 | def __init__(self): 10 | BoletoData.__init__(self) 11 | self.codigo_banco = "041" 12 | self.logo_image = "logo_banrisul.jpg" 13 | 14 | @property 15 | def campo_livre(self): 16 | content = '21%04d%07d%08d40' % (int(self.agencia_cedente), 17 | int(self.conta_cedente), 18 | int(self.nosso_numero)) 19 | return '%s%s' % (content, self._dv_campo_livre(content)) 20 | 21 | # From http://jrimum.org/bopepo/browser/trunk/src/br/com/nordestefomento/ 22 | # jrimum/bopepo/campolivre/AbstractCLBanrisul.java 23 | def _dv_campo_livre(self, campo_livre): 24 | dv = self.modulo10(campo_livre) 25 | while True: 26 | restoMod11 = self.modulo11(campo_livre + str(dv), 7, 1) 27 | if restoMod11 != 1: 28 | break 29 | dv += 1 30 | dv %= 10 31 | 32 | return str(dv) + str(11 - restoMod11) 33 | -------------------------------------------------------------------------------- /libs/pyboleto/bank/bradesco.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 2 | """ 3 | pyboleto.bank.bradesco 4 | ~~~~~~~~~~~~~~~~~~~~~~ 5 | 6 | Lógica para boletos do banco Bradesco. 7 | 8 | :copyright: © 2011 - 2012 by Eduardo Cereto Carvalho 9 | :license: BSD, see LICENSE for more details. 10 | 11 | """ 12 | from ..data import BoletoData, custom_property 13 | 14 | 15 | class BoletoBradesco(BoletoData): 16 | ''' 17 | Gera Dados necessários para criação de boleto para o banco Bradesco 18 | ''' 19 | 20 | nosso_numero = custom_property('nosso_numero', 11) 21 | agencia_cedente = custom_property('agencia_cedente', 4) 22 | conta_cedente = custom_property('conta_cedente', 7) 23 | 24 | def __init__(self): 25 | super(BoletoBradesco, self).__init__() 26 | 27 | self.codigo_banco = "237" 28 | self.logo_image = "logo_bancobradesco.jpg" 29 | self.carteira = '06' 30 | 31 | def format_nosso_numero(self): 32 | return "%s/%s-%s" % ( 33 | self.carteira, 34 | self.nosso_numero, 35 | self.dv_nosso_numero 36 | ) 37 | 38 | @property 39 | def dv_nosso_numero(self): 40 | resto2 = self.modulo11(self.nosso_numero, 7, 1) 41 | digito = 11 - resto2 42 | if digito == 10: 43 | dv = 'P' 44 | elif digito == 11: 45 | dv = 0 46 | else: 47 | dv = digito 48 | return dv 49 | 50 | @property 51 | def campo_livre(self): 52 | content = "%4s%2s%11s%7s%1s" % (self.agencia_cedente.split('-')[0], 53 | self.carteira, 54 | self.nosso_numero, 55 | self.conta_cedente.split('-')[0], 56 | '0' 57 | ) 58 | return content 59 | -------------------------------------------------------------------------------- /libs/pyboleto/bank/caixa.py: -------------------------------------------------------------------------------- 1 | #-*- coding: utf-8 -*- 2 | from ..data import BoletoData, custom_property 3 | 4 | 5 | class BoletoCaixa(BoletoData): 6 | ''' 7 | Gera Dados necessários para criação de boleto para o banco Caixa 8 | Economica Federal 9 | 10 | ''' 11 | 12 | conta_cedente = custom_property('conta_cedente', 11) 13 | ''' 14 | Este numero tem o inicio fixo 15 | Carteira SR: 80, 81 ou 82 16 | Carteira CR: 90 (Confirmar com gerente qual usar) 17 | 18 | ''' 19 | nosso_numero = custom_property('nosso_numero', 10) 20 | 21 | def __init__(self): 22 | super(BoletoCaixa, self).__init__() 23 | 24 | self.codigo_banco = "104" 25 | self.local_pagamento = "Preferencialmente nas Casas Lotéricas e \ 26 | Agências da Caixa" 27 | self.logo_image = "logo_bancocaixa.jpg" 28 | 29 | @property 30 | def dv_nosso_numero(self): 31 | resto2 = self.modulo11(self.nosso_numero.split('-')[0], 9, 1) 32 | digito = 11 - resto2 33 | if digito == 10 or digito == 11: 34 | dv = 0 35 | else: 36 | dv = digito 37 | return dv 38 | 39 | @property 40 | def campo_livre(self): 41 | content = "%10s%4s%11s" % (self.nosso_numero, 42 | self.agencia_cedente, 43 | self.conta_cedente.split('-')[0]) 44 | return content 45 | 46 | def format_nosso_numero(self): 47 | return self.nosso_numero + '-' + str(self.dv_nosso_numero) 48 | -------------------------------------------------------------------------------- /libs/pyboleto/bank/hsbc.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 2 | from ..data import BoletoData, custom_property 3 | 4 | 5 | ### CAUTION - NÃO TESTADO ### 6 | 7 | 8 | class BoletoHsbc(BoletoData): 9 | ''' 10 | Gera Dados necessários para criação de boleto para o banco HSBC 11 | ''' 12 | 13 | numero_documento = custom_property('numero_documento', 13) 14 | 15 | def __init__(self): 16 | super(BoletoHsbc, self).__init__() 17 | 18 | self.codigo_banco = "399" 19 | self.logo_image = "logo_bancohsbc.jpg" 20 | self.carteira = 'CNR' 21 | 22 | def format_nosso_numero(self): 23 | nosso_numero = self.nosso_numero 24 | # Primeiro DV 25 | nosso_numero += str(self.modulo11(nosso_numero)) 26 | # Cobrança com vencimento = 4 27 | nosso_numero += "4" 28 | # Segundo DV 29 | sum_params = int(nosso_numero) + int(self.conta_cedente) 30 | sum_params += int(self.data_vencimento.strftime('%d%m%y')) 31 | sum_params = str(sum_params) 32 | nosso_numero += str(self.modulo11(sum_params)) 33 | return nosso_numero 34 | 35 | @property 36 | def data_vencimento_juliano(self): 37 | data_vencimento = str(self.data_vencimento.timetuple().tm_yday) 38 | data_vencimento += str(self.data_vencimento.year)[-1:] 39 | return data_vencimento.zfill(4) 40 | 41 | @property 42 | def campo_livre(self): 43 | content = "%7s%13s%4s2" % (self.conta_cedente, 44 | self.nosso_numero, 45 | self.data_vencimento_juliano) 46 | return content 47 | 48 | 49 | class BoletoHsbcComRegistro(BoletoData): 50 | ''' 51 | Gera Dados necessários para criação de boleto para o banco HSBC 52 | com registro 53 | ''' 54 | # Nosso numero (sem dv) sao 10 digitos 55 | nosso_numero = custom_property('nosso_numero', 10) 56 | 57 | def __init__(self): 58 | super(BoletoHsbcComRegistro, self).__init__() 59 | 60 | self.codigo_banco = "399" 61 | self.logo_image = "logo_bancohsbc.jpg" 62 | self.carteira = 'CSB' 63 | self.especie_documento = 'PD' 64 | 65 | @property 66 | def dv_nosso_numero(self): 67 | resto = self.modulo11(self.nosso_numero, 7, 1) 68 | if resto == 0 or resto == 1: 69 | return 0 70 | else: 71 | return 11 - resto 72 | 73 | @property 74 | def campo_livre(self): 75 | content = "%10s%1s%4s%7s001" % (self.nosso_numero, 76 | self.dv_nosso_numero, 77 | self.agencia_cedente.split('-')[0], 78 | self.conta_cedente.split('-')[0]) 79 | return content 80 | -------------------------------------------------------------------------------- /libs/pyboleto/bank/itau.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 2 | from ..data import BoletoData, custom_property 3 | 4 | ### CAUTION - NÃO TESTADO ### 5 | 6 | 7 | class BoletoItau(BoletoData): 8 | '''Implementa Boleto Itaú 9 | 10 | Gera Dados necessários para criação de boleto para o banco Itau 11 | Todas as carteiras com excessão das que utilizam 15 dígitos: (106,107, 12 | 195,196,198) 13 | ''' 14 | 15 | # Nosso numero (sem dv) com 8 digitos 16 | nosso_numero = custom_property('nosso_numero', 8) 17 | # Conta (sem dv) com 5 digitos 18 | conta_cedente = custom_property('conta_cedente', 5) 19 | # Agência (sem dv) com 4 digitos 20 | agencia_cedente = custom_property('agencia_cedente', 4) 21 | carteira = custom_property('carteira', 3) 22 | 23 | def __init__(self): 24 | super(BoletoItau, self).__init__() 25 | 26 | self.codigo_banco = "341" 27 | self.logo_image = "logo_itau.jpg" 28 | self.especie_documento = 'DM' 29 | 30 | @property 31 | def dv_nosso_numero(self): 32 | composto = "%4s%5s%3s%8s" % (self.agencia_cedente, self.conta_cedente, 33 | self.carteira, self.nosso_numero) 34 | return self.modulo10(composto) 35 | 36 | @property 37 | def dv_agencia_conta_cedente(self): 38 | agencia_conta = "%s%s" % (self.agencia_cedente, self.conta_cedente) 39 | return self.modulo10(agencia_conta) 40 | 41 | @property 42 | def agencia_conta_cedente(self): 43 | return "%s/%s-%s" % (self.agencia_cedente, self.conta_cedente, 44 | self.dv_agencia_conta_cedente) 45 | 46 | def format_nosso_numero(self): 47 | return "%3s/%8s-%1s" % (self.carteira, self.nosso_numero, 48 | self.dv_nosso_numero) 49 | 50 | @property 51 | def campo_livre(self): 52 | content = "%3s%8s%1s%4s%5s%1s%3s" % (self.carteira, 53 | self.nosso_numero, 54 | self.dv_nosso_numero, 55 | self.agencia_cedente, 56 | self.conta_cedente, 57 | self.dv_agencia_conta_cedente, 58 | '000' 59 | ) 60 | return content 61 | -------------------------------------------------------------------------------- /libs/pyboleto/bank/real.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 2 | from ..data import BoletoData 3 | 4 | 5 | class BoletoReal(BoletoData): 6 | 7 | def __init__(self): 8 | super(BoletoReal, self).__init__() 9 | 10 | self.codigo_banco = "356" 11 | self.logo_image = "logo_bancoreal.jpg" 12 | 13 | @property 14 | def agencia_conta_cedente(self): 15 | dv = self.digitao_cobranca 16 | s = "%s/%s/%s" % (self.agencia_cedente, self.conta_cedente, dv) 17 | return s 18 | 19 | @property 20 | def digitao_cobranca(self): 21 | num = "%s%s%s" % ( 22 | self.nosso_numero, 23 | self.agencia_cedente, 24 | self.conta_cedente 25 | ) 26 | dv = self.modulo10(num) 27 | return dv 28 | 29 | def calculate_dv_barcode(self, line): 30 | dv = self.modulo11(line, r=1) 31 | if dv == 0 or dv == 1: 32 | dv = 1 33 | else: 34 | dv = 11 - dv 35 | return dv 36 | 37 | @property 38 | def campo_livre(self): 39 | content = "%4s%7s%1s%13s" % (self.agencia_cedente, 40 | self.conta_cedente, 41 | self.digitao_cobranca, 42 | self.nosso_numero) 43 | return content 44 | -------------------------------------------------------------------------------- /libs/pyboleto/bank/santander.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 2 | """ 3 | pyboleto.bank.santander 4 | ~~~~~~~~~~~~~~~~~~~~~~~ 5 | 6 | Lógica para boletos do banco Santander. 7 | Carteira ``'101'`` Com Registro 8 | Carteira ``'102'`` Sem Registro 9 | Carteira ``'201'`` Penhor Rápido Com Registro 10 | 11 | Baseado no projeto `BoletoPHP ` 12 | 13 | :copyright: © 2011 - 2012 by Eduardo Cereto Carvalho 14 | :license: BSD, see LICENSE for more details. 15 | 16 | """ 17 | from ..data import BoletoData, custom_property 18 | 19 | 20 | class BoletoSantander(BoletoData): 21 | ''' 22 | Gera Dados necessários para criação de boleto para o banco Santander 23 | ''' 24 | 25 | nosso_numero = custom_property('nosso_numero', 12) 26 | 27 | #: Também chamado de "ponto de venda" 28 | agencia_cedente = custom_property('agencia_cedente', 4) 29 | 30 | #: Também chamdo de código do cedente, se for uma conta de 9 dígitos 31 | #: ignorar os 2 primeiros 32 | conta_cedente = custom_property('conta_cedente', 7) 33 | 34 | def __init__(self): 35 | super(BoletoSantander, self).__init__() 36 | 37 | self.codigo_banco = "033" 38 | self.logo_image = "logo_santander.jpg" 39 | self.carteira = '102' 40 | # IOS - somente para Seguradoras (Se 7% informar 7, limitado 9%) 41 | # Demais clientes usar 0 (zero) 42 | self.ios = "0" 43 | 44 | def format_nosso_numero(self): 45 | return "%s-%s" % ( 46 | self.nosso_numero, 47 | self._dv_nosso_numero() 48 | ) 49 | 50 | def _dv_nosso_numero(self): 51 | return str(self.modulo11(self.nosso_numero, 9, 0)) 52 | 53 | @property 54 | def campo_livre(self): 55 | content = "".join([ 56 | '9', 57 | self.conta_cedente, 58 | self.nosso_numero, 59 | self._dv_nosso_numero(), 60 | self.ios, 61 | self.carteira, 62 | ]) 63 | return content 64 | -------------------------------------------------------------------------------- /libs/pyboleto/media/logo_bancobradesco.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blinktrade/bitex/a4896e7faef9c4aa0ca5325f18b77db67003764e/libs/pyboleto/media/logo_bancobradesco.jpg -------------------------------------------------------------------------------- /libs/pyboleto/media/logo_bancocaixa.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blinktrade/bitex/a4896e7faef9c4aa0ca5325f18b77db67003764e/libs/pyboleto/media/logo_bancocaixa.jpg -------------------------------------------------------------------------------- /libs/pyboleto/media/logo_bancohsbc.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blinktrade/bitex/a4896e7faef9c4aa0ca5325f18b77db67003764e/libs/pyboleto/media/logo_bancohsbc.jpg -------------------------------------------------------------------------------- /libs/pyboleto/media/logo_bancoreal.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blinktrade/bitex/a4896e7faef9c4aa0ca5325f18b77db67003764e/libs/pyboleto/media/logo_bancoreal.jpg -------------------------------------------------------------------------------- /libs/pyboleto/media/logo_banrisul.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blinktrade/bitex/a4896e7faef9c4aa0ca5325f18b77db67003764e/libs/pyboleto/media/logo_banrisul.jpg -------------------------------------------------------------------------------- /libs/pyboleto/media/logo_bb.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blinktrade/bitex/a4896e7faef9c4aa0ca5325f18b77db67003764e/libs/pyboleto/media/logo_bb.jpg -------------------------------------------------------------------------------- /libs/pyboleto/media/logo_itau.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blinktrade/bitex/a4896e7faef9c4aa0ca5325f18b77db67003764e/libs/pyboleto/media/logo_itau.jpg -------------------------------------------------------------------------------- /libs/pyboleto/media/logo_santander.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blinktrade/bitex/a4896e7faef9c4aa0ca5325f18b77db67003764e/libs/pyboleto/media/logo_santander.jpg -------------------------------------------------------------------------------- /libs/ws4py/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Redistribution and use in source and binary forms, with or without 4 | # modification, are permitted provided that the following conditions are 5 | # met: 6 | # 7 | # * Redistributions of source code must retain the above copyright 8 | # notice, this list of conditions and the following disclaimer. 9 | # * Redistributions in binary form must reproduce the above 10 | # copyright notice, this list of conditions and the following disclaimer 11 | # in the documentation and/or other materials provided with the 12 | # distribution. 13 | # * Neither the name of ws4py nor the names of its 14 | # contributors may be used to endorse or promote products derived from 15 | # this software without specific prior written permission. 16 | # 17 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 | # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 | # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 | # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 | # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 | # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 | # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 | # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 | # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | # 29 | import logging 30 | from ws4py.compat import enc 31 | 32 | __author__ = "Sylvain Hellegouarch" 33 | __version__ = "0.3.0-beta" 34 | __all__ = ['WS_KEY', 'WS_VERSION', 'configure_logger', 'format_addresses'] 35 | 36 | WS_KEY = enc("258EAFA5-E914-47DA-95CA-C5AB0DC85B11") 37 | WS_VERSION = (8, 13) 38 | 39 | def configure_logger(stdout=True, filepath=None, level=logging.INFO): 40 | logger = logging.getLogger('ws4py') 41 | logger.setLevel(level) 42 | logfmt = logging.Formatter("[%(asctime)s] %(levelname)s %(message)s") 43 | 44 | if filepath: 45 | h = handlers.RotatingFileHandler(filepath, maxBytes=10485760, backupCount=3) 46 | h.setLevel(level) 47 | h.setFormatter(logfmt) 48 | logger.addHandler(h) 49 | 50 | if stdout: 51 | import sys 52 | h = logging.StreamHandler(sys.stdout) 53 | h.setLevel(level) 54 | h.setFormatter(logfmt) 55 | logger.addHandler(h) 56 | 57 | return logger 58 | 59 | def format_addresses(ws): 60 | me_ip, me_port = ws.local_address 61 | peer_ip, peer_port = ws.peer_address 62 | return "[Local => %s:%d | Remote => %s:%d]" % (me_ip, me_port, peer_ip, peer_port) 63 | 64 | -------------------------------------------------------------------------------- /libs/ws4py/client/geventclient.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import copy 3 | 4 | import gevent 5 | from gevent import Greenlet 6 | from gevent.queue import Queue 7 | 8 | from ws4py.client import WebSocketBaseClient 9 | 10 | __all__ = ['WebSocketClient'] 11 | 12 | class WebSocketClient(WebSocketBaseClient): 13 | def __init__(self, url, protocols=None, extensions=None): 14 | """ 15 | WebSocket client that executes the 16 | :meth:`run() ` into a gevent greenlet. 17 | 18 | .. code-block:: python 19 | 20 | ws = WebSocketClient('ws://localhost:9000/echo', protocols=['http-only', 'chat']) 21 | ws.connect() 22 | 23 | ws.send("Hello world") 24 | 25 | def incoming(): 26 | while True: 27 | m = ws.receive() 28 | if m is not None: 29 | print str(m) 30 | else: 31 | break 32 | 33 | def outgoing(): 34 | for i in range(0, 40, 5): 35 | ws.send("*" * i) 36 | 37 | greenlets = [ 38 | gevent.spawn(incoming), 39 | gevent.spawn(outgoing), 40 | ] 41 | gevent.joinall(greenlets) 42 | """ 43 | WebSocketBaseClient.__init__(self, url, protocols, extensions) 44 | self._th = Greenlet(self.run) 45 | 46 | self.messages = Queue() 47 | """ 48 | Queue that will hold received messages. 49 | """ 50 | 51 | def handshake_ok(self): 52 | """ 53 | Called when the upgrade handshake has completed 54 | successfully. 55 | 56 | Starts the client's thread. 57 | """ 58 | self._th.start() 59 | 60 | def received_message(self, message): 61 | """ 62 | Override the base class to store the incoming message 63 | in the `messages` queue. 64 | """ 65 | self.messages.put(copy.deepcopy(message)) 66 | 67 | def closed(self, code, reason=None): 68 | """ 69 | Puts a :exc:`StopIteration` as a message into the 70 | `messages` queue. 71 | """ 72 | # When the connection is closed, put a StopIteration 73 | # on the message queue to signal there's nothing left 74 | # to wait for 75 | self.messages.put(StopIteration) 76 | 77 | def receive(self): 78 | """ 79 | Returns messages that were stored into the 80 | `messages` queue and returns `None` when the 81 | websocket is terminated or closed. 82 | """ 83 | # If the websocket was terminated and there are no messages 84 | # left in the queue, return None immediately otherwise the client 85 | # will block forever 86 | if self.terminated and self.messages.empty(): 87 | return None 88 | message = self.messages.get() 89 | if message is StopIteration: 90 | return None 91 | return message 92 | -------------------------------------------------------------------------------- /libs/ws4py/client/threadedclient.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import threading 3 | 4 | from ws4py.client import WebSocketBaseClient 5 | 6 | __all__ = ['WebSocketClient'] 7 | 8 | class WebSocketClient(WebSocketBaseClient): 9 | def __init__(self, url, protocols=None, extensions=None, heartbeat_freq=None): 10 | """ 11 | .. code-block:: python 12 | 13 | from ws4py.client.threadedclient import WebSocketClient 14 | 15 | class EchoClient(WebSocketClient): 16 | def opened(self): 17 | for i in range(0, 200, 25): 18 | self.send("*" * i) 19 | 20 | def closed(self, code, reason): 21 | print(("Closed down", code, reason)) 22 | 23 | def received_message(self, m): 24 | print("=> %d %s" % (len(m), str(m))) 25 | 26 | try: 27 | ws = EchoClient('ws://localhost:9000/echo', protocols=['http-only', 'chat']) 28 | ws.connect() 29 | except KeyboardInterrupt: 30 | ws.close() 31 | 32 | """ 33 | WebSocketBaseClient.__init__(self, url, protocols, extensions, heartbeat_freq) 34 | self._th = threading.Thread(target=self.run, name='WebSocketClient') 35 | self._th.daemon = True 36 | 37 | @property 38 | def daemon(self): 39 | """ 40 | `True` if the client's thread is set to be a daemon thread. 41 | """ 42 | return self._th.daemon 43 | 44 | @daemon.setter 45 | def daemon(self, flag): 46 | """ 47 | Set to `True` if the client's thread should be a daemon. 48 | """ 49 | self._th.daemon = flag 50 | 51 | def run_forever(self): 52 | """ 53 | Simply blocks the thread until the 54 | websocket has terminated. 55 | """ 56 | self._th.join() 57 | 58 | def handshake_ok(self): 59 | """ 60 | Called when the upgrade handshake has completed 61 | successfully. 62 | 63 | Starts the client's thread. 64 | """ 65 | self._th.start() 66 | 67 | if __name__ == '__main__': 68 | from ws4py.client.threadedclient import WebSocketClient 69 | 70 | class EchoClient(WebSocketClient): 71 | def opened(self): 72 | for i in range(0, 200, 25): 73 | self.send("*" * i) 74 | 75 | def closed(self, code, reason): 76 | print(("Closed down", code, reason)) 77 | 78 | def received_message(self, m): 79 | print("=> %d %s" % (len(m), str(m))) 80 | if len(m) == 175: 81 | self.close(reason='bye bye') 82 | 83 | try: 84 | ws = EchoClient('ws://localhost:9000/ws', protocols=['http-only', 'chat']) 85 | ws.connect() 86 | ws.run_forever() 87 | except KeyboardInterrupt: 88 | ws.close() 89 | -------------------------------------------------------------------------------- /libs/ws4py/compat.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | __doc__ = """ 3 | This compatibility module is inspired by the one found 4 | in CherryPy. It provides a common entry point for the various 5 | functions and types that are used with ws4py but which 6 | differ from Python 2.x to Python 3.x 7 | 8 | There are likely better ways for some of them so feel 9 | free to provide patches. 10 | 11 | Note this has been tested against 2.7 and 3.3 only but 12 | should hopefully work fine with other versions too. 13 | """ 14 | import sys 15 | 16 | if sys.version_info >= (3, 0): 17 | py3k = True 18 | from urllib.parse import urlsplit 19 | range = range 20 | unicode = str 21 | basestring = (bytes, str) 22 | _ord = ord 23 | 24 | def enc(b, encoding='utf-8'): 25 | if isinstance(b, str): 26 | return b.encode(encoding) 27 | elif isinstance(b, bytearray): 28 | return bytes(b) 29 | return b 30 | 31 | def dec(b, encoding='utf-8'): 32 | if isinstance(b, (bytes, bytearray)): 33 | return b.decode(encoding) 34 | return b 35 | 36 | def get_connection(fileobj): 37 | return fileobj.raw._sock 38 | 39 | def detach_connection(fileobj): 40 | fileobj.detach() 41 | 42 | def ord(c): 43 | if isinstance(c, int): 44 | return c 45 | return _ord(c) 46 | else: 47 | py3k = False 48 | from urlparse import urlsplit 49 | range = xrange 50 | unicode = unicode 51 | basestring = basestring 52 | ord = ord 53 | 54 | def enc(b, encoding='utf-8'): 55 | if isinstance(b, unicode): 56 | return b.encode(encoding) 57 | elif isinstance(b, bytearray): 58 | return str(b) 59 | return b 60 | 61 | def dec(b, encoding='utf-8'): 62 | if isinstance(b, (str, bytearray)): 63 | return b.decode(encoding) 64 | return b 65 | 66 | def get_connection(fileobj): 67 | return fileobj._sock 68 | 69 | def detach_connection(fileobj): 70 | fileobj._sock = None 71 | -------------------------------------------------------------------------------- /libs/ws4py/exc.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | __all__ = ['WebSocketException', 'FrameTooLargeException', 'ProtocolException', 4 | 'UnsupportedFrameTypeException', 'TextFrameEncodingException', 5 | 'UnsupportedFrameTypeException', 'TextFrameEncodingException', 6 | 'StreamClosed', 'HandshakeError', 'InvalidBytesError'] 7 | 8 | class WebSocketException(Exception): pass 9 | 10 | class ProtocolException(WebSocketException): pass 11 | 12 | class FrameTooLargeException(WebSocketException): pass 13 | 14 | class UnsupportedFrameTypeException(WebSocketException): pass 15 | 16 | class TextFrameEncodingException(WebSocketException): pass 17 | 18 | class InvalidBytesError(WebSocketException): pass 19 | 20 | class StreamClosed(Exception): pass 21 | 22 | class HandshakeError(WebSocketException): 23 | def __init__(self, msg): 24 | self.msg = msg 25 | 26 | def __str__(self): 27 | return self.msg 28 | -------------------------------------------------------------------------------- /libs/ws4py/server/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blinktrade/bitex/a4896e7faef9c4aa0ca5325f18b77db67003764e/libs/ws4py/server/__init__.py -------------------------------------------------------------------------------- /libs/ws4py/server/geventserver.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | __doc__ = """ 3 | WSGI entities to support WebSocket from within gevent. 4 | 5 | Its usage is rather simple: 6 | 7 | .. code-block: python 8 | 9 | from gevent import monkey; monkey.patch_all() 10 | from ws4py.websocket import EchoWebSocket 11 | from ws4py.server.geventserver import WSGIServer 12 | from ws4py.server.wsgiutils import WebSocketWSGIApplication 13 | 14 | server = WSGIServer(('localhost', 9000), WebSocketWSGIApplication(handler_cls=EchoWebSocket)) 15 | server.serve_forever() 16 | 17 | """ 18 | import logging 19 | import sys 20 | 21 | import gevent 22 | from gevent.pywsgi import WSGIHandler, WSGIServer as _WSGIServer 23 | from gevent.pool import Group 24 | 25 | from ws4py import format_addresses 26 | from ws4py.server.wsgiutils import WebSocketWSGIApplication 27 | 28 | logger = logging.getLogger('ws4py') 29 | 30 | __all__ = ['WebSocketWSGIHandler', 'WSGIServer'] 31 | 32 | class WebSocketWSGIHandler(WSGIHandler): 33 | """ 34 | A WSGI handler that will perform the :rfc:`6455` 35 | upgrade and handshake before calling the WSGI application. 36 | 37 | If the incoming request doesn't have a `'Upgrade'` header, 38 | the handler will simply fallback to the gevent builtin's handler 39 | and process it as per usual. 40 | """ 41 | 42 | def run_application(self): 43 | upgrade_header = self.environ.get('HTTP_UPGRADE', '').lower() 44 | if upgrade_header: 45 | try: 46 | # Build and start the HTTP response 47 | self.environ['ws4py.socket'] = self.socket or self.environ['wsgi.input'].rfile._sock 48 | self.result = self.application(self.environ, self.start_response) or [] 49 | self.process_result() 50 | except: 51 | raise 52 | else: 53 | del self.environ['ws4py.socket'] 54 | self.socket = None 55 | self.rfile.close() 56 | 57 | ws = self.environ.pop('ws4py.websocket') 58 | if ws: 59 | self.server.link_websocket_to_server(ws) 60 | else: 61 | gevent.pywsgi.WSGIHandler.run_application(self) 62 | 63 | class WSGIServer(_WSGIServer): 64 | handler_class = WebSocketWSGIHandler 65 | 66 | def __init__(self, *args, **kwargs): 67 | """ 68 | WSGI server that simply tracks websockets 69 | and send them a proper closing handshake 70 | when the server terminates. 71 | 72 | Other than that, the server is the same 73 | as its :class:`gevent.pywsgi.WSGIServer` 74 | base. 75 | """ 76 | _WSGIServer.__init__(self, *args, **kwargs) 77 | self._websockets = Group() 78 | 79 | def link_websocket_to_server(self, websocket): 80 | logger.info("Managing websocket %s" % format_addresses(websocket)) 81 | self._websockets.spawn(websocket.run) 82 | 83 | def stop(self, *args, **kwargs): 84 | logger.info("Terminating server and all connected websockets") 85 | for greenlet in self._websockets: 86 | try: 87 | websocket = greenlet._run.im_self 88 | if websocket: 89 | websocket.close(1001, 'Server is shutting down') 90 | except: 91 | pass 92 | _WSGIServer.stop(self, *args, **kwargs) 93 | 94 | if __name__ == '__main__': 95 | from ws4py import configure_logger 96 | configure_logger() 97 | 98 | from ws4py.websocket import EchoWebSocket 99 | server = WSGIServer(('127.0.0.1', 9000), 100 | WebSocketWSGIApplication(handler_cls=EchoWebSocket)) 101 | server.serve_forever() 102 | -------------------------------------------------------------------------------- /logs/README: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blinktrade/bitex/a4896e7faef9c4aa0ca5325f18b77db67003764e/logs/README -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | pyzmq>=14.3.1 2 | crypto>=1.1.0 3 | tornado>=4.1 4 | sqlalchemy>=0.9.7 5 | requests>=2.3.0 6 | appdirs 7 | mailchimp 8 | pycountry 9 | pyboleto 10 | mock 11 | -------------------------------------------------------------------------------- /static/404.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | A página que você está procurando não existe (404) 5 | 6 | 7 | 8 | 9 | 18 | 19 | 20 | 21 | 22 | 29 | 30 |
31 | 32 |
33 |
34 |
35 |
36 |

A página não existe! Erro 404

37 |
38 |

A página que você procura não existe em nosso servidor. Isso pode ser um erro de digitação, ou um erro em nosso servidor. Aperte o botão Voltar do seu browser para voltar a página anterior

39 |

Ou vá para a nossa página inicial:

40 | BlinkTrade 41 |
42 |
43 |

44 |
45 |
46 |
47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /static/422.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | The change you wanted was rejected (422) 5 | 17 | 18 | 19 | 20 | 21 |
22 |

The change you wanted was rejected.

23 |

Maybe you tried to change something you didn't have access to.

24 |
25 | 26 | 27 | -------------------------------------------------------------------------------- /static/500.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | We're sorry, but something went wrong (500) 5 | 43 | 44 | 45 | 46 | 47 |
48 |

Ops!

49 |

Fomos notificados sobre este problema e vamos dar uma olhada em breve.

50 |
51 | 52 | 53 | -------------------------------------------------------------------------------- /static/chart.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 85 | 86 | 87 | 88 | 89 |
90 | 91 | 92 | -------------------------------------------------------------------------------- /static/css/Dialog.css: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2009 The Closure Library Authors. All Rights Reserved. 3 | * 4 | * Use of this source code is governed by the Apache License, Version 2.0. 5 | * See the COPYING file for details. 6 | */ 7 | 8 | /* 9 | * Standard styling for goog.ui.Dialog. 10 | * 11 | * @author ssaviano@google.com (Steven Saviano) 12 | * @author attila@google.com (Attila Bodis) 13 | */ 14 | 15 | .modal-dialog { 16 | background: #c1d9ff; 17 | border: 1px solid #3a5774; 18 | color: #000; 19 | padding: 4px; 20 | position: absolute; 21 | } 22 | 23 | .modal-dialog a, 24 | .modal-dialog a:link, 25 | .modal-dialog a:visited { 26 | color: #06c; 27 | cursor: pointer; 28 | } 29 | 30 | .modal-dialog-bg { 31 | background: #666; 32 | left: 0; 33 | position: absolute; 34 | top: 0; 35 | } 36 | 37 | .modal-dialog-title { 38 | background: #e0edfe; 39 | color: #000; 40 | cursor: pointer; 41 | font-size: 120%; 42 | font-weight: bold; 43 | 44 | /* Add padding on the right to ensure the close button has room. */ 45 | padding: 8px 31px 8px 8px; 46 | 47 | position: relative; 48 | _zoom: 1; /* Ensures proper width in IE6 RTL. */ 49 | } 50 | 51 | .modal-dialog-title-close { 52 | /* Client apps may override the URL at which they serve the sprite. */ 53 | background: #e0edfe url(http://ssl.gstatic.com/editor/editortoolbar.png) no-repeat -528px 0; 54 | cursor: default; 55 | height: 15px; 56 | position: absolute; 57 | right: 10px; 58 | top: 8px; 59 | width: 15px; 60 | vertical-align: middle; 61 | } 62 | 63 | .modal-dialog-buttons, 64 | .modal-dialog-content { 65 | background-color: #fff; 66 | padding: 8px; 67 | } 68 | 69 | .goog-buttonset-default { 70 | font-weight: bold; 71 | } 72 | 73 | /* Need to override bootstrap */ 74 | .modal {margin: 0;} -------------------------------------------------------------------------------- /static/css/sticky.css: -------------------------------------------------------------------------------- 1 | .sticky-queue{z-index:100;position:fixed;background:#fff;border:1px solid #999999;-moz-box-shadow:0 0 5px #bbb;-webkit-box-shadow:0 0 5px #bbb;box-shadow:0 0 5px #bbb;width:250px;overflow:hidden}.sticky-note{padding-right:20px;margin:0}.sticky{font-size:12px;color:#555;display:none;padding:10px;position:relative}.sticky-close{position:absolute;top:10px;right:10px;height:14px;width:14px;cursor:pointer}.sticky-close:before{content:"\2716"}.top-right{right:20px}.top-center{top:-2px;left:50%;margin-left:-125px}.top-left{left:20px}.top-right,.top-center,.top-left{top:-2px;-moz-border-radius-bottomleft:6px;-webkit-border-bottom-left-radius:6px;border-bottom-left-radius:6px;-moz-border-radius-bottomright:6px;-webkit-border-bottom-right-radius:6px;border-bottom-right-radius:6px}.bottom-right{right:20px}.bottom-center{bottom:-2px;left:50%;margin-left:-125px}.bottom-left{left:20px}.bottom-right,.bottom-center,.bottom-left{bottom:-2px;-moz-border-radius-topleft:6px;-webkit-border-top-left-radius:6px;border-top-left-radius:6px;-moz-border-radius-topright:6px;-webkit-border-top-right-radius:6px;border-top-right-radius:6px}.border-top-right,.border-top-center,.border-top-left{border-top:1px solid #999}.border-bottom-right,.border-bottom-center,.border-bottom-left{border-bottom:1px solid #999} 2 | -------------------------------------------------------------------------------- /static/font/FontAwesome.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blinktrade/bitex/a4896e7faef9c4aa0ca5325f18b77db67003764e/static/font/FontAwesome.otf -------------------------------------------------------------------------------- /static/font/fontawesome-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blinktrade/bitex/a4896e7faef9c4aa0ca5325f18b77db67003764e/static/font/fontawesome-webfont.eot -------------------------------------------------------------------------------- /static/font/fontawesome-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blinktrade/bitex/a4896e7faef9c4aa0ca5325f18b77db67003764e/static/font/fontawesome-webfont.ttf -------------------------------------------------------------------------------- /static/font/fontawesome-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blinktrade/bitex/a4896e7faef9c4aa0ca5325f18b77db67003764e/static/font/fontawesome-webfont.woff -------------------------------------------------------------------------------- /static/guaranibitcoin_tos.html: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blinktrade/bitex/a4896e7faef9c4aa0ca5325f18b77db67003764e/static/guaranibitcoin_tos.html -------------------------------------------------------------------------------- /static/images/UrduBit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blinktrade/bitex/a4896e7faef9c4aa0ca5325f18b77db67003764e/static/images/UrduBit.png -------------------------------------------------------------------------------- /static/images/UrduBitBeta.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blinktrade/bitex/a4896e7faef9c4aa0ca5325f18b77db67003764e/static/images/UrduBitBeta.png -------------------------------------------------------------------------------- /static/images/UrduBitFront.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blinktrade/bitex/a4896e7faef9c4aa0ca5325f18b77db67003764e/static/images/UrduBitFront.png -------------------------------------------------------------------------------- /static/images/UrduBitFrontBeta.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blinktrade/bitex/a4896e7faef9c4aa0ca5325f18b77db67003764e/static/images/UrduBitFrontBeta.png -------------------------------------------------------------------------------- /static/images/bitcoin-center-black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blinktrade/bitex/a4896e7faef9c4aa0ca5325f18b77db67003764e/static/images/bitcoin-center-black.png -------------------------------------------------------------------------------- /static/images/bitcoin-center.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blinktrade/bitex/a4896e7faef9c4aa0ca5325f18b77db67003764e/static/images/bitcoin-center.png -------------------------------------------------------------------------------- /static/images/bitcoin32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blinktrade/bitex/a4896e7faef9c4aa0ca5325f18b77db67003764e/static/images/bitcoin32.png -------------------------------------------------------------------------------- /static/images/bitcoin530.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blinktrade/bitex/a4896e7faef9c4aa0ca5325f18b77db67003764e/static/images/bitcoin530.png -------------------------------------------------------------------------------- /static/images/bitcoin64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blinktrade/bitex/a4896e7faef9c4aa0ca5325f18b77db67003764e/static/images/bitcoin64.png -------------------------------------------------------------------------------- /static/images/bitex.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blinktrade/bitex/a4896e7faef9c4aa0ca5325f18b77db67003764e/static/images/bitex.png -------------------------------------------------------------------------------- /static/images/bitex2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blinktrade/bitex/a4896e7faef9c4aa0ca5325f18b77db67003764e/static/images/bitex2.png -------------------------------------------------------------------------------- /static/images/blinktrade-demo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blinktrade/bitex/a4896e7faef9c4aa0ca5325f18b77db67003764e/static/images/blinktrade-demo.png -------------------------------------------------------------------------------- /static/images/blinktrade.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blinktrade/bitex/a4896e7faef9c4aa0ca5325f18b77db67003764e/static/images/blinktrade.png -------------------------------------------------------------------------------- /static/images/coinstrabeta.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blinktrade/bitex/a4896e7faef9c4aa0ca5325f18b77db67003764e/static/images/coinstrabeta.png -------------------------------------------------------------------------------- /static/images/coinstrabeta2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blinktrade/bitex/a4896e7faef9c4aa0ca5325f18b77db67003764e/static/images/coinstrabeta2.png -------------------------------------------------------------------------------- /static/images/comprabitcoin2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blinktrade/bitex/a4896e7faef9c4aa0ca5325f18b77db67003764e/static/images/comprabitcoin2.png -------------------------------------------------------------------------------- /static/images/cryptos-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blinktrade/bitex/a4896e7faef9c4aa0ca5325f18b77db67003764e/static/images/cryptos-white.png -------------------------------------------------------------------------------- /static/images/cryptos.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blinktrade/bitex/a4896e7faef9c4aa0ca5325f18b77db67003764e/static/images/cryptos.png -------------------------------------------------------------------------------- /static/images/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blinktrade/bitex/a4896e7faef9c4aa0ca5325f18b77db67003764e/static/images/favicon.ico -------------------------------------------------------------------------------- /static/images/guaranibitcoinbeta.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blinktrade/bitex/a4896e7faef9c4aa0ca5325f18b77db67003764e/static/images/guaranibitcoinbeta.png -------------------------------------------------------------------------------- /static/images/guaranibitcoinbeta2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blinktrade/bitex/a4896e7faef9c4aa0ca5325f18b77db67003764e/static/images/guaranibitcoinbeta2.png -------------------------------------------------------------------------------- /static/images/preload.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blinktrade/bitex/a4896e7faef9c4aa0ca5325f18b77db67003764e/static/images/preload.gif -------------------------------------------------------------------------------- /static/images/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blinktrade/bitex/a4896e7faef9c4aa0ca5325f18b77db67003764e/static/images/screenshot.png -------------------------------------------------------------------------------- /static/images/surbitcoin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blinktrade/bitex/a4896e7faef9c4aa0ca5325f18b77db67003764e/static/images/surbitcoin.png -------------------------------------------------------------------------------- /static/images/surbitcoin_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blinktrade/bitex/a4896e7faef9c4aa0ca5325f18b77db67003764e/static/images/surbitcoin_logo.png -------------------------------------------------------------------------------- /static/images/surbitcoin_logo_ven.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blinktrade/bitex/a4896e7faef9c4aa0ca5325f18b77db67003764e/static/images/surbitcoin_logo_ven.png -------------------------------------------------------------------------------- /static/images/surbitcoinbeta.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blinktrade/bitex/a4896e7faef9c4aa0ca5325f18b77db67003764e/static/images/surbitcoinbeta.png -------------------------------------------------------------------------------- /static/images/surbitcoinbeta2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blinktrade/bitex/a4896e7faef9c4aa0ca5325f18b77db67003764e/static/images/surbitcoinbeta2.png -------------------------------------------------------------------------------- /static/images/ubuntubitx-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blinktrade/bitex/a4896e7faef9c4aa0ca5325f18b77db67003764e/static/images/ubuntubitx-logo.png -------------------------------------------------------------------------------- /static/img/bitcoin_wallpaper_libertas_aequitas_vertas_2-copie.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blinktrade/bitex/a4896e7faef9c4aa0ca5325f18b77db67003764e/static/img/bitcoin_wallpaper_libertas_aequitas_vertas_2-copie.png -------------------------------------------------------------------------------- /static/img/glyphicons-halflings-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blinktrade/bitex/a4896e7faef9c4aa0ca5325f18b77db67003764e/static/img/glyphicons-halflings-white.png -------------------------------------------------------------------------------- /static/img/glyphicons-halflings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blinktrade/bitex/a4896e7faef9c4aa0ca5325f18b77db67003764e/static/img/glyphicons-halflings.png -------------------------------------------------------------------------------- /static/img/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blinktrade/bitex/a4896e7faef9c4aa0ca5325f18b77db67003764e/static/img/logo.png -------------------------------------------------------------------------------- /static/img/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blinktrade/bitex/a4896e7faef9c4aa0ca5325f18b77db67003764e/static/img/screenshot.png -------------------------------------------------------------------------------- /static/js/externs/parsley.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {=(string)} opt_method 3 | * @return {jQuery} 4 | */ 5 | jQuery.prototype.parsley = function(opt_method) {}; 6 | -------------------------------------------------------------------------------- /static/js/parsley.extend.min.js: -------------------------------------------------------------------------------- 1 | /* Parsley dist/parsley.extend.min.js build version 1.1.15 http://parsleyjs.org */ 2 | window.ParsleyConfig=window.ParsleyConfig||{}; 3 | (function(d){window.ParsleyConfig=d.extend(!0,{},window.ParsleyConfig,{validators:{minwords:function(a,b){a=a.replace(/(^\s*)|(\s*$)/gi,"");a=a.replace(/[ ]{2,}/gi," ");a=a.replace(/\n /,"\n");a=a.split(" ").length;return a>=b},maxwords:function(a,b){a=a.replace(/(^\s*)|(\s*$)/gi,"");a=a.replace(/[ ]{2,}/gi," ");a=a.replace(/\n /,"\n");a=a.split(" ").length;return a<=b},rangewords:function(a,b){a=a.replace(/(^\s*)|(\s*$)/gi,"");a=a.replace(/[ ]{2,}/gi," ");a=a.replace(/\n /,"\n");a=a.split(" ").length; 4 | return a>=b[0]&&a<=b[1]},greaterthan:function(a,b,c){c.options.validateIfUnchanged=!0;return new Number(a)>new Number(d(b).val())},lessthan:function(a,b,c){c.options.validateIfUnchanged=!0;return new Number(a)a?c+a:c+(a-9)):c+=a;return 0===c%10}},messages:{minwords:"This value should have %s words at least.",maxwords:"This value should have %s words maximum.",rangewords:"This value should have between %s and %s words.",greaterthan:"This value should be greater than %s.",lessthan:"This value should be less than %s.",beforedate:"This date should be before %s.",afterdate:"This date should be after %s.", 6 | luhn:"This value should pass the luhn test."}})})(window.jQuery||window.Zepto); 7 | -------------------------------------------------------------------------------- /static/js/sticky.js: -------------------------------------------------------------------------------- 1 | /* 2 | Sticky v2.1.2 by Andy Matthews 3 | http://twitter.com/commadelimited 4 | 5 | forked from Sticky by Daniel Raftery 6 | http://twitter.com/ThrivingKings 7 | */ 8 | (function ($) { 9 | 10 | $.sticky = $.fn.sticky = function (note, options, callback) { 11 | 12 | // allow options to be ignored, and callback to be second argument 13 | if (typeof options === 'function') callback = options; 14 | 15 | // generate unique ID based on the hash of the note. 16 | var hashCode = function(str){ 17 | var hash = 0, 18 | i = 0, 19 | c = '', 20 | len = str.length; 21 | if (len === 0) return hash; 22 | for (i = 0; i < len; i++) { 23 | c = str.charCodeAt(i); 24 | hash = ((hash<<5)-hash) + c; 25 | hash &= hash; 26 | } 27 | return 's'+Math.abs(hash); 28 | }, 29 | o = { 30 | position: 'top-right', // top-left, top-right, bottom-left, or bottom-right 31 | speed: 'fast', // animations: fast, slow, or integer 32 | allowdupes: true, // true or false 33 | autoclose: 5000, // delay in milliseconds. Set to 0 to remain open. 34 | classList: '' // arbitrary list of classes. Suggestions: success, warning, important, or info. Defaults to ''. 35 | }, 36 | uniqID = hashCode(note), // a relatively unique ID 37 | display = true, 38 | duplicate = false, 39 | tmpl = '

NOTE

', 40 | positions = ['top-right', 'top-center', 'top-left', 'bottom-right', 'bottom-center', 'bottom-left']; 41 | 42 | // merge default and incoming options 43 | if (options) $.extend(o, options); 44 | 45 | // Handling duplicate notes and IDs 46 | $('.sticky').each(function () { 47 | if ($(this).attr('id') === hashCode(note)) { 48 | duplicate = true; 49 | if (!o.allowdupes) display = false; 50 | } 51 | if ($(this).attr('id') === uniqID) uniqID = hashCode(note); 52 | }); 53 | 54 | // Make sure the sticky queue exists 55 | if (!$('.sticky-queue').length) { 56 | $('body').append('
'); 57 | } else { 58 | // if it exists already, but the position param is different, 59 | // then allow it to be overridden 60 | $('.sticky-queue').removeClass( positions.join(' ') ).addClass(o.position); 61 | } 62 | 63 | // Can it be displayed? 64 | if (display) { 65 | // Building and inserting sticky note 66 | $('.sticky-queue').prepend( 67 | tmpl 68 | .replace('POS', o.position) 69 | .replace('ID', uniqID) 70 | .replace('NOTE', note) 71 | .replace('CLASSLIST', o.classList) 72 | ).find('#' + uniqID) 73 | .slideDown(o.speed, function(){ 74 | display = true; 75 | // Callback function? 76 | if (callback && typeof callback === 'function') { 77 | callback({ 78 | 'id': uniqID, 79 | 'duplicate': duplicate, 80 | 'displayed': display 81 | }); 82 | } 83 | }); 84 | 85 | } 86 | 87 | // Listeners 88 | $('.sticky').ready(function () { 89 | // If 'autoclose' is enabled, set a timer to close the sticky 90 | if (o.autoclose) { 91 | $('#' + uniqID).delay(o.autoclose).fadeOut(o.speed, function(){ 92 | // remove element from DOM 93 | $(this).remove(); 94 | }); 95 | } 96 | }); 97 | 98 | // Closing a sticky 99 | $('.sticky-close').on('click', function () { 100 | $('#' + $(this).parent().attr('id')).dequeue().fadeOut(o.speed, function(){ 101 | // remove element from DOM 102 | $(this).remove(); 103 | }); 104 | }); 105 | 106 | }; 107 | })(jQuery); -------------------------------------------------------------------------------- /static/js/sticky.min.js: -------------------------------------------------------------------------------- 1 | /*! sticky 24-01-2014 */ 2 | !function(a){a.sticky=a.fn.sticky=function(b,c,d){"function"==typeof c&&(d=c);var e=function(a){var b=0,c=0,d="",e=a.length;if(0===e)return b;for(c=0;e>c;c++)d=a.charCodeAt(c),b=(b<<5)-b+d,b&=b;return"s"+Math.abs(b)},f={position:"top-right",speed:"fast",allowdupes:!0,autoclose:5e3,classList:""},g=e(b),h=!0,i=!1,j='

NOTE

',k=["top-right","top-center","top-left","bottom-right","bottom-center","bottom-left"];c&&a.extend(f,c),a(".sticky").each(function(){a(this).attr("id")===e(b)&&(i=!0,f.allowdupes||(h=!1)),a(this).attr("id")===g&&(g=e(b))}),a(".sticky-queue").length?a(".sticky-queue").removeClass(k.join(" ")).addClass(f.position):a("body").append('
'),h&&a(".sticky-queue").prepend(j.replace("POS",f.position).replace("ID",g).replace("NOTE",b).replace("CLASSLIST",f.classList)).find("#"+g).slideDown(f.speed,function(){h=!0,d&&"function"==typeof d&&d({id:g,duplicate:i,displayed:h})}),a(".sticky").ready(function(){f.autoclose&&a("#"+g).delay(f.autoclose).fadeOut(f.speed,function(){a(this).remove()})}),a(".sticky-close").on("click",function(){a("#"+a(this).parent().attr("id")).dequeue().fadeOut(f.speed,function(){a(this).remove()})})}}(jQuery); -------------------------------------------------------------------------------- /static/surbitcoin_maintenance.html: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | SurBitcoin – El primer mercado de bitcoin de Venezuela. 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 21 | 22 | 23 | 24 | 25 | 26 | 29 | 30 | 31 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 66 | 67 |
68 | 69 |
70 |
71 | 72 | 73 | 74 |
75 |
76 | 77 |

78 | Estamos realizando operaciones de mantenimiento. Disculpen las molestias.
79 | Estaremos de vuelta en una hora 80 |

81 |
82 |
83 | 84 | 85 | 95 | 96 | 97 | 98 | 99 | -------------------------------------------------------------------------------- /static/surbitcoin_tos.html: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blinktrade/bitex/a4896e7faef9c4aa0ca5325f18b77db67003764e/static/surbitcoin_tos.html -------------------------------------------------------------------------------- /tools/__init__.py: -------------------------------------------------------------------------------- 1 | __author__ = 'rodrigo' 2 | -------------------------------------------------------------------------------- /tools/arbitrage/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blinktrade/bitex/a4896e7faef9c4aa0ca5325f18b77db67003764e/tools/arbitrage/__init__.py -------------------------------------------------------------------------------- /tools/arbitrage/arbitrage.ini: -------------------------------------------------------------------------------- 1 | [bitstamp1] 2 | websocket_url= wss://api.testnet.blinktrade.com/trade/ 3 | username = user 4 | password = abc12345 5 | buy_fee = 0 6 | sell_fee = 0 7 | broker_id=5 8 | dest_market=BTCUSD 9 | 10 | [bitstamp] 11 | websocket_url= wss://api.testnet.blinktrade.com/trade/ 12 | username = user 13 | password = abc12345 14 | buy_fee = -2.00 15 | sell_fee = 2.00 16 | broker_id=5 17 | dest_market=BTCUSD 18 | 19 | 20 | [b2u] 21 | websocket_url= wss://api.testnet.blinktrade.com/trade/ 22 | broker_id=5 23 | username = user 24 | password = abc12345 25 | buy_fee = 0 26 | sell_fee = 0 27 | broker_id=5 28 | dest_market=BTCUSD 29 | 30 | 31 | [basebit] 32 | websocket_url= wss://api.testnet.blinktrade.com/trade/ 33 | username = user 34 | password = abc12345 35 | buy_fee = 0 36 | sell_fee = 0 37 | broker_id=5 38 | dest_market=BTCUSD 39 | 40 | 41 | [bitfinex] 42 | websocket_url= wss://api.testnet.blinktrade.com/trade/ 43 | username = user 44 | password = abc12345 45 | buy_fee = 0 46 | sell_fee = 0 47 | broker_id=5 48 | dest_market=BTCUSD 49 | 50 | 51 | [bitinvest] 52 | websocket_url= wss://api.testnet.blinktrade.com/trade/ 53 | username = user 54 | password = abc12345 55 | buy_fee = 0 56 | sell_fee = 0 57 | subscription_api_key = fc848c1b8ead44bc99db3a80f7dfb882 58 | broker_id=5 59 | dest_market=BTCUSD 60 | 61 | 62 | [hitbtc] 63 | websocket_url= wss://api.testnet.blinktrade.com/trade/ 64 | username = user 65 | password = abc12345 66 | buy_fee = 0 67 | sell_fee = 0 68 | broker_id=5 69 | dest_market=BTCUSD 70 | 71 | [itbit1] 72 | websocket_url= wss://api.testnet.blinktrade.com/trade/ 73 | username = user 74 | password = abc12345 75 | buy_fee = 0 76 | sell_fee = 0 77 | broker_id=5 78 | dest_market=BTCUSD 79 | 80 | [mb] 81 | websocket_url= wss://api.testnet.blinktrade.com/trade/ 82 | username = user 83 | password = abc12345 84 | buy_fee = 0 85 | sell_fee = 0 86 | broker_id=5 87 | dest_market=BTCUSD 88 | 89 | -------------------------------------------------------------------------------- /tools/arbitrage/b2u.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import sys 3 | import urllib2 4 | from time import sleep 5 | import json 6 | 7 | from arbitrator import BlinkTradeArbitrator 8 | 9 | import datetime 10 | import hmac 11 | import hashlib 12 | import ConfigParser 13 | from ws4py.exc import HandshakeError 14 | 15 | 16 | B2U_API_KEY = 'XXXX' 17 | B2U_API_SECRET = 'YYYY' 18 | 19 | def send_order_to_b2u(sender, order): 20 | nonce = datetime.datetime.now().strftime('%s') 21 | message = str(nonce) + '.blinktrade.' + str(B2U_API_KEY) 22 | signature = hmac.new(B2U_API_SECRET, msg=message, digestmod=hashlib.sha256).hexdigest().upper() 23 | 24 | post_params = { 25 | 'key': B2U_API_KEY, 26 | 'signature': signature, 27 | 'nonce': nonce, 28 | 'amount': float(order['OrderQty']/1.e8), 29 | 'price': float(order['Price'] / 1.e8) 30 | } 31 | 32 | if msg['Side'] == '1': 33 | print datetime.datetime.now(), 'POST https://www.bitcointoyou.com/api/buy/', str(post_params) 34 | elif msg['Side'] == '2': 35 | print datetime.datetime.now(), 'POST https://www.bitcointoyou.com/api/sell/', str(post_params) 36 | 37 | 38 | def main(): 39 | candidates = ['arbitrage.ini', 'b2u.ini' ] 40 | if len(sys.argv) > 1: 41 | candidates.append(sys.argv[1]) 42 | 43 | 44 | config = ConfigParser.SafeConfigParser({ 45 | 'websocket_url': 'wss://127.0.0.1/trade/', 46 | 'username': '', 47 | 'password': '', 48 | 'broker_id': 5, 49 | 'buy_fee': 0, 50 | 'sell_fee': 0, 51 | 'api_key': 'KEY', 52 | 'api_secret': 'SECRET' 53 | }) 54 | config.read( candidates ) 55 | 56 | websocket_url = config.get('b2u', 'websocket_url') 57 | username = config.get('b2u', 'username') 58 | password = config.get('b2u', 'password') 59 | buy_fee = int(config.get('b2u', 'buy_fee')) 60 | sell_fee = int(config.get('b2u', 'sell_fee')) 61 | api_key = config.get('b2u', 'api_key') 62 | api_secret = config.get('b2u', 'api_secret') 63 | broker_id = config.getint('b2u', 'broker_id') 64 | dest_market = config.get('b2u', 'dest_market') 65 | 66 | print 'websocket_url:', websocket_url 67 | print 'username:', username 68 | print 'buy_fee:', buy_fee 69 | print 'sell_fee:', sell_fee 70 | 71 | arbitrator = BlinkTradeArbitrator( broker_id, username,password,websocket_url, dest_market) 72 | arbitrator.connect() 73 | 74 | arbitrator.signal_order.connect(send_order_to_b2u) 75 | 76 | while True: 77 | try: 78 | sleep(10) 79 | if arbitrator.is_connected(): 80 | arbitrator.send_testRequest() 81 | else: 82 | try: 83 | arbitrator.reconnect() 84 | except HandshakeError,e: 85 | continue 86 | 87 | try: 88 | raw_data = urllib2.urlopen('http://www.bitcointoyou.com/API/orderbook.aspx').read() 89 | except Exception: 90 | print 'ERROR RETRIEVING ORDER BOOK' 91 | continue 92 | 93 | 94 | bids_asks = [] 95 | try: 96 | bids_asks = json.loads(raw_data) 97 | except Exception : 98 | try: 99 | bids_asks = json.loads(raw_data.replace('][','],[')) # bug with b2u api 100 | except Exception : 101 | pass 102 | pass 103 | 104 | if bids_asks: 105 | ask_list = [ [ int(float(fiat)*1e8 * (1. + sell_fee) ), int(float(btc) * 1e8) ] for fiat,btc in bids_asks['asks'] ] 106 | bid_list = [ [ int(float(fiat)*1e8 * (1. - buy_fee) ), int(float(btc) * 1e8) ] for fiat,btc in bids_asks['bids'] ] 107 | 108 | number_of_asks_to_remove_due_a_weird_bug = 0 109 | for ask_price, ask_size in ask_list: 110 | if ask_price < bid_list[0][0]: 111 | number_of_asks_to_remove_due_a_weird_bug += 1 112 | else: 113 | break 114 | if number_of_asks_to_remove_due_a_weird_bug: 115 | print datetime.datetime.now(), 'Those sell orders are weird => ', [ 'BTC {:,.8f}'.format(s/1e8) + ' @ R$ {:,.2f}'.format(p/1e8) for p, s in ask_list[:number_of_asks_to_remove_due_a_weird_bug] ] 116 | 117 | ask_list = ask_list[number_of_asks_to_remove_due_a_weird_bug:] 118 | 119 | arbitrator.process_ask_list(ask_list) 120 | arbitrator.process_bid_list(bid_list) 121 | 122 | except urllib2.URLError as e: 123 | print datetime.datetime.now(), e 124 | 125 | except KeyboardInterrupt: 126 | arbitrator.cancel_all_orders() 127 | print 'wait....' 128 | sleep(5) 129 | arbitrator.close() 130 | break 131 | 132 | main() 133 | 134 | -------------------------------------------------------------------------------- /tools/arbitrage/basebit.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import sys 3 | import urllib2 4 | from time import sleep 5 | import json 6 | 7 | from arbitrator import BlinkTradeArbitrator 8 | 9 | import datetime 10 | import hmac 11 | import hashlib 12 | import ConfigParser 13 | from ws4py.exc import HandshakeError 14 | 15 | 16 | BASEBIT_API_KEY = 'XXXX' 17 | BASEBIT_API_SECRET = 'YYYY' 18 | 19 | def send_order_to_basebit(sender, order): 20 | nonce = datetime.datetime.now().strftime('%s') 21 | message = 'sendorder' + str(BASEBIT_API_KEY) + str(nonce) 22 | signature = hmac.new(BASEBIT_API_SECRET, msg=message, digestmod=hashlib.sha256).hexdigest().upper() 23 | 24 | post_params = { 25 | 'key': BASEBIT_API_KEY, 26 | 'sign': signature, 27 | 'pair': order['Symbol'], 28 | 'quantity': float(order['OrderQty']/1.e8), 29 | 'price': float( order['Price'] / 1.e8) 30 | } 31 | 32 | if msg['Side'] == '1': 33 | post_params['type'] = 'buy' 34 | elif msg['Side'] == '2': 35 | post_params['type'] = 'sell' 36 | 37 | print datetime.datetime.now(), 'POST https://www.basebit.com.br/secure/tapi/' + message, str(post_params) 38 | 39 | def main(): 40 | candidates = ['arbitrage.ini', 'basebit.ini' ] 41 | if len(sys.argv) > 1: 42 | candidates.append(sys.argv[1]) 43 | 44 | 45 | config = ConfigParser.SafeConfigParser({ 46 | 'websocket_url': 'wss://127.0.0.1/trade/', 47 | 'username': '', 48 | 'password': '', 49 | 'buy_fee': 0, 50 | 'sell_fee': 0, 51 | 'api_key': 'KEY', 52 | 'api_secret': 'SECRET' 53 | }) 54 | config.read( candidates ) 55 | 56 | websocket_url = config.get('basebit', 'websocket_url') 57 | username = config.get('basebit', 'username') 58 | password = config.get('basebit', 'password') 59 | buy_fee = int(config.get('basebit', 'buy_fee')) 60 | sell_fee = int(config.get('basebit', 'sell_fee')) 61 | api_key = config.get('basebit', 'api_key') 62 | api_secret = config.get('basebit', 'api_secret') 63 | broker_id = config.getint('basebit', 'broker_id') 64 | dest_market = config.get('basebit', 'dest_market') 65 | 66 | print 'websocket_url:', websocket_url 67 | print 'username:', username 68 | print 'buy_fee:', buy_fee 69 | print 'sell_fee:', sell_fee 70 | 71 | arbitrator = BlinkTradeArbitrator(broker_id, username,password,websocket_url, dest_market ) 72 | arbitrator.connect() 73 | 74 | arbitrator.signal_order.connect(send_order_to_basebit) 75 | 76 | while True: 77 | try: 78 | sleep(10) 79 | 80 | if arbitrator.is_connected(): 81 | arbitrator.send_testRequest() 82 | else: 83 | try: 84 | arbitrator.reconnect() 85 | except HandshakeError,e: 86 | continue 87 | 88 | try: 89 | raw_data = urllib2.urlopen('http://www.basebit.com.br/book-BTC_BRL').read() 90 | except Exception: 91 | print 'ERROR RETRIEVING ORDER BOOK' 92 | continue 93 | 94 | bids_asks = [] 95 | try: 96 | bids_asks = json.loads(raw_data) 97 | except Exception : 98 | pass 99 | 100 | if bids_asks: 101 | ask_list = [ [ int(float(o['price']) * 1e8 * (1. + sell_fee) ) , int(o['quantity'] * 1e8) ] for o in bids_asks['result']['asks'] ] 102 | bid_list = [ [ int(float(o['price']) * 1e8 * (1. + buy_fee) ) , int(o['quantity'] * 1e8) ] for o in bids_asks['result']['bids'] ] 103 | arbitrator.process_ask_list(ask_list) 104 | arbitrator.process_bid_list(bid_list) 105 | except urllib2.URLError as e: 106 | print datetime.datetime.now(), e 107 | 108 | except KeyboardInterrupt: 109 | arbitrator.cancel_all_orders() 110 | print 'wait....' 111 | sleep(5) 112 | 113 | arbitrator.close() 114 | break 115 | 116 | main() 117 | 118 | -------------------------------------------------------------------------------- /tools/arbitrage/bitfinex.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import sys 3 | import urllib2 4 | from time import sleep 5 | import json 6 | 7 | from arbitrator import BlinkTradeArbitrator 8 | 9 | import datetime 10 | import hmac 11 | import hashlib 12 | import ConfigParser 13 | from ws4py.exc import HandshakeError 14 | 15 | BITFINEX_API_KEY = 'XXXX' 16 | BITFINEX_API_SECRET = 'YYYY' 17 | 18 | def send_order_to_bitfinex(sender, order): 19 | nonce = datetime.datetime.now().strftime('%s') 20 | message = 'sendorder' + str(BITFINEX_API_KEY) + str(nonce) 21 | signature = hmac.new(BITFINEX_API_SECRET, msg=message, digestmod=hashlib.sha256).hexdigest().upper() 22 | 23 | post_params = { 24 | 'key': BITFINEX_API_KEY, 25 | 'sign': signature, 26 | 'pair': 'btc_brl', 27 | 'volume': float(order['OrderQty']/1.e8), 28 | 'price': float( order['Price'] / 1.e8) 29 | } 30 | 31 | if order['Side'] == '1': 32 | post_params['type'] = 'buy' 33 | elif order['Side'] == '2': 34 | post_params['type'] = 'sell' 35 | 36 | print datetime.datetime.now(), 'POST https://api.bitfinex.com/v1/tapi/' + message, str(post_params) 37 | 38 | def main(): 39 | candidates = ['arbitrage.ini', 'bitfinex.ini' ] 40 | if len(sys.argv) > 1: 41 | candidates.append(sys.argv[1]) 42 | 43 | 44 | config = ConfigParser.SafeConfigParser({ 45 | 'websocket_url': 'wss://127.0.0.1/trade/', 46 | 'username': '', 47 | 'password': '', 48 | 'buy_fee': 0, 49 | 'sell_fee': 0, 50 | 'api_key': 'KEY', 51 | 'api_secret': 'SECRET' 52 | }) 53 | config.read( candidates ) 54 | 55 | websocket_url = config.get('bitfinex', 'websocket_url') 56 | username = config.get('bitfinex', 'username') 57 | password = config.get('bitfinex', 'password') 58 | buy_fee = int(config.get('bitfinex', 'buy_fee')) 59 | sell_fee = int(config.get('bitfinex', 'sell_fee')) 60 | api_key = config.get('bitfinex', 'api_key') 61 | api_secret = config.get('bitfinex', 'api_secret') 62 | broker_id = config.getint('bitfinex', 'broker_id') 63 | dest_market = config.get('bitfinex', 'dest_market') 64 | 65 | arbitrator = BlinkTradeArbitrator(broker_id, username,password,websocket_url, dest_market) 66 | arbitrator.connect() 67 | 68 | arbitrator.signal_order.connect(send_order_to_bitfinex) 69 | 70 | while True: 71 | try: 72 | sleep(1) 73 | 74 | if arbitrator.is_connected(): 75 | arbitrator.send_testRequest() 76 | else: 77 | try: 78 | arbitrator.reconnect() 79 | except HandshakeError,e: 80 | continue 81 | 82 | try: 83 | raw_data = urllib2.urlopen('https://api.bitfinex.com/v1/book/BTCUSD').read() 84 | except Exception: 85 | print 'ERROR RETRIEVING ORDER BOOK' 86 | continue 87 | 88 | 89 | bids_asks = [] 90 | try: 91 | bids_asks = json.loads(raw_data) 92 | except Exception : 93 | pass 94 | 95 | if bids_asks: 96 | bid_list = [ [ int(float(o['price']) * 1e8 * (1. + buy_fee) ) , int( float(o['amount']) * 1e8) ] for o in bids_asks['bids'] ] 97 | ask_list = [ [ int(float(o['price']) * 1e8 * (1. + sell_fee) ) , int( float(o['amount']) * 1e8) ] for o in bids_asks['asks'] ] 98 | arbitrator.process_ask_list(ask_list) 99 | arbitrator.process_bid_list(bid_list) 100 | except urllib2.URLError as e: 101 | print datetime.datetime.now(), e 102 | 103 | except KeyboardInterrupt: 104 | arbitrator.cancel_all_orders() 105 | print 'wait....' 106 | sleep(5) 107 | arbitrator.close() 108 | break 109 | 110 | main() 111 | 112 | -------------------------------------------------------------------------------- /tools/arbitrage/bitinvest.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import sys 3 | import urllib2 4 | from time import sleep 5 | import json 6 | 7 | from arbitrator import BlinkTradeArbitrator 8 | 9 | import datetime 10 | import hmac 11 | import hashlib 12 | import subprocess 13 | import ConfigParser 14 | from ws4py.exc import HandshakeError 15 | 16 | 17 | BINVEST_API_KEY = 'XXXX' 18 | BINVEST_API_SECRET = 'YYYY' 19 | 20 | def send_order_to_BINVEST(sender, order): 21 | nonce = datetime.datetime.now().strftime('%s') 22 | message = 'sendorder' + str(BINVEST_API_KEY) + str(nonce) 23 | signature = hmac.new(BINVEST_API_SECRET, msg=message, digestmod=hashlib.sha256).hexdigest().upper() 24 | 25 | post_params = { 26 | 'key': BINVEST_API_KEY, 27 | 'sign': signature, 28 | 'pair': 'btc_brl', 29 | 'volume': float(order['OrderQty']/1.e8), 30 | 'price': float( order['Price'] / 1.e8) 31 | } 32 | 33 | if msg['Side'] == '1': 34 | post_params['type'] = 'buy' 35 | elif msg['Side'] == '2': 36 | post_params['type'] = 'sell' 37 | 38 | print datetime.datetime.now(), 'POST https://api.bitinvest.com.br/tapi/' + message, str(post_params) 39 | 40 | def main(): 41 | candidates = ['arbitrage.ini', 'basebit.ini' ] 42 | if len(sys.argv) > 1: 43 | candidates.append(sys.argv[1]) 44 | 45 | 46 | config = ConfigParser.SafeConfigParser({ 47 | 'websocket_url': 'wss://127.0.0.1/trade/', 48 | 'username': '', 49 | 'password': '', 50 | 'buy_fee': 0, 51 | 'sell_fee': 0, 52 | 'api_key': 'KEY', 53 | 'api_secret': 'SECRET', 54 | 'subscription_api_key':'api_key' 55 | }) 56 | config.read( candidates ) 57 | 58 | websocket_url = config.get('bitinvest', 'websocket_url') 59 | username = config.get('bitinvest', 'username') 60 | password = config.get('bitinvest', 'password') 61 | buy_fee = int(config.get('bitinvest', 'buy_fee')) 62 | sell_fee = int(config.get('bitinvest', 'sell_fee')) 63 | api_key = config.get('bitinvest', 'api_key') 64 | api_secret = config.get('bitinvest', 'api_secret') 65 | subscription_api_key = config.get('bitinvest', 'subscription_api_key') 66 | broker_id = config.getint('bitinvest', 'broker_id') 67 | dest_market = config.get('bitinvest', 'dest_market') 68 | 69 | 70 | arbitrator = BlinkTradeArbitrator(broker_id, username,password,websocket_url, dest_market) 71 | arbitrator.connect() 72 | 73 | arbitrator.signal_order.connect(send_order_to_BINVEST) 74 | 75 | while True: 76 | try: 77 | sleep(15) 78 | if arbitrator.is_connected(): 79 | arbitrator.send_testRequest() 80 | else: 81 | try: 82 | arbitrator.reconnect() 83 | except HandshakeError,e: 84 | continue 85 | 86 | try: 87 | # something wrong with urllib2 or bitinvest servers. 88 | #raw_data = urllib2.urlopen('https://api.bitinvest.com.br/exchange/orderbook?subscription-key=' + subscription_api_key).read() 89 | 90 | # curl works. I know, this is ugly, but it works 91 | api_url = 'https://api.bitinvest.com.br/exchange/orderbook?subscription-key=' + subscription_api_key 92 | raw_data = subprocess.check_output( ['curl', api_url ] ) 93 | except Exception: 94 | print 'ERROR RETRIEVING ORDER BOOK' 95 | continue 96 | 97 | bids_asks = [] 98 | try: 99 | bids_asks = json.loads(raw_data) 100 | except Exception : 101 | pass 102 | 103 | if bids_asks: 104 | ask_list = [ [ int(float(o[0]) * 1e8 * (1. + sell_fee) ) , int(o[1] * 1e8) ] for o in bids_asks['asks'] ] 105 | bid_list = [ [ int(float(o[0]) * 1e8 * (1. + buy_fee) ) , int(o[1] * 1e8) ] for o in bids_asks['bids'] ] 106 | arbitrator.process_ask_list(ask_list) 107 | arbitrator.process_bid_list(bid_list) 108 | except urllib2.URLError as e: 109 | print datetime.datetime.now(), e 110 | 111 | except KeyboardInterrupt: 112 | arbitrator.cancel_all_orders() 113 | print 'wait....' 114 | sleep(5) 115 | arbitrator.close() 116 | break 117 | 118 | main() 119 | 120 | -------------------------------------------------------------------------------- /tools/arbitrage/hitbtc.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import sys 3 | import urllib2 4 | from time import sleep 5 | import json 6 | 7 | from arbitrator import BlinkTradeArbitrator 8 | 9 | import datetime 10 | import hmac 11 | import hashlib 12 | import ConfigParser 13 | from ws4py.exc import HandshakeError 14 | 15 | 16 | HITBTC_API_KEY = 'XXXX' 17 | HITBTC_API_SECRET = 'YYYY' 18 | 19 | def send_order(sender, order): 20 | nonce = datetime.datetime.now().strftime('%s') 21 | message = 'sendorder' + str(HITBTC_API_KEY) + str(nonce) 22 | signature = hmac.new(HITBTC_API_SECRET, msg=message, digestmod=hashlib.sha256).hexdigest().upper() 23 | 24 | post_params = { 25 | 'key': HITBTC_API_KEY, 26 | 'sign': signature, 27 | 'pair': 'btc_brl', 28 | 'volume': float(order['OrderQty']/1.e8), 29 | 'price': float( order['Price'] / 1.e8) 30 | } 31 | 32 | if order['Side'] == '1': 33 | post_params['type'] = 'buy' 34 | elif order['Side'] == '2': 35 | post_params['type'] = 'sell' 36 | 37 | print datetime.datetime.now(), 'POST https://api.hitbtc.com/v1/tapi/' + message, str(post_params) 38 | 39 | def main(): 40 | candidates = ['arbitrage.ini', 'hitbtc.ini' ] 41 | if len(sys.argv) > 1: 42 | candidates.append(sys.argv[1]) 43 | 44 | 45 | config = ConfigParser.SafeConfigParser({ 46 | 'websocket_url': 'wss://127.0.0.1/trade/', 47 | 'username': '', 48 | 'password': '', 49 | 'buy_fee': 0, 50 | 'sell_fee': 0, 51 | 'api_key': 'KEY', 52 | 'api_secret': 'SECRET' 53 | }) 54 | config.read( candidates ) 55 | 56 | websocket_url = config.get('hitbtc', 'websocket_url') 57 | username = config.get('hitbtc', 'username') 58 | password = config.get('hitbtc', 'password') 59 | buy_fee = int(config.get('hitbtc', 'buy_fee')) 60 | sell_fee = int(config.get('hitbtc', 'sell_fee')) 61 | api_key = config.get('hitbtc', 'api_key') 62 | api_secret = config.get('hitbtc', 'api_secret') 63 | broker_id = config.getint('hitbtc', 'broker_id') 64 | dest_market = config.get('hitbtc', 'dest_market') 65 | 66 | 67 | arbitrator = BlinkTradeArbitrator(broker_id, username,password,websocket_url, dest_market) 68 | arbitrator.connect() 69 | 70 | arbitrator.signal_order.connect(send_order) 71 | 72 | while True: 73 | try: 74 | sleep(1) 75 | if arbitrator.is_connected(): 76 | arbitrator.send_testRequest() 77 | else: 78 | try: 79 | arbitrator.reconnect() 80 | except HandshakeError,e: 81 | continue 82 | 83 | try: 84 | raw_data = urllib2.urlopen('https://api.hitbtc.com/api/1/public/BTCUSD/orderbook?format_price=number&format_amount=number').read() 85 | except Exception: 86 | print 'ERROR RETRIEVING ORDER BOOK' 87 | continue 88 | 89 | 90 | bids_asks = [] 91 | try: 92 | bids_asks = json.loads(raw_data) 93 | except Exception : 94 | pass 95 | 96 | if bids_asks: 97 | bid_list = [ [ int(float(o[0]) * 1e8 * (1. + buy_fee) ) , int( float(o[1]) * 1e8) ] for o in bids_asks['bids'] ] 98 | ask_list = [ [ int(float(o[0]) * 1e8 * (1. + sell_fee) ) , int( float(o[1]) * 1e8) ] for o in bids_asks['asks'] ] 99 | arbitrator.process_ask_list(ask_list) 100 | arbitrator.process_bid_list(bid_list) 101 | except urllib2.URLError as e: 102 | print datetime.datetime.now(), e 103 | 104 | except KeyboardInterrupt: 105 | arbitrator.cancel_all_orders() 106 | print 'wait....' 107 | sleep(5) 108 | arbitrator.close() 109 | break 110 | 111 | main() 112 | 113 | -------------------------------------------------------------------------------- /tools/arbitrage/itbit.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import sys 3 | import urllib2 4 | from time import sleep 5 | import json 6 | 7 | from arbitrator import BlinkTradeArbitrator 8 | 9 | import datetime 10 | import hmac 11 | import hashlib 12 | import ConfigParser 13 | from ws4py.exc import HandshakeError 14 | 15 | 16 | ITBIT_API_KEY = 'XXXX' 17 | ITBIT_API_SECRET = 'YYYY' 18 | 19 | def send_order(sender, order): 20 | nonce = datetime.datetime.now().strftime('%s') 21 | message = 'sendorder' + str(ITBIT_API_KEY) + str(nonce) 22 | signature = hmac.new(ITBIT_API_SECRET, msg=message, digestmod=hashlib.sha256).hexdigest().upper() 23 | 24 | post_params = { 25 | 'key': ITBIT_API_KEY, 26 | 'sign': signature, 27 | 'pair': 'btc_brl', 28 | 'volume': float(order['OrderQty']/1.e8), 29 | 'price': float( order['Price'] / 1.e8) 30 | } 31 | 32 | if order['Side'] == '1': 33 | post_params['type'] = 'buy' 34 | elif order['Side'] == '2': 35 | post_params['type'] = 'sell' 36 | 37 | print datetime.datetime.now(), 'POST https://api.hitbtc.com/v1/tapi/' + message, str(post_params) 38 | 39 | def main(): 40 | candidates = ['arbitrage.ini', 'itbit.ini' ] 41 | if len(sys.argv) > 1: 42 | candidates.append(sys.argv[1]) 43 | 44 | 45 | config = ConfigParser.SafeConfigParser({ 46 | 'websocket_url': 'wss://127.0.0.1/trade/', 47 | 'username': '', 48 | 'password': '', 49 | 'buy_fee': 0, 50 | 'sell_fee': 0, 51 | 'api_key': 'KEY', 52 | 'api_secret': 'SECRET' 53 | }) 54 | config.read( candidates ) 55 | 56 | websocket_url = config.get('itbit', 'websocket_url') 57 | username = config.get('itbit', 'username') 58 | password = config.get('itbit', 'password') 59 | buy_fee = float(config.get('itbit', 'buy_fee')) 60 | sell_fee = float(config.get('itbit', 'sell_fee')) 61 | api_key = config.get('itbit', 'api_key') 62 | api_secret = config.get('itbit', 'api_secret') 63 | broker_id = config.getint('itbit', 'broker_id') 64 | dest_market = config.get('itbit', 'dest_market') 65 | 66 | arbitrator = BlinkTradeArbitrator(broker_id,username,password,websocket_url, dest_market ) 67 | arbitrator.connect() 68 | 69 | arbitrator.signal_order.connect(send_order) 70 | 71 | while True: 72 | try: 73 | sleep(1) 74 | if arbitrator.is_connected(): 75 | arbitrator.send_testRequest() 76 | else: 77 | try: 78 | arbitrator.reconnect() 79 | except HandshakeError,e: 80 | continue 81 | 82 | try: 83 | raw_data = urllib2.urlopen('https://www.itbit.com/api/v2/markets/XBTUSD/orders').read() 84 | except Exception: 85 | print 'ERROR RETRIEVING ORDER BOOK' 86 | continue 87 | 88 | 89 | bids_asks = [] 90 | try: 91 | bids_asks = json.loads(raw_data) 92 | except Exception : 93 | pass 94 | 95 | if bids_asks: 96 | bid_list = [ [ int(float(o[0]) * 1e8 * (1. + buy_fee) ) , int( float(o[1]) * 1e8) ] for o in bids_asks['bids'] ] 97 | ask_list = [ [ int(float(o[0]) * 1e8 * (1. + sell_fee) ) , int( float(o[1]) * 1e8) ] for o in bids_asks['asks'] ] 98 | arbitrator.process_ask_list(ask_list) 99 | arbitrator.process_bid_list(bid_list) 100 | except urllib2.URLError as e: 101 | print datetime.datetime.now(), e 102 | 103 | except KeyboardInterrupt: 104 | arbitrator.cancel_all_orders() 105 | print 'wait....' 106 | sleep(5) 107 | arbitrator.close() 108 | break 109 | 110 | main() 111 | 112 | -------------------------------------------------------------------------------- /tools/arbitrage/mb.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import sys 3 | import urllib2 4 | from time import sleep 5 | import json 6 | 7 | from arbitrator import BlinkTradeArbitrator 8 | 9 | import datetime 10 | import hmac 11 | import hashlib 12 | import ConfigParser 13 | from ws4py.exc import HandshakeError 14 | 15 | 16 | MB_API_KEY = 'XXXX' 17 | MB_API_SECRET = 'YYYY' 18 | 19 | def send_order_to_MB(sender, order): 20 | nonce = datetime.datetime.now().strftime('%s') 21 | message = 'sendorder' + str(MB_API_KEY) + str(nonce) 22 | signature = hmac.new(MB_API_SECRET, msg=message, digestmod=hashlib.sha256).hexdigest().upper() 23 | 24 | post_params = { 25 | 'key': MB_API_KEY, 26 | 'sign': signature, 27 | 'pair': 'btc_brl', 28 | 'volume': float(order['OrderQty']/1.e8), 29 | 'price': float( order['Price'] / 1.e8) 30 | } 31 | 32 | if msg['Side'] == '1': 33 | post_params['type'] = 'buy' 34 | elif msg['Side'] == '2': 35 | post_params['type'] = 'sell' 36 | 37 | print datetime.datetime.now(), 'POST https://www.mercadobitcoin.com.br/tapi/' + message, str(post_params) 38 | 39 | def main(): 40 | candidates = ['arbitrage.ini', 'mb.ini' ] 41 | if len(sys.argv) > 1: 42 | candidates.append(sys.argv[1]) 43 | 44 | 45 | config = ConfigParser.SafeConfigParser({ 46 | 'websocket_url': 'wss://127.0.0.1/trade/', 47 | 'username': '', 48 | 'password': '', 49 | 'buy_fee': 0, 50 | 'sell_fee': 0, 51 | 'api_key': 'KEY', 52 | 'api_secret': 'SECRET' 53 | }) 54 | config.read( candidates ) 55 | 56 | websocket_url = config.get('mb', 'websocket_url') 57 | username = config.get('mb', 'username') 58 | password = config.get('mb', 'password') 59 | buy_fee = int(config.get('mb', 'buy_fee')) 60 | sell_fee = int(config.get('mb', 'sell_fee')) 61 | api_key = config.get('mb', 'api_key') 62 | api_secret = config.get('mb', 'api_secret') 63 | broker_id = config.getint('mb', 'broker_id') 64 | dest_market = config.get('mb', 'dest_market') 65 | 66 | print 'websocket_url:', websocket_url 67 | print 'username:', username 68 | print 'buy_fee:', buy_fee 69 | print 'sell_fee:', sell_fee 70 | 71 | arbitrator = BlinkTradeArbitrator(broker_id, username,password,websocket_url, dest_market) 72 | arbitrator.connect() 73 | 74 | arbitrator.signal_order.connect(send_order_to_MB) 75 | 76 | while True: 77 | try: 78 | sleep(5) 79 | if arbitrator.is_connected(): 80 | arbitrator.send_testRequest() 81 | else: 82 | try: 83 | arbitrator.reconnect() 84 | except HandshakeError,e: 85 | continue 86 | 87 | try: 88 | raw_data = urllib2.urlopen('https://www.mercadobitcoin.com.br/api/orderbook/').read() 89 | except Exception: 90 | print 'ERROR RETRIEVING ORDER BOOK' 91 | continue 92 | 93 | bids_asks = [] 94 | try: 95 | bids_asks = json.loads(raw_data) 96 | except Exception : 97 | pass 98 | 99 | if bids_asks: 100 | ask_list = [ [ int(float(o[0]) * 1e8 * (1. + sell_fee) ) , int(o[1] * 1e8) ] for o in bids_asks['asks'] ] 101 | bid_list = [ [ int(float(o[0]) * 1e8 * (1. + buy_fee) ) , int(o[1] * 1e8) ] for o in bids_asks['bids'] ] 102 | arbitrator.process_ask_list(ask_list) 103 | arbitrator.process_bid_list(bid_list) 104 | 105 | except urllib2.URLError as e: 106 | print datetime.datetime.now(), e 107 | 108 | except KeyboardInterrupt: 109 | arbitrator.cancel_all_orders() 110 | print 'wait....' 111 | sleep(5) 112 | arbitrator.close() 113 | break 114 | 115 | main() 116 | 117 | -------------------------------------------------------------------------------- /tools/arbitrage/order_book_processor.py: -------------------------------------------------------------------------------- 1 | import sys 2 | sys.path.insert(0, '../../libs') 3 | 4 | from pyblinktrade.signals import Signal 5 | import datetime 6 | import time 7 | import random 8 | 9 | class OrderBookProcessor(): 10 | def __init__(self, side, symbol): 11 | self.side = side 12 | self.symbol = symbol 13 | self.orders_by_id = {} 14 | self.orders_by_price = {} 15 | self.orders_list_ordered_by_timestamp = [] 16 | 17 | self.send_new_order_signal = Signal() 18 | self.cancel_order_signal = Signal() 19 | 20 | def _get_order_by_price(self, price): 21 | if price in self.orders_by_price: 22 | return self.orders_by_price[price] 23 | return None 24 | 25 | def _send_new_order(self, price, volume): 26 | now = datetime.datetime.now() 27 | timestamp = time.mktime(now.timetuple())*1e3 + now.microsecond/1e3 28 | 29 | order_id = str(int(timestamp)) + str(int(random.random()*100000)) 30 | 31 | order = { 'id': order_id, 'price': price, 'vol': volume , 'ts': timestamp } 32 | self.orders_by_price[price] = order 33 | self.orders_by_id[order_id] = order 34 | 35 | self.orders_list_ordered_by_timestamp.append( order ) 36 | 37 | order_message = { 38 | 'MsgType': 'D', 39 | 'Symbol' : self.symbol, 40 | 'OrdType':'2', 41 | 'Price': int(price), 42 | 'OrderQty': int(volume), 43 | 'ClOrdID': str(order_id), 44 | 'Side': self.side, 45 | } 46 | self.send_new_order_signal( self, order_message) 47 | 48 | return order_id 49 | 50 | def _send_cancel_replace_order(self, order_id, new_volume): 51 | original_order = self.orders_by_id[order_id] 52 | 53 | original_volume = original_order['vol'] 54 | if original_volume != new_volume: 55 | self._cancel_order( original_order['id'] ) 56 | return self._send_new_order( original_order['price'], new_volume ) 57 | else: 58 | # nothing to do ... let's just update the current order timestamp. 59 | now = datetime.datetime.now() 60 | new_timestamp = time.mktime(now.timetuple())*1e3 + now.microsecond/1e3 61 | original_order['ts'] = new_timestamp 62 | 63 | pos = 0 64 | for order in self.orders_list_ordered_by_timestamp: 65 | if order['id'] == order_id: 66 | break 67 | pos += 1 68 | del self.orders_list_ordered_by_timestamp[pos] 69 | self.orders_list_ordered_by_timestamp.append( original_order ) 70 | 71 | def _get_last_timestamp(self): 72 | if not self.orders_list_ordered_by_timestamp: 73 | now = datetime.datetime.now() 74 | timestamp = time.mktime(now.timetuple())*1e3 + now.microsecond/1e3 75 | return timestamp 76 | return self.orders_list_ordered_by_timestamp[-1]['ts'] 77 | 78 | def _cancel_all_orders_prior_timestamp(self, timestamp): 79 | orders_to_cancel = [] 80 | for order in self.orders_list_ordered_by_timestamp: 81 | if order['ts'] <= timestamp: 82 | orders_to_cancel.append(order['id']) 83 | 84 | for order_id in orders_to_cancel: 85 | self._cancel_order( order_id ) 86 | 87 | def _cancel_order(self, order_id): 88 | original_order = self.orders_by_id[order_id] 89 | 90 | self.cancel_order_signal(self, { 'MsgType':'F', 'OrigClOrdID': str(order_id)} ) 91 | 92 | # find the order position 93 | pos = 0 94 | for order in self.orders_list_ordered_by_timestamp: 95 | if order['id'] == order_id: 96 | break 97 | pos += 1 98 | del self.orders_list_ordered_by_timestamp[pos] 99 | 100 | del self.orders_by_price[original_order['price']] 101 | del self.orders_by_id[original_order['id'] ] 102 | return True 103 | 104 | def process_order_list(self, order_list): 105 | bid_timestamp = self._get_last_timestamp() 106 | for o in order_list: 107 | order_volume = o[1] 108 | order_price = o[0] 109 | 110 | # get the order using the price 111 | order = self._get_order_by_price(order_price) 112 | if order: 113 | if not order_volume: 114 | self._cancel_order(order['id']) 115 | else: 116 | self._send_cancel_replace_order( order['id'], order_volume ) 117 | else: 118 | if order_price and order_volume: 119 | self._send_new_order(order_price, order_volume) 120 | self._cancel_all_orders_prior_timestamp(bid_timestamp) 121 | -------------------------------------------------------------------------------- /tools/arbitrage/util.py: -------------------------------------------------------------------------------- 1 | def get_funded_entries(orders, balance, is_total_vol): 2 | total_vol_usd = 0 3 | total_vol_btc = 0 4 | funded_entries = [] 5 | for price_usd, size_btc in orders: 6 | vol_usd = (price_usd * size_btc) / 1e8 7 | previous_total_vol_btc = total_vol_btc 8 | previous_total_vol_usd = total_vol_usd 9 | total_vol_usd += vol_usd 10 | total_vol_btc += size_btc 11 | if is_total_vol: 12 | if total_vol_usd > balance: 13 | available_volume = balance - previous_total_vol_usd 14 | if available_volume: 15 | funded_entries.append([ price_usd, int( (float (available_volume) / float (price_usd)) * 1.e8) ]) 16 | break 17 | else: 18 | if total_vol_btc > balance: 19 | if balance-previous_total_vol_btc: 20 | funded_entries.append([ price_usd, int(balance-previous_total_vol_btc) ]) 21 | break 22 | funded_entries.append([ price_usd, size_btc ]) 23 | return funded_entries 24 | 25 | 26 | def aggregate_orders(order_list): 27 | res = [] 28 | for price, size in order_list: 29 | if res: 30 | if res[-1][0] == price: 31 | res[-1][1] += size 32 | else: 33 | res.append( [ price, size ] ) 34 | else: 35 | res.append( [ price, size ] ) 36 | return res 37 | -------------------------------------------------------------------------------- /tools/latency_analyser/gw_latency_analyser.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import fileinput 3 | import sys 4 | import json 5 | import datetime 6 | import csv 7 | 8 | cancel_order_dict = {} 9 | new_order_single_dict = {} 10 | 11 | line_number = 0 12 | 13 | csv_file = open(sys.argv[2], 'wt') 14 | csv_writer = csv.writer(csv_file) 15 | csv_writer.writerow( ('Timestamp','LineNumber', 'MessageType', 'ClOrdID', 'Latency(ms)') ) 16 | 17 | def latency_in_ms(t1, t2): 18 | return ( t2 - t1 ).microseconds / 1000 19 | 20 | for line in fileinput.input(sys.argv[1]): 21 | timestamp = line[:23] 22 | timestamp = datetime.datetime.strptime(timestamp + '000', "%Y-%m-%d %H:%M:%S,%f") 23 | 24 | 25 | line_number += 1 26 | 27 | log_data = line[26:].split(',') 28 | if len(log_data) > 2: 29 | log_type = log_data[0] 30 | session = log_data[1] 31 | message = log_data[2] 32 | message_start_index = line.find(message) 33 | message = line[message_start_index:] 34 | 35 | try: 36 | message = json.loads(message) 37 | log_record = [timestamp, log_type, session, message ] 38 | 39 | 40 | if 'MsgType' in message and message['MsgType'] == 'F': 41 | cancel_order_dict[ message['OrigClOrdID'] ] = log_record 42 | 43 | if 'MsgType' in message and message['MsgType'] == 'D': 44 | new_order_single_dict[ message['ClOrdID'] ] = log_record 45 | 46 | 47 | if 'MsgType' in message and message['MsgType'] == '8': 48 | if message['ExecType'] == '4': 49 | if message['ClOrdID'] in cancel_order_dict: 50 | latency = latency_in_ms(cancel_order_dict[ message['ClOrdID'] ][0], timestamp) 51 | row = (timestamp, line_number, 'CANCEL_ORDER', message['ClOrdID'], latency ) 52 | csv_writer.writerow( row ) 53 | del cancel_order_dict[ message['ClOrdID'] ] 54 | 55 | if message['ExecType'] == '0': 56 | if message['ClOrdID'] in new_order_single_dict: 57 | latency = latency_in_ms(new_order_single_dict[ message['ClOrdID'] ][0], timestamp) 58 | row = (timestamp, line_number, 'NEW_ORDER', message['ClOrdID'], latency ) 59 | csv_writer.writerow( row ) 60 | del new_order_single_dict[ message['ClOrdID'] ] 61 | 62 | #print line_number, timestamp, log_type, session, message 63 | except Exception,e : 64 | pass 65 | --------------------------------------------------------------------------------