├── readme.rst ├── examples ├── tornado_websocket_chat-master │ ├── app │ │ ├── __init__.py │ │ ├── app_cache.py │ │ ├── app_factory.py │ │ ├── app_config.py │ │ ├── app_services.py │ │ ├── app_urls.py │ │ └── app_handlers.py │ ├── requirements.txt │ ├── .gitignore │ ├── public │ │ ├── msg │ │ │ ├── img │ │ │ │ └── msg.gif │ │ │ ├── js │ │ │ │ └── msg.js │ │ │ └── css │ │ │ │ └── msg.css │ │ ├── index.html │ │ └── chat.html │ ├── manage.py │ └── readme.md ├── templates │ └── index.html ├── app2.py ├── app3.py ├── websocket.py ├── app4.py └── app1.py ├── .vscode └── settings.json ├── .gitignore ├── quantaxisbackend ├── data │ ├── __pycache__ │ │ ├── __init__.cpython-36.pyc │ │ └── handles.cpython-36.pyc │ ├── __init__.py │ └── handles.py ├── user │ ├── __pycache__ │ │ ├── __init__.cpython-36.pyc │ │ └── handles.cpython-36.pyc │ ├── __init__.py │ └── handles.py ├── quotation │ ├── __pycache__ │ │ ├── __init__.cpython-36.pyc │ │ └── handles.cpython-36.pyc │ ├── index.html │ ├── __init__.py │ ├── handles.py │ └── websocket.md ├── index.html ├── backtest │ ├── __init__.py │ └── handles.py ├── util │ ├── __init__.py │ └── handles.py ├── __init__.py └── app.py ├── LICENSE ├── setup.py └── README.md /readme.rst: -------------------------------------------------------------------------------- 1 | quantaxisbackend 2 | =============== -------------------------------------------------------------------------------- /examples/tornado_websocket_chat-master/app/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/tornado_websocket_chat-master/requirements.txt: -------------------------------------------------------------------------------- 1 | tornado>=4.5.2 2 | -------------------------------------------------------------------------------- /examples/tornado_websocket_chat-master/.gitignore: -------------------------------------------------------------------------------- 1 | *__pycache__* 2 | *keys* 3 | *.png* -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "restructuredtext.workspaceRoot": "c:\\quantaxisweb" 3 | } -------------------------------------------------------------------------------- /examples/tornado_websocket_chat-master/app/app_cache.py: -------------------------------------------------------------------------------- 1 | messages = [] 2 | clients = set() 3 | users = {} -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # QUANTAXIS Logs 2 | 3 | *.log 4 | dist/ 5 | *__pycache__/ 6 | *.pyc 7 | *.egg-info/ 8 | build/ 9 | -------------------------------------------------------------------------------- /quantaxisbackend/data/__pycache__/__init__.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QUANTAXIS/QUANTAXISWEB/HEAD/quantaxisbackend/data/__pycache__/__init__.cpython-36.pyc -------------------------------------------------------------------------------- /quantaxisbackend/data/__pycache__/handles.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QUANTAXIS/QUANTAXISWEB/HEAD/quantaxisbackend/data/__pycache__/handles.cpython-36.pyc -------------------------------------------------------------------------------- /quantaxisbackend/user/__pycache__/__init__.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QUANTAXIS/QUANTAXISWEB/HEAD/quantaxisbackend/user/__pycache__/__init__.cpython-36.pyc -------------------------------------------------------------------------------- /quantaxisbackend/user/__pycache__/handles.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QUANTAXIS/QUANTAXISWEB/HEAD/quantaxisbackend/user/__pycache__/handles.cpython-36.pyc -------------------------------------------------------------------------------- /examples/tornado_websocket_chat-master/public/msg/img/msg.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QUANTAXIS/QUANTAXISWEB/HEAD/examples/tornado_websocket_chat-master/public/msg/img/msg.gif -------------------------------------------------------------------------------- /quantaxisbackend/quotation/__pycache__/__init__.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QUANTAXIS/QUANTAXISWEB/HEAD/quantaxisbackend/quotation/__pycache__/__init__.cpython-36.pyc -------------------------------------------------------------------------------- /quantaxisbackend/quotation/__pycache__/handles.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QUANTAXIS/QUANTAXISWEB/HEAD/quantaxisbackend/quotation/__pycache__/handles.cpython-36.pyc -------------------------------------------------------------------------------- /examples/tornado_websocket_chat-master/app/app_factory.py: -------------------------------------------------------------------------------- 1 | def create_app(config): 2 | from app.app_urls import urls 3 | from tornado.web import Application 4 | app = Application(urls, **config) 5 | return app 6 | -------------------------------------------------------------------------------- /examples/tornado_websocket_chat-master/manage.py: -------------------------------------------------------------------------------- 1 | from app import app_services as services 2 | 3 | 4 | commands = { 5 | "runserver": services.run_dev_ioloop 6 | } 7 | 8 | 9 | if __name__ == "__main__": 10 | import sys 11 | commands[sys.argv[1]]() -------------------------------------------------------------------------------- /examples/tornado_websocket_chat-master/app/app_config.py: -------------------------------------------------------------------------------- 1 | import os 2 | from app import keys 3 | 4 | 5 | APP_DIR = os.path.dirname(__file__) 6 | STATIC_PATH = os.path.dirname(APP_DIR) + os.sep + "public" 7 | 8 | 9 | config = { 10 | # Critical settings were externalized to keys.py file. 11 | "cookie_secret": keys.SECRET_KEY, 12 | "debug": keys.DEBUG, 13 | "login_url": "/", 14 | "host": keys.HOST, 15 | "port": 8004, 16 | "app_dir": APP_DIR, 17 | "static_path": STATIC_PATH 18 | } 19 | -------------------------------------------------------------------------------- /examples/templates/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 13 | 14 | 15 | 16 |
17 | hello 18 | 19 | 20 |
21 | 22 | 23 | -------------------------------------------------------------------------------- /examples/tornado_websocket_chat-master/app/app_services.py: -------------------------------------------------------------------------------- 1 | from tornado.ioloop import IOLoop 2 | from app import app_factory 3 | from app import app_cache as cache 4 | from app.app_config import config 5 | 6 | 7 | def run_dev_ioloop(): 8 | """ Run Tornado IOLoop in debug mode (not for production). """ 9 | app = app_factory.create_app(config) 10 | app.listen(config["port"]) 11 | print("Running Tornado on", config["host"] + ":" + str(config["port"])) 12 | IOLoop.current().start() 13 | 14 | 15 | def broadcast(message): 16 | """ Send json message to all clients registered to WebSocketHandler. """ 17 | for client in cache.clients: 18 | client.write_message(message) 19 | -------------------------------------------------------------------------------- /examples/tornado_websocket_chat-master/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | MSG 7 | 8 | 9 | 10 | 11 | 12 |
13 |
14 |
15 | 16 | 17 |
18 |
19 |
20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /examples/tornado_websocket_chat-master/app/app_urls.py: -------------------------------------------------------------------------------- 1 | from tornado.web import StaticFileHandler 2 | from app.app_config import config 3 | from app.app_handlers import IndexHandler 4 | from app.app_handlers import ConnectionHandler 5 | from app.app_handlers import DisconnectionHandler 6 | from app.app_handlers import ChatHandler 7 | from app.app_handlers import ResetHandler 8 | from app.app_handlers import WebSocketHandler 9 | 10 | 11 | urls = [ 12 | (r"/", IndexHandler), 13 | (r"/connect", ConnectionHandler), 14 | (r"/disconnect", DisconnectionHandler), 15 | (r"/chat", ChatHandler), 16 | (r"/reset", ResetHandler), 17 | (r"/websocket", WebSocketHandler), 18 | (r'/(.*)', StaticFileHandler, {'path': config["static_path"]}), 19 | ] -------------------------------------------------------------------------------- /examples/tornado_websocket_chat-master/readme.md: -------------------------------------------------------------------------------- 1 |

MSG - Tornado WebSocket Chat

2 | 3 | 4 | 5 |

Stack:

6 | 13 | 14 |

Dependencies:

15 |

See requirements.txt for dependencies.

16 | 17 |

Deployment:

18 |
    19 |
  1. Clone repository into Python virtual environment and install dependencies: pip install -r requirements.txt
  2. 20 |
  3. Create keys.py file and setup keys required in app_config.
  4. 21 |
  5. Run with: python manage.py runserver
  6. 22 |
23 | 24 |

Licence:

25 |

MIT Licence

-------------------------------------------------------------------------------- /quantaxisbackend/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 15 | 16 | 17 | 18 | 26 | 27 | 28 |
29 | input the code 30 | 31 | 32 |
33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /quantaxisbackend/quotation/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 15 | 16 | 17 | 18 | 26 | 27 | 28 |
29 | input the code 30 | 31 | 32 |
33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /examples/app2.py: -------------------------------------------------------------------------------- 1 | import textwrap 2 | 3 | import tornado.httpserver 4 | import tornado.ioloop 5 | import tornado.options 6 | import tornado.web 7 | 8 | from tornado.options import define, options 9 | define("port", default=8000, help="run on the given port", type=int) 10 | 11 | class ReverseHandler(tornado.web.RequestHandler): 12 | def get(self, input): 13 | self.write(input[::-1]) 14 | 15 | class WrapHandler(tornado.web.RequestHandler): 16 | def post(self): 17 | text = self.get_argument('text') 18 | width = self.get_argument('width', 40) 19 | self.write(textwrap.fill(text, int(width))) 20 | 21 | if __name__ == "__main__": 22 | tornado.options.parse_command_line() 23 | app = tornado.web.Application( 24 | handlers=[ 25 | (r"/reverse/(\w+)", ReverseHandler), 26 | (r"/wrap", WrapHandler) 27 | ] 28 | ) 29 | http_server = tornado.httpserver.HTTPServer(app) 30 | http_server.listen(options.port) 31 | tornado.ioloop.IOLoop.instance().start() -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Vincent yu 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, 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, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /examples/app3.py: -------------------------------------------------------------------------------- 1 | import tornado.httpserver 2 | import tornado.ioloop 3 | import tornado.options 4 | import tornado.web 5 | 6 | import pymongo 7 | 8 | from tornado.options import define, options 9 | define("port", default=8000, help="run on the given port", type=int) 10 | 11 | 12 | class Application(tornado.web.Application): 13 | def __init__(self): 14 | handlers = [(r"/(\w+)", WordHandler)] 15 | conn = pymongo.MongoClient("localhost", 27017) 16 | self.db = conn["example"] 17 | tornado.web.Application.__init__(self, handlers, debug=True) 18 | 19 | 20 | class WordHandler(tornado.web.RequestHandler): 21 | def get(self, word): 22 | coll = self.application.db.words 23 | word_doc = coll.find_one({"word": word}) 24 | if word_doc: 25 | del word_doc["_id"] 26 | self.write(word_doc) 27 | else: 28 | self.set_status(404) 29 | self.write({"error": "word not found"}) 30 | 31 | 32 | if __name__ == "__main__": 33 | tornado.options.parse_command_line() 34 | http_server = tornado.httpserver.HTTPServer(Application()) 35 | http_server.listen(options.port) 36 | tornado.ioloop.IOLoop.instance().start() 37 | -------------------------------------------------------------------------------- /quantaxisbackend/backtest/__init__.py: -------------------------------------------------------------------------------- 1 | # coding:utf-8 2 | # 3 | # The MIT License (MIT) 4 | # 5 | # Copyright (c) 2016-2018 yutiansut/QUANTAXIS 6 | # 7 | # Permission is hereby granted, free of charge, to any person obtaining a copy 8 | # of this software and associated documentation files (the "Software"), to deal 9 | # in the Software without restriction, including without limitation the rights 10 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | # copies of the Software, and to permit persons to whom the Software is 12 | # furnished to do so, subject to the following conditions: 13 | # 14 | # The above copyright notice and this permission notice shall be included in all 15 | # copies or substantial portions of the Software. 16 | # 17 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | # SOFTWARE. -------------------------------------------------------------------------------- /quantaxisbackend/backtest/handles.py: -------------------------------------------------------------------------------- 1 | # coding:utf-8 2 | # 3 | # The MIT License (MIT) 4 | # 5 | # Copyright (c) 2016-2018 yutiansut/QUANTAXIS 6 | # 7 | # Permission is hereby granted, free of charge, to any person obtaining a copy 8 | # of this software and associated documentation files (the "Software"), to deal 9 | # in the Software without restriction, including without limitation the rights 10 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | # copies of the Software, and to permit persons to whom the Software is 12 | # furnished to do so, subject to the following conditions: 13 | # 14 | # The above copyright notice and this permission notice shall be included in all 15 | # copies or substantial portions of the Software. 16 | # 17 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | # SOFTWARE. -------------------------------------------------------------------------------- /quantaxisbackend/data/__init__.py: -------------------------------------------------------------------------------- 1 | # coding:utf-8 2 | # 3 | # The MIT License (MIT) 4 | # 5 | # Copyright (c) 2016-2018 yutiansut/QUANTAXIS 6 | # 7 | # Permission is hereby granted, free of charge, to any person obtaining a copy 8 | # of this software and associated documentation files (the "Software"), to deal 9 | # in the Software without restriction, including without limitation the rights 10 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | # copies of the Software, and to permit persons to whom the Software is 12 | # furnished to do so, subject to the following conditions: 13 | # 14 | # The above copyright notice and this permission notice shall be included in all 15 | # copies or substantial portions of the Software. 16 | # 17 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | # SOFTWARE. -------------------------------------------------------------------------------- /quantaxisbackend/user/__init__.py: -------------------------------------------------------------------------------- 1 | # coding:utf-8 2 | # 3 | # The MIT License (MIT) 4 | # 5 | # Copyright (c) 2016-2018 yutiansut/QUANTAXIS 6 | # 7 | # Permission is hereby granted, free of charge, to any person obtaining a copy 8 | # of this software and associated documentation files (the "Software"), to deal 9 | # in the Software without restriction, including without limitation the rights 10 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | # copies of the Software, and to permit persons to whom the Software is 12 | # furnished to do so, subject to the following conditions: 13 | # 14 | # The above copyright notice and this permission notice shall be included in all 15 | # copies or substantial portions of the Software. 16 | # 17 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | # SOFTWARE. -------------------------------------------------------------------------------- /quantaxisbackend/util/__init__.py: -------------------------------------------------------------------------------- 1 | # coding:utf-8 2 | # 3 | # The MIT License (MIT) 4 | # 5 | # Copyright (c) 2016-2018 yutiansut/QUANTAXIS 6 | # 7 | # Permission is hereby granted, free of charge, to any person obtaining a copy 8 | # of this software and associated documentation files (the "Software"), to deal 9 | # in the Software without restriction, including without limitation the rights 10 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | # copies of the Software, and to permit persons to whom the Software is 12 | # furnished to do so, subject to the following conditions: 13 | # 14 | # The above copyright notice and this permission notice shall be included in all 15 | # copies or substantial portions of the Software. 16 | # 17 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | # SOFTWARE. -------------------------------------------------------------------------------- /quantaxisbackend/quotation/__init__.py: -------------------------------------------------------------------------------- 1 | # coding:utf-8 2 | # 3 | # The MIT License (MIT) 4 | # 5 | # Copyright (c) 2016-2018 yutiansut/QUANTAXIS 6 | # 7 | # Permission is hereby granted, free of charge, to any person obtaining a copy 8 | # of this software and associated documentation files (the "Software"), to deal 9 | # in the Software without restriction, including without limitation the rights 10 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | # copies of the Software, and to permit persons to whom the Software is 12 | # furnished to do so, subject to the following conditions: 13 | # 14 | # The above copyright notice and this permission notice shall be included in all 15 | # copies or substantial portions of the Software. 16 | # 17 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | # SOFTWARE. -------------------------------------------------------------------------------- /quantaxisbackend/__init__.py: -------------------------------------------------------------------------------- 1 | # coding:utf-8 2 | # 3 | # The MIT License (MIT) 4 | # 5 | # Copyright (c) 2016-2018 yutiansut/QUANTAXIS 6 | # 7 | # Permission is hereby granted, free of charge, to any person obtaining a copy 8 | # of this software and associated documentation files (the "Software"), to deal 9 | # in the Software without restriction, including without limitation the rights 10 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | # copies of the Software, and to permit persons to whom the Software is 12 | # furnished to do so, subject to the following conditions: 13 | # 14 | # The above copyright notice and this permission notice shall be included in all 15 | # copies or substantial portions of the Software. 16 | # 17 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | # SOFTWARE. 24 | 25 | from quantaxisbackend.data.handles import StockdayHandler, StockminHandler 26 | from quantaxisbackend.quotation.handles import RealtimeSocketHandler, SimulateSocketHandler 27 | from quantaxisbackend.user.handles import SigninHandler, SignupHandler 28 | from quantaxisbackend.util.handles import BaseHandler 29 | from quantaxisbackend.app import start -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | # coding:utf-8 2 | import codecs 3 | import os 4 | import sys 5 | 6 | try: 7 | from setuptools import setup 8 | except: 9 | from distutils.core import setup 10 | """ 11 | 打包的用的setup必须引入, 12 | """ 13 | 14 | 15 | def read(fname): 16 | 17 | return codecs.open(os.path.join(os.path.dirname(__file__), fname)).read() 18 | 19 | 20 | NAME = "quantaxisbackend" 21 | """ 22 | 名字,一般放你包的名字即可 23 | """ 24 | PACKAGES = ["quantaxisbackend","quantaxisbackend.backtest","quantaxisbackend.data","quantaxisbackend.quotation","quantaxisbackend.user","quantaxisbackend.util"] 25 | """ 26 | 包含的包,可以多个,这是一个列表 27 | """ 28 | 29 | DESCRIPTION = "QUANTAXISBACKEND: WEB" 30 | 31 | 32 | LONG_DESCRIPTION = read("README.rst") 33 | """ 34 | 参见read方法说明 35 | """ 36 | 37 | KEYWORDS = ["quantaxis", "quant", "finance"] 38 | """ 39 | 关于当前包的一些关键字,方便PyPI进行分类。 40 | """ 41 | 42 | AUTHOR = "yutiansut" 43 | 44 | AUTHOR_EMAIL = "yutiansut@qq.com" 45 | 46 | URL = "http://www.yutiansut.com" 47 | 48 | VERSION = "0.1.0" 49 | 50 | 51 | LICENSE = "MIT" 52 | 53 | 54 | setup( 55 | name=NAME, 56 | version=VERSION, 57 | description=DESCRIPTION, 58 | long_description=LONG_DESCRIPTION, 59 | classifiers=[ 60 | 'License :: OSI Approved :: MIT License', 61 | 'Programming Language :: Python', 62 | 'Intended Audience :: Developers', 63 | 'Operating System :: OS Independent', 64 | ], 65 | install_requires=['tornado'], 66 | # entry_points={ 67 | # 'console_scripts': [ 68 | # 'quantaxis=QUANTAXIS.QACmd:QA_cmd' 69 | # ] 70 | # }, 71 | keywords=KEYWORDS, 72 | author=AUTHOR, 73 | author_email=AUTHOR_EMAIL, 74 | url=URL, 75 | license=LICENSE, 76 | packages=PACKAGES, 77 | include_package_data=True, 78 | zip_safe=True, 79 | ) 80 | 81 | # 把上面的变量填入了一个setup()中即可。 -------------------------------------------------------------------------------- /examples/tornado_websocket_chat-master/public/msg/js/msg.js: -------------------------------------------------------------------------------- 1 | var messageForm = document.getElementById("messageForm"); 2 | messageForm.addEventListener("submit", function(event) { 3 | event.preventDefault(); 4 | if (this.message.value) { 5 | var message = { 6 | "code": "msg", 7 | "text": this.message.value 8 | } 9 | socketSend(message); 10 | } 11 | this.message.value = ""; 12 | this.message.focus(); 13 | }); 14 | 15 | 16 | var vueChat = new Vue({ 17 | el: "#vueChat", 18 | data: { 19 | messages: [], 20 | styleObject: { 21 | height: (window.innerHeight-100) + "px" 22 | } 23 | }, 24 | methods: { 25 | updateHeight: function(value) { 26 | this.styleObject.height = (value-100) + "px" 27 | } 28 | } 29 | }); 30 | 31 | 32 | window.addEventListener("resize", function() { 33 | vueChat.updateHeight(window.innerHeight); 34 | }); 35 | 36 | 37 | var socket = new WebSocket("ws://127.0.0.1:8004/websocket"); 38 | 39 | 40 | socket.onopen = function() { 41 | socket.send(JSON.stringify({'code': 'msgs'})); 42 | }; 43 | 44 | 45 | socket.onmessage = function(message) { 46 | var message = JSON.parse(message.data); 47 | if (message['code'] === "msg") { 48 | vueChat.messages.push(message); 49 | } 50 | else if (message['code'] === "msgs") { 51 | vueChat.messages.push.apply(vueChat.messages, message['messages']); 52 | } 53 | setTimeout(() => { 54 | scrollBottom(chatWindow); 55 | }, 10); 56 | }; 57 | 58 | 59 | socket.onclose = function() { 60 | socket.send("disconnect"); 61 | }; 62 | 63 | 64 | function socketSend(message) { 65 | socket.send(JSON.stringify(message)); 66 | } 67 | 68 | 69 | function scrollBottom(element) { 70 | element.scrollTop = element.scrollHeight; 71 | } -------------------------------------------------------------------------------- /quantaxisbackend/util/handles.py: -------------------------------------------------------------------------------- 1 | # coding:utf-8 2 | # 3 | # The MIT License (MIT) 4 | # 5 | # Copyright (c) 2016-2018 yutiansut/QUANTAXIS 6 | # 7 | # Permission is hereby granted, free of charge, to any person obtaining a copy 8 | # of this software and associated documentation files (the "Software"), to deal 9 | # in the Software without restriction, including without limitation the rights 10 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | # copies of the Software, and to permit persons to whom the Software is 12 | # furnished to do so, subject to the following conditions: 13 | # 14 | # The above copyright notice and this permission notice shall be included in all 15 | # copies or substantial portions of the Software. 16 | # 17 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | # SOFTWARE. 24 | from tornado.web import RequestHandler 25 | 26 | 27 | class BaseHandler(RequestHandler): 28 | 29 | def set_default_headers(self): 30 | self.set_header("Access-Control-Allow-Origin", "*") # 这个地方可以写域名 31 | self.set_header("Access-Control-Allow-Headers", "x-requested-with") 32 | self.set_header('Access-Control-Allow-Methods', 'POST, GET, OPTIONS') 33 | 34 | def post(self): 35 | self.write('some post') 36 | 37 | def get(self): 38 | self.write('some get') 39 | 40 | def options(self): 41 | # no body 42 | self.set_status(204) 43 | self.finish() 44 | -------------------------------------------------------------------------------- /examples/tornado_websocket_chat-master/public/chat.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | MSG 7 | 8 | 9 | 10 | 11 | 12 | 13 | 29 | 30 | 31 |
32 |
33 |
34 |
35 |

{{ message['username'] }} > {{ message['text'] }}

36 |
37 |
38 |
39 |
40 | 41 | 42 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /examples/websocket.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # coding:utf-8 3 | import os.path 4 | 5 | import tornado.httpserver 6 | import tornado.web 7 | import tornado.ioloop 8 | import tornado.options 9 | import tornado.httpclient 10 | import tornado.websocket 11 | 12 | import json 13 | 14 | """tornado 的websocket 15 | """ 16 | 17 | 18 | class IndexHandler(tornado.web.RequestHandler): 19 | def get(self): 20 | self.render("index.html") 21 | 22 | 23 | class SocketHandler(tornado.websocket.WebSocketHandler): 24 | """docstring for SocketHandler""" 25 | clients = set() 26 | 27 | @staticmethod 28 | def send_to_all(message): 29 | for c in SocketHandler.clients: 30 | c.write_message(json.dumps(message)) 31 | 32 | def open(self): 33 | self.write_message(json.dumps({ 34 | 'type': 'sys', 35 | 'message': 'Welcome to WebSocket', 36 | })) 37 | SocketHandler.send_to_all({ 38 | 'type': 'sys', 39 | 'message': str(id(self)) + ' has joined', 40 | }) 41 | SocketHandler.clients.add(self) 42 | 43 | def on_close(self): 44 | SocketHandler.clients.remove(self) 45 | SocketHandler.send_to_all({ 46 | 'type': 'sys', 47 | 'message': str(id(self)) + ' has left', 48 | }) 49 | 50 | def on_message(self, message): 51 | SocketHandler.send_to_all({ 52 | 'type': 'user', 53 | 'id': id(self), 54 | 'message': message, 55 | }) 56 | 57 | 58 | # MAIN 59 | if __name__ == '__main__': 60 | app = tornado.web.Application( 61 | handlers=[ 62 | (r"/", IndexHandler), 63 | (r"/chat", SocketHandler) 64 | ], 65 | debug=True, 66 | template_path=os.path.join(os.path.dirname(__file__), "templates"), 67 | static_path=os.path.join(os.path.dirname(__file__), "static") 68 | ) 69 | app.listen(8010) 70 | tornado.ioloop.IOLoop.instance().start() 71 | -------------------------------------------------------------------------------- /examples/app4.py: -------------------------------------------------------------------------------- 1 | import os.path 2 | import tornado.locale 3 | import tornado.httpserver 4 | import tornado.ioloop 5 | import tornado.options 6 | import tornado.web 7 | from tornado.options import define, options 8 | import pymongo 9 | 10 | define("port", default=8000, help="run on the given port", type=int) 11 | 12 | class Application(tornado.web.Application): 13 | def __init__(self): 14 | handlers = [ 15 | (r"/", MainHandler), 16 | (r"/recommended/", RecommendedHandler), 17 | ] 18 | settings = dict( 19 | template_path=os.path.join(os.path.dirname(__file__), "templates"), 20 | static_path=os.path.join(os.path.dirname(__file__), "static"), 21 | ui_modules={"Book": BookModule}, 22 | debug=True, 23 | ) 24 | conn = pymongo.Connection("localhost", 27017) 25 | self.db = conn["bookstore"] 26 | tornado.web.Application.__init__(self, handlers, **settings) 27 | 28 | class MainHandler(tornado.web.RequestHandler): 29 | def get(self): 30 | self.render( 31 | "index.html", 32 | page_title = "Burt's Books | Home", 33 | header_text = "Welcome to Burt's Books!", 34 | ) 35 | 36 | class RecommendedHandler(tornado.web.RequestHandler): 37 | def get(self): 38 | coll = self.application.db.books 39 | books = coll.find() 40 | self.render( 41 | "recommended.html", 42 | page_title = "Burt's Books | Recommended Reading", 43 | header_text = "Recommended Reading", 44 | books = books 45 | ) 46 | 47 | class BookModule(tornado.web.UIModule): 48 | def render(self, book): 49 | return self.render_string( 50 | "modules/book.html", 51 | book=book, 52 | ) 53 | def css_files(self): 54 | return "/static/css/recommended.css" 55 | def javascript_files(self): 56 | return "/static/js/recommended.js" 57 | 58 | if __name__ == "__main__": 59 | tornado.options.parse_command_line() 60 | http_server = tornado.httpserver.HTTPServer(Application()) 61 | http_server.listen(options.port) 62 | tornado.ioloop.IOLoop.instance().start() -------------------------------------------------------------------------------- /examples/app1.py: -------------------------------------------------------------------------------- 1 | #coding :utf-8 2 | # 3 | # The MIT License (MIT) 4 | # 5 | # Copyright (c) 2016-2018 yutiansut/QUANTAXIS 6 | # 7 | # Permission is hereby granted, free of charge, to any person obtaining a copy 8 | # of this software and associated documentation files (the "Software"), to deal 9 | # in the Software without restriction, including without limitation the rights 10 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | # copies of the Software, and to permit persons to whom the Software is 12 | # furnished to do so, subject to the following conditions: 13 | # 14 | # The above copyright notice and this permission notice shall be included in all 15 | # copies or substantial portions of the Software. 16 | # 17 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | # SOFTWARE. 24 | 25 | import tornado.httpserver 26 | import tornado.ioloop 27 | import tornado.options 28 | import tornado.web 29 | 30 | from tornado.options import define, options 31 | define("port", default=8000, help="run on the given port", type=int) 32 | 33 | 34 | class IndexHandler(tornado.web.RequestHandler): 35 | def get(self): 36 | greeting = self.get_argument('greeting', 'Hello') 37 | # Tornado的RequestHandler类有一系列有用的内建方法,包括get_argument,我们在这里从一个查询字符串中取得参数greeting的值。 38 | # (如果这个参数没有出现在查询字符串中,Tornado将使用get_argument的第二个参数作为默认值。) 39 | self.write(greeting + ', friendly user!') 40 | # RequestHandler的另一个有用的方法是write,它以一个字符串作为函数的参数,并将其写入到HTTP响应中。 41 | # 在这里,我们使用请求中greeting参数提供的值插入到greeting中,并写回到响应中。 42 | 43 | 44 | if __name__ == "__main__": 45 | tornado.options.parse_command_line() 46 | app = tornado.web.Application(handlers=[(r"/", IndexHandler)]) 47 | http_server = tornado.httpserver.HTTPServer(app) 48 | http_server.listen(options.port) 49 | tornado.ioloop.IOLoop.instance().start() 50 | -------------------------------------------------------------------------------- /quantaxisbackend/user/handles.py: -------------------------------------------------------------------------------- 1 | # coding:utf-8 2 | # 3 | # The MIT License (MIT) 4 | # 5 | # Copyright (c) 2016-2018 yutiansut/QUANTAXIS 6 | # 7 | # Permission is hereby granted, free of charge, to any person obtaining a copy 8 | # of this software and associated documentation files (the "Software"), to deal 9 | # in the Software without restriction, including without limitation the rights 10 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | # copies of the Software, and to permit persons to whom the Software is 12 | # furnished to do so, subject to the following conditions: 13 | # 14 | # The above copyright notice and this permission notice shall be included in all 15 | # copies or substantial portions of the Software. 16 | # 17 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | # SOFTWARE. 24 | 25 | import datetime 26 | import json 27 | 28 | import tornado 29 | from tornado.web import Application, RequestHandler, authenticated 30 | from tornado.websocket import WebSocketHandler 31 | 32 | from QUANTAXIS.QASU.user import QA_user_sign_in, QA_user_sign_up 33 | from QUANTAXIS.QAUtil.QASql import QA_util_sql_mongo_setting 34 | from quantaxisbackend.util.handles import BaseHandler 35 | 36 | 37 | class SignupHandler(BaseHandler): 38 | def get(self): 39 | username = self.get_argument('user', default='admin') 40 | password = self.get_argument('password', default='admin') 41 | if QA_user_sign_up(username, password, client=QA_util_sql_mongo_setting()): 42 | self.write('SUCCESS') 43 | else: 44 | self.write('WRONG') 45 | 46 | 47 | class SigninHandler(BaseHandler): 48 | def get(self): 49 | username = self.get_argument('user', default='admin') 50 | password = self.get_argument('password', default='admin') 51 | res = QA_user_sign_in(username, password, 52 | client=QA_util_sql_mongo_setting()) 53 | if res is not None: 54 | self.write('SUCCESS') 55 | else: 56 | self.write('WRONG') 57 | 58 | 59 | if __name__ == '__main__': 60 | app = Application( 61 | handlers=[ 62 | 63 | (r"/user/signin", SigninHandler), 64 | (r"/user/signup", SignupHandler) 65 | ], 66 | debug=True 67 | ) 68 | app.listen(8010) 69 | tornado.ioloop.IOLoop.instance().start() 70 | -------------------------------------------------------------------------------- /quantaxisbackend/app.py: -------------------------------------------------------------------------------- 1 | # coding:utf-8 2 | # 3 | # The MIT License (MIT) 4 | # 5 | # Copyright (c) 2016-2018 yutiansut/QUANTAXIS 6 | # 7 | # Permission is hereby granted, free of charge, to any person obtaining a copy 8 | # of this software and associated documentation files (the "Software"), to deal 9 | # in the Software without restriction, including without limitation the rights 10 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | # copies of the Software, and to permit persons to whom the Software is 12 | # furnished to do so, subject to the following conditions: 13 | # 14 | # The above copyright notice and this permission notice shall be included in all 15 | # copies or substantial portions of the Software. 16 | # 17 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | # SOFTWARE. 24 | import tornado 25 | from tornado.web import Application, RequestHandler, authenticated 26 | 27 | from quantaxisbackend.data.handles import StockdayHandler, StockminHandler 28 | from quantaxisbackend.quotation.handles import (RealtimeSocketHandler, 29 | SimulateSocketHandler) 30 | from quantaxisbackend.user.handles import SigninHandler, SignupHandler 31 | from quantaxisbackend.util.handles import BaseHandler 32 | 33 | 34 | class INDEX(BaseHandler): 35 | def get(self): 36 | self.render("index.html") 37 | 38 | 39 | def start(): 40 | app = Application( 41 | handlers=[ 42 | (r"/", INDEX), 43 | (r"/stock/day", StockdayHandler), 44 | (r"/stock/min", StockminHandler), 45 | (r"/user/signin", SigninHandler), 46 | (r"/user/signup", SignupHandler), 47 | (r"/realtime", RealtimeSocketHandler), 48 | (r"/simulate", SimulateSocketHandler) 49 | ], 50 | debug=True 51 | ) 52 | app.listen(8010) 53 | tornado.ioloop.IOLoop.instance().start() 54 | 55 | 56 | if __name__ == '__main__': 57 | app = Application( 58 | handlers=[ 59 | (r"/", INDEX), 60 | (r"/stock/day", StockdayHandler), 61 | (r"/stock/min", StockminHandler), 62 | (r"/user/signin", SigninHandler), 63 | (r"/user/signup", SignupHandler), 64 | (r"/realtime", RealtimeSocketHandler), 65 | (r"/simulate", SimulateSocketHandler) 66 | ], 67 | debug=True 68 | ) 69 | app.listen(8010) 70 | tornado.ioloop.IOLoop.instance().start() 71 | -------------------------------------------------------------------------------- /examples/tornado_websocket_chat-master/public/msg/css/msg.css: -------------------------------------------------------------------------------- 1 | * { 2 | margin: 0px; 3 | padding: 0px; 4 | box-sizing: border-box; 5 | border: none; 6 | } 7 | 8 | body { 9 | background-color: #756D47; 10 | font-family: "Open Sans", sans-serif; 11 | font-size: 18px; 12 | color: #fff; 13 | } 14 | 15 | .bottom {bottom: 0px;} 16 | 17 | .btn { 18 | background-color: rgba(0,0,0,0.5); 19 | height: 40px; 20 | font-size: 18px; 21 | color: orange; 22 | } 23 | 24 | .btn:hover { 25 | background-color: rgba(255,255,255,0.1); 26 | cursor: pointer; 27 | color: orange; 28 | } 29 | 30 | .container { 31 | margin-left: 15px; 32 | margin-right: 15px; 33 | width: auto; 34 | } 35 | 36 | .cover { 37 | width: 100%; 38 | height: 100vh; 39 | } 40 | 41 | .fixed {position: fixed;} 42 | 43 | .flex-col { 44 | display: flex; 45 | flex-direction: column; 46 | } 47 | 48 | .flex-row { 49 | display: flex; 50 | flex-direction: row; 51 | } 52 | 53 | .input { 54 | padding-left: 5px; 55 | background-color: transparent; 56 | height: 40px; 57 | border: 2px solid rgba(255,255,255,0.1); 58 | font-size: 18px; 59 | color: #fff; 60 | } 61 | 62 | .input:active, 63 | .input:focus { 64 | color: #fff; 65 | border-color: orange; 66 | } 67 | 68 | .h-center { 69 | display: flex; 70 | justify-content: center; 71 | } 72 | 73 | .margin-0 { 74 | margin: 0px; 75 | } 76 | 77 | .message { 78 | word-wrap: break-word; 79 | word-break: break-all; 80 | } 81 | 82 | .navbar { 83 | width: 100%; 84 | background-color: rgba(0,0,0,0.5); 85 | height: 50px; 86 | } 87 | 88 | .navLink { 89 | height: 50px; 90 | padding-left: 15px; 91 | padding-right: 15px; 92 | display: flex; 93 | align-items: center; 94 | color: #fff; 95 | text-decoration: none; 96 | } 97 | 98 | .navLink:hover { 99 | background-color: rgba(255,255,255,0.1); 100 | color: orange; 101 | } 102 | 103 | .row-reverse { 104 | display: flex; 105 | flex-direction: row-reverse; 106 | } 107 | 108 | .v-center { 109 | display: flex; 110 | align-items: center; 111 | } 112 | 113 | .top {top: 0px;} 114 | .w-100 {width: 100%;} 115 | 116 | [class*='col-'] { 117 | float: left; 118 | min-height: 1px; 119 | } 120 | 121 | .col-xs-2 {width: 16.66%;} 122 | .col-xs-3 {width: 25%;} 123 | .col-xs-4 {width: 33.33%;} 124 | .col-xs-5 {width: 41.66%;} 125 | .col-xs-6 {width: 50.00%;} 126 | .col-xs-7 {width: 58.33%;} 127 | .col-xs-8 {width: 66.66%;} 128 | .col-xs-9 {width: 75%;} 129 | .col-xs-10 {width: 83.33%;} 130 | 131 | @media (min-width: 640px) { 132 | .col-sm-2 {width: 16.66%;} 133 | .col-sm-3 {width: 25%;} 134 | .col-sm-4 {width: 33.33%;} 135 | .col-sm-5 {width: 41.66%;} 136 | .col-sm-6 {width: 50.00%;} 137 | .col-sm-7 {width: 58.33%;} 138 | .col-sm-8 {width: 66.66%;} 139 | .col-sm-9 {width: 75%;} 140 | .col-sm-10 {width: 83.33%;} 141 | } -------------------------------------------------------------------------------- /quantaxisbackend/quotation/handles.py: -------------------------------------------------------------------------------- 1 | # coding:utf-8 2 | # 3 | # The MIT License (MIT) 4 | # 5 | # Copyright (c) 2016-2018 yutiansut/QUANTAXIS 6 | # 7 | # Permission is hereby granted, free of charge, to any person obtaining a copy 8 | # of this software and associated documentation files (the "Software"), to deal 9 | # in the Software without restriction, including without limitation the rights 10 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | # copies of the Software, and to permit persons to whom the Software is 12 | # furnished to do so, subject to the following conditions: 13 | # 14 | # The above copyright notice and this permission notice shall be included in all 15 | # copies or substantial portions of the Software. 16 | # 17 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | # SOFTWARE. 24 | 25 | import os 26 | import time 27 | 28 | import tornado 29 | from tornado.web import Application, RequestHandler, authenticated 30 | from tornado.websocket import WebSocketHandler 31 | 32 | import QUANTAXIS as QA 33 | from quantaxisbackend.util.handles import BaseHandler 34 | 35 | 36 | """ 37 | 要实现2个api 38 | 39 | 1. SIMULATED WEBSOCKET 40 | 41 | 2. REALTIME WEBSOCKET 42 | 43 | """ 44 | 45 | 46 | class INDEX(BaseHandler): 47 | def get(self): 48 | self.render("index.html") 49 | 50 | 51 | class RealtimeSocketHandler(WebSocketHandler): 52 | def open(self): 53 | print('socket start') 54 | 55 | def on_message(self, message): 56 | self.write_message('message {}'.format(message)) 57 | 58 | def on_close(self): 59 | print('connection close') 60 | 61 | 62 | class SimulateSocketHandler(WebSocketHandler): 63 | def open(self): 64 | self.write_message('start') 65 | 66 | def on_message(self, message): 67 | if len(str(message)) == 6: 68 | data = QA.QA_util_to_json_from_pandas( 69 | QA.QA_fetch_stock_day(message, '2017-01-01', '2017-01-05', 'pd')) 70 | for item in data: 71 | self.write_message(item) 72 | time.sleep(0.1) 73 | 74 | def on_close(self): 75 | print('connection close') 76 | 77 | 78 | if __name__ == '__main__': 79 | app = Application( 80 | handlers=[ 81 | (r"/", INDEX), 82 | (r"/realtime", RealtimeSocketHandler), 83 | (r"/simulate", SimulateSocketHandler) 84 | ], 85 | debug=True 86 | ) 87 | app.listen(8010) 88 | tornado.ioloop.IOLoop.instance().start() 89 | -------------------------------------------------------------------------------- /quantaxisbackend/data/handles.py: -------------------------------------------------------------------------------- 1 | # coding:utf-8 2 | # 3 | # The MIT License (MIT) 4 | # 5 | # Copyright (c) 2016-2018 yutiansut/QUANTAXIS 6 | # 7 | # Permission is hereby granted, free of charge, to any person obtaining a copy 8 | # of this software and associated documentation files (the "Software"), to deal 9 | # in the Software without restriction, including without limitation the rights 10 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | # copies of the Software, and to permit persons to whom the Software is 12 | # furnished to do so, subject to the following conditions: 13 | # 14 | # The above copyright notice and this permission notice shall be included in all 15 | # copies or substantial portions of the Software. 16 | # 17 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | # SOFTWARE. 24 | 25 | import datetime 26 | import json 27 | 28 | import tornado 29 | from tornado.web import Application, RequestHandler, authenticated 30 | from tornado.websocket import WebSocketHandler 31 | 32 | from QUANTAXIS.QAFetch.QAQuery import QA_fetch_stock_day, QA_fetch_stock_min 33 | from QUANTAXIS.QAFetch.QAQuery_Advance import QA_fetch_stock_day_adv 34 | from QUANTAXIS.QAUtil.QATransform import QA_util_to_json_from_pandas 35 | from quantaxisbackend.util.handles import BaseHandler 36 | 37 | 38 | class StockdayHandler(BaseHandler): 39 | def get(self): 40 | """ 41 | 采用了get_arguents来获取参数 42 | 默认参数: code-->000001 start-->2017-01-01 end-->today 43 | 44 | """ 45 | code = self.get_argument('code', default='000001') 46 | start = self.get_argument('start', default='2017-01-01') 47 | end = self.get_argument('end', default=str(datetime.date.today())) 48 | data = QA_util_to_json_from_pandas( 49 | QA_fetch_stock_day(code, start, end, format='pd')) 50 | 51 | self.write({'result': data}) 52 | 53 | 54 | class StockminHandler(BaseHandler): 55 | def get(self): 56 | """ 57 | 采用了get_arguents来获取参数 58 | 默认参数: code-->000001 start-->2017-01-01 09:00:00 end-->now 59 | 60 | """ 61 | code = self.get_argument('code', default='000001') 62 | start = self.get_argument('start', default='2017-01-01 09:00:00') 63 | end = self.get_argument('end', default=str(datetime.datetime.now())) 64 | frequence = self.get_argument('frequence', default='1min') 65 | data = QA_util_to_json_from_pandas( 66 | QA_fetch_stock_min(code, start, end, format='pd', frequence=frequence)) 67 | 68 | self.write({'result': data}) 69 | 70 | 71 | if __name__ == "__main__": 72 | 73 | app = Application( 74 | handlers=[ 75 | (r"/stock/day", StockdayHandler), 76 | (r"/stock/min", StockminHandler) 77 | ], 78 | debug=True 79 | ) 80 | app.listen(8010) 81 | tornado.ioloop.IOLoop.current().start() 82 | -------------------------------------------------------------------------------- /examples/tornado_websocket_chat-master/app/app_handlers.py: -------------------------------------------------------------------------------- 1 | import json 2 | from tornado.web import RequestHandler 3 | from tornado.web import authenticated 4 | from tornado.websocket import WebSocketHandler 5 | from app import app_cache as cache 6 | from app import app_services as services 7 | from app.app_config import config 8 | 9 | 10 | class BaseHandler(RequestHandler): 11 | def get_current_user(self): 12 | return self.get_secure_cookie("user") 13 | 14 | 15 | class IndexHandler(BaseHandler): 16 | def get(self): 17 | if self.current_user: 18 | self.redirect("/chat") 19 | else: 20 | with open(config["static_path"] + "/index.html", 'r') as file: 21 | self.write(file.read()) 22 | 23 | 24 | class ConnectionHandler(BaseHandler): 25 | def post(self): 26 | try: 27 | # If Javascript is enabled -> JSON is posted 28 | username = json.loads(self.request.body.decode())["username"] 29 | except: 30 | # If Javascript is disabled -> form is posted 31 | username = self.get_argument("username") 32 | if username and (username not in cache.users): 33 | self.set_secure_cookie("user", username) 34 | cache.users[username] = username 35 | self.redirect("/chat") 36 | message = { 37 | "code": "msg", 38 | "username": "HOST", 39 | "text": username + " connected" 40 | } 41 | message = json.dumps(message) 42 | services.broadcast(message) 43 | else: 44 | self.redirect("/") 45 | 46 | 47 | class DisconnectionHandler(BaseHandler): 48 | @authenticated 49 | def get(self): 50 | username = self.current_user.decode() 51 | self.set_secure_cookie("user", "") 52 | try: 53 | del cache.users[username] 54 | except KeyError: 55 | pass 56 | message = { 57 | "code": "msg", 58 | "username": "HOST", 59 | "text": username + " disconnected" 60 | } 61 | message = json.dumps(message) 62 | services.broadcast(message) 63 | return self.redirect("/") 64 | 65 | 66 | class ChatHandler(BaseHandler): 67 | @authenticated 68 | def get(self): 69 | if self.current_user: 70 | with open(config["static_path"] + "/chat.html", 'r') as file: 71 | self.write(file.read()) 72 | else: 73 | self.redirect("/") 74 | 75 | 76 | class WebSocketHandler(WebSocketHandler): 77 | 78 | def open(self): 79 | cache.clients.add(self) 80 | 81 | def on_message(self, message): 82 | message = json.loads(message) 83 | if message['code'] == 'msg': 84 | message['username'] = self.get_secure_cookie("user").decode() 85 | cache.messages.append(message) 86 | message = json.dumps(message) 87 | [client.write_message(message) for client in cache.clients] 88 | elif message['code'] == 'msgs': 89 | message['messages'] = cache.messages 90 | self.write_message(json.dumps(message)) 91 | 92 | def on_close(self): 93 | cache.clients.remove(self) 94 | 95 | 96 | class ResetHandler(RequestHandler): 97 | """ Clear cached messages. """ 98 | 99 | def get(self): 100 | cache.messages = [] 101 | self.redirect("/") 102 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # QUANTAXIS 的后台api 2 | 3 | 4 | * 1. [后端的标准和格式规范](#) 5 | * 1.1. [基础标准](#-1) 6 | * 2. [命名格式](#-1) 7 | * 3. [后端的实现方式和注意事项](#-1) 8 | * 3.1. [跨域支持](#-1) 9 | * 3.1.1. [Flask](#Flask) 10 | * 3.1.2. [Tornado](#Tornado) 11 | * 3.1.3. [express](#express) 12 | * 3.2. [权限](#-1) 13 | * 4. [必须实现的部分](#-1) 14 | * 4.1. [用户管理 /user](#user) 15 | * 4.1.1. [登陆](#-1) 16 | * 4.1.2. [注册](#-1) 17 | * 4.2. [回测部分 /backtest](#backtest) 18 | * 4.2.1. [回测概览(列表查询)](#-1) 19 | * 4.2.2. [单个回测结果查询()](#-1) 20 | * 4.3. [行情查询部分 /marketdata & /data](#marketdatadata) 21 | * 4.3.1. [URI总规则 GENERAL URI RULE](#URIGENERALURIRULE) 22 | * 4.3.2. [股票日线 STOCK DAY](#STOCKDAY) 23 | * 4.3.3. [股票分钟线 STOCK MINDATA](#STOCKMINDATA) 24 | * 4.3.4. [股票实时上下五档 STOCK REALTIME 5-ASK/BID](#STOCKREALTIME5-ASKBID) 25 | * 4.3.5. [股票分笔数据 STOCK TRANSACTION](#STOCKTRANSACTION) 26 | * 4.3.6. [股票财务数据](#-1) 27 | * 4.3.7. [期货日线](#-1) 28 | * 4.3.8. [期货分钟线](#-1) 29 | * 4.4. [实时行情推送 /quotation](#quotation) 30 | 31 | 35 | 36 | 37 | 38 | quantaxis 采用前后端分离的模式开发,所以对于后端而言 是一个可以快速替换/语言随意的部分.只需要按照规则设置好REST的url即可 39 | 40 | 41 | ## 1. 后端的标准和格式规范 42 | 43 | ### 1.1. 基础标准 44 | 45 | quantaxis的后台可以用 nodejs(express/koa), python(flask/django/tornado), go 等等语言实现 46 | 47 | quantaxis的后台部分主要是作为微服务,给前端(web/client/app)等提供标准化的查询/交互接口 48 | 49 | 50 | ## 2. 命名格式 51 | 52 | quantaxis的后台命名格式 53 | 54 | http://ip:port/功能(backtest/marketdata/user/..)/细分功能(info/query_code/..) 55 | 56 | example: 57 | 58 | ``` 59 | http://localhost:3000/backtest/info_cookie?cookie=xxxxx ==> 按backtest的cookie查询backtest的信息 60 | 61 | ``` 62 | 63 | ## 3. 后端的实现方式和注意事项 64 | 65 | 66 | ### 3.1. 跨域支持 67 | 68 | 因为是前后端分离的模式, 需要对于url采取跨域允许 69 | 70 | 跨域在python中的实现 71 | 72 | #### 3.1.1. Flask 73 | 74 | ```python 75 | @app.route("/status") 76 | def status(): 77 | rst = make_response(jsonify('200')) 78 | rst.headers['Access-Control-Allow-Origin'] = '*' 79 | rst.headers['Access-Control-Allow-Methods'] = 'PUT,GET,POST,DELETE' 80 | allow_headers = "Referer,Accept,Origin,User-Agent" 81 | rst.headers['Access-Control-Allow-Headers'] = allow_headers 82 | return rst 83 | 84 | ``` 85 | 86 | 87 | #### 3.1.2. Tornado 88 | 89 | ```python 90 | class BaseHandler(tornado.web.RequestHandler): 91 | 92 | def set_default_headers(self): 93 | print("setting headers!!!") 94 | self.set_header("Access-Control-Allow-Origin", "*") # 这个地方可以写域名 95 | self.set_header("Access-Control-Allow-Headers", "x-requested-with") 96 | self.set_header('Access-Control-Allow-Methods', 'POST, GET, OPTIONS') 97 | 98 | def post(self): 99 | self.write('some post') 100 | 101 | def get(self): 102 | self.write('some get') 103 | 104 | def options(self): 105 | # no body 106 | self.set_status(204) 107 | self.finish() 108 | ``` 109 | 110 | 跨域在nodejs中的实现 111 | 112 | #### 3.1.3. express 113 | 114 | ```javascript 115 | 116 | router.get('*', function (req, res, next) { 117 | res.header("Access-Control-Allow-Origin", "*"); 118 | res.header("Access-Control-Allow-Headers", "X-Requested-With"); 119 | res.header("Access-Control-Allow-Methods", "PUT,POST,GET,DELETE,OPTIONS"); 120 | res.header("X-Powered-By", ' 3.2.1') 121 | res.header("Content-Type", "application/json;charset=utf-8"); 122 | next(); 123 | }); 124 | 125 | ``` 126 | 127 | ### 3.2. 权限 128 | 129 | 后台服务需要保护好隐私不被泄露,避免路径攻击和端口暴露等问题 130 | 131 | ## 4. 必须实现的部分 132 | 133 | 134 | ### 4.1. 用户管理 /user 135 | 136 | #### 4.1.1. 登陆 137 | ``` 138 | http://[ip]:[port]/users/login?name=[]&password=[] 139 | ``` 140 | #### 4.1.2. 注册 141 | ``` 142 | http://[ip]:[port]/users/signup?name=[]&password=[] 143 | ``` 144 | 145 | ### 4.2. 回测部分 /backtest 146 | 147 | #### 4.2.1. 回测概览(列表查询) 148 | ``` 149 | http://[ip]:[port]/backtest/list?user=[] 150 | ``` 151 | 152 | #### 4.2.2. 单个回测结果查询() 153 | ``` 154 | http://[ip]:[port]/backtest/info?cookie=[] 155 | ``` 156 | 157 | ### 4.3. 行情查询部分 /marketdata & /data 158 | 159 | 功能性的API,分别代表着 日线/分钟线/实时(5档)/分笔数据 160 | 161 | #### 4.3.1. URI总规则 GENERAL URI RULE 162 | ``` 163 | 总URI为 http://[ip]:[port]/[market_type]/[frequence]?code=[]&start=[]&end=[] 164 | ``` 165 | 166 | #### 4.3.2. 股票日线 STOCK DAY 167 | ``` 168 | http://[ip]:[port]/marketdata/stock/day?code=[]&start=[]&end=[] 169 | ``` 170 | 171 | 当不给定结束日期的时候,返回的就是直到当前的数据 172 | 173 | #### 4.3.3. 股票分钟线 STOCK MINDATA 174 | ``` 175 | http://[ip]:[port]/marketdata/stock/min?code=[]&start=[]&end=[] 176 | ``` 177 | 178 | 当不给定结束日期的时候,返回的就是直到当前的数据 179 | 180 | #### 4.3.4. 股票实时上下五档 STOCK REALTIME 5-ASK/BID 181 | ``` 182 | http://[ip]:[port]/marketdata/stock/realtime?code=[] 183 | ``` 184 | 185 | 实时返回股票的L1上下五档的行情数据 186 | 187 | #### 4.3.5. 股票分笔数据 STOCK TRANSACTION 188 | ``` 189 | http://[ip]:[port]/marketdata/stock/transaction?code=[]&start=[]&end=[] 190 | ``` 191 | code 指的是具体的股票代码 192 | start 指的是分笔开始的时间 193 | end 指的是分笔结束的时间 194 | 195 | #### 4.3.6. 股票财务数据 196 | ``` 197 | http://[ip]:[port]/marketdata/stock/info?code=[]&time=[] 198 | ``` 199 | code 指的是具体的股票 200 | time 指的是时间段 201 | 202 | 如 code=000001 time=2018Q1 指的是000001的2018年1季度 203 | 204 | time的格式为: YEAR['YYYY']+Q+times[1,2,3,4](1- 1季度财报 2- 半年度财报 3- 3季度财报 4- 年报) 205 | 206 | #### 4.3.7. 期货日线 207 | ``` 208 | http://[ip]:[port]/marketdata/future/day?code=[]&start=[]&end=[] 209 | ``` 210 | 211 | #### 4.3.8. 期货分钟线 212 | ``` 213 | http://[ip]:[port]/marketdata/future/min?code=[]&start=[]&end=[] 214 | ``` 215 | ### 4.4. 实时行情推送 /quotation 216 | ``` 217 | /quotation 推送指的是 建立一个websocket链接: 218 | ``` 219 | 1. user login [Handler] 220 | 221 | 2. auth [] 222 | 223 | 3. send_req [front end/client] 224 | 225 | 4. make connection 226 | 227 | 5. data transport 228 | -------------------------------------------------------------------------------- /quantaxisbackend/quotation/websocket.md: -------------------------------------------------------------------------------- 1 | # WEBSOCKET 2 | 3 | 4 | * 1. [WebSocketHandler.open(*args, **kwargs)[source]](#WebSocketHandler.openargskwargssource) 5 | * 2. [WebSocketHandler.on_message(message)[source]](#WebSocketHandler.on_messagemessagesource) 6 | * 3. [WebSocketHandler.on_close()[source]](#WebSocketHandler.on_closesource) 7 | * 4. [WebSocketHandler.select_subprotocol(subprotocols)[source]](#WebSocketHandler.select_subprotocolsubprotocolssource) 8 | * 5. [WebSocketHandler.on_ping(data)[source]](#WebSocketHandler.on_pingdatasource) 9 | * 6. [WebSocketHandler.write_message(message, binary=False)[source]](#WebSocketHandler.write_messagemessagebinaryFalsesource) 10 | * 7. [WebSocketHandler.close(code=None, reason=None)[source]](#WebSocketHandler.closecodeNonereasonNonesource) 11 | * 8. [WebSocketHandler.check_origin(origin)[source]](#WebSocketHandler.check_originoriginsource) 12 | * 9. [WebSocketHandler.get_compression_options()[source]](#WebSocketHandler.get_compression_optionssource) 13 | * 10. [WebSocketHandler.set_nodelay(value)[source]](#WebSocketHandler.set_nodelayvaluesource) 14 | * 11. [WebSocketHandler.ping(data)[source]](#WebSocketHandler.pingdatasource) 15 | * 12. [WebSocketHandler.on_pong(data)[source]](#WebSocketHandler.on_pongdatasource) 16 | * 13. [tornado.websocket.websocket_connect(url, io_loop=None, callback=None, connect_timeout=None, on_message_callback=None, compression_options=None, ping_interval=None, ping_timeout=None, max_message_size=None)[source]](#tornado.websocket.websocket_connecturlio_loopNonecallbackNoneconnect_timeoutNoneon_message_callbackNonecompression_optionsNoneping_intervalNoneping_timeoutNonemax_message_sizeNonesource) 17 | * 14. [class tornado.websocket.WebSocketClientConnection(io_loop, request, on_message_callback=None, compression_options=None, ping_interval=None, ping_timeout=None, max_message_size=None)[source]](#classtornado.websocket.WebSocketClientConnectionio_looprequeston_message_callbackNonecompression_optionsNoneping_intervalNoneping_timeoutNonemax_message_sizeNonesource) 18 | * 15. [write_message(message, binary=False)[source]](#write_messagemessagebinaryFalsesource) 19 | * 16. [read_message(callback=None)[source]](#read_messagecallbackNonesource) 20 | 21 | 25 | 26 | 27 | Event handlers 28 | ## 1. WebSocketHandler.open(*args, **kwargs)[source] 29 | Invoked when a new WebSocket is opened. 30 | 31 | The arguments to open are extracted from the tornado.web.URLSpec regular expression, just like the arguments to tornado.web.RequestHandler.get. 32 | 33 | ## 2. WebSocketHandler.on_message(message)[source] 34 | Handle incoming messages on the WebSocket 35 | 36 | This method must be overridden. 37 | 38 | Changed in version 4.5: on_message can be a coroutine. 39 | 40 | ## 3. WebSocketHandler.on_close()[source] 41 | Invoked when the WebSocket is closed. 42 | 43 | If the connection was closed cleanly and a status code or reason phrase was supplied, these values will be available as the attributes self.close_code and self.close_reason. 44 | 45 | Changed in version 4.0: Added close_code and close_reason attributes. 46 | 47 | ## 4. WebSocketHandler.select_subprotocol(subprotocols)[source] 48 | Invoked when a new WebSocket requests specific subprotocols. 49 | 50 | subprotocols is a list of strings identifying the subprotocols proposed by the client. This method may be overridden to return one of those strings to select it, or None to not select a subprotocol. Failure to select a subprotocol does not automatically abort the connection, although clients may close the connection if none of their proposed subprotocols was selected. 51 | 52 | ## 5. WebSocketHandler.on_ping(data)[source] 53 | Invoked when the a ping frame is received. 54 | 55 | 56 | Output 57 | ## 6. WebSocketHandler.write_message(message, binary=False)[source] 58 | Sends the given message to the client of this Web Socket. 59 | 60 | The message may be either a string or a dict (which will be encoded as json). If the binary argument is false, the message will be sent as utf8; in binary mode any byte string is allowed. 61 | 62 | If the connection is already closed, raises WebSocketClosedError. 63 | 64 | Changed in version 3.2: WebSocketClosedError was added (previously a closed connection would raise an AttributeError) 65 | 66 | Changed in version 4.3: Returns a Future which can be used for flow control. 67 | 68 | ## 7. WebSocketHandler.close(code=None, reason=None)[source] 69 | Closes this Web Socket. 70 | 71 | Once the close handshake is successful the socket will be closed. 72 | 73 | code may be a numeric status code, taken from the values defined in RFC 6455 section 7.4.1. reason may be a textual message about why the connection is closing. These values are made available to the client, but are not otherwise interpreted by the websocket protocol. 74 | 75 | Changed in version 4.0: Added the code and reason arguments. 76 | 77 | Configuration 78 | ## 8. WebSocketHandler.check_origin(origin)[source] 79 | Override to enable support for allowing alternate origins. 80 | 81 | The origin argument is the value of the Origin HTTP header, the url responsible for initiating this request. This method is not called for clients that do not send this header; such requests are always allowed (because all browsers that implement WebSockets support this header, and non-browser clients do not have the same cross-site security concerns). 82 | 83 | Should return True to accept the request or False to reject it. By default, rejects all requests with an origin on a host other than this one. 84 | 85 | This is a security protection against cross site scripting attacks on browsers, since WebSockets are allowed to bypass the usual same-origin policies and don’t use CORS headers. 86 | 87 | Warning 88 | 89 | This is an important security measure; don’t disable it without understanding the security implications. In particular, if your authentication is cookie-based, you must either restrict the origins allowed by check_origin() or implement your own XSRF-like protection for websocket connections. See these articles for more. 90 | 91 | To accept all cross-origin traffic (which was the default prior to Tornado 4.0), simply override this method to always return true: 92 | 93 | def check_origin(self, origin): 94 | return True 95 | To allow connections from any subdomain of your site, you might do something like: 96 | 97 | def check_origin(self, origin): 98 | parsed_origin = urllib.parse.urlparse(origin) 99 | return parsed_origin.netloc.endswith(".mydomain.com") 100 | New in version 4.0. 101 | 102 | ## 9. WebSocketHandler.get_compression_options()[source] 103 | Override to return compression options for the connection. 104 | 105 | If this method returns None (the default), compression will be disabled. If it returns a dict (even an empty one), it will be enabled. The contents of the dict may be used to control the following compression options: 106 | 107 | compression_level specifies the compression level. 108 | 109 | mem_level specifies the amount of memory used for the internal compression state. 110 | 111 | These parameters are documented in details here: https://docs.python.org/3.6/library/zlib.html#zlib.compressobj 112 | New in version 4.1. 113 | 114 | Changed in version 4.5: Added compression_level and mem_level. 115 | 116 | ## 10. WebSocketHandler.set_nodelay(value)[source] 117 | Set the no-delay flag for this stream. 118 | 119 | By default, small messages may be delayed and/or combined to minimize the number of packets sent. This can sometimes cause 200-500ms delays due to the interaction between Nagle’s algorithm and TCP delayed ACKs. To reduce this delay (at the expense of possibly increasing bandwidth usage), call self.set_nodelay(True) once the websocket connection is established. 120 | 121 | See BaseIOStream.set_nodelay for additional details. 122 | 123 | New in version 3.1. 124 | 125 | Other 126 | ## 11. WebSocketHandler.ping(data)[source] 127 | Send ping frame to the remote end. 128 | 129 | ## 12. WebSocketHandler.on_pong(data)[source] 130 | Invoked when the response to a ping frame is received. 131 | 132 | exception tornado.websocket.WebSocketClosedError[source] 133 | Raised by operations on a closed connection. 134 | 135 | New in version 3.2. 136 | 137 | Client-side support 138 | ## 13. tornado.websocket.websocket_connect(url, io_loop=None, callback=None, connect_timeout=None, on_message_callback=None, compression_options=None, ping_interval=None, ping_timeout=None, max_message_size=None)[source] 139 | Client-side websocket support. 140 | 141 | Takes a url and returns a Future whose result is a WebSocketClientConnection. 142 | 143 | compression_options is interpreted in the same way as the return value of WebSocketHandler.get_compression_options. 144 | 145 | The connection supports two styles of operation. In the coroutine style, the application typically calls read_message in a loop: 146 | 147 | conn = yield websocket_connect(url) 148 | while True: 149 | msg = yield conn.read_message() 150 | if msg is None: break 151 | # Do something with msg 152 | In the callback style, pass an on_message_callback to websocket_connect. In both styles, a message of None indicates that the connection has been closed. 153 | 154 | Changed in version 3.2: Also accepts HTTPRequest objects in place of urls. 155 | 156 | Changed in version 4.1: Added compression_options and on_message_callback. The io_loop argument is deprecated. 157 | 158 | Changed in version 4.5: Added the ping_interval, ping_timeout, and max_message_size arguments, which have the same meaning as in WebSocketHandler. 159 | 160 | ## 14. class tornado.websocket.WebSocketClientConnection(io_loop, request, on_message_callback=None, compression_options=None, ping_interval=None, ping_timeout=None, max_message_size=None)[source] 161 | WebSocket client connection. 162 | 163 | This class should not be instantiated directly; use the websocket_connect function instead. 164 | 165 | close(code=None, reason=None)[source] 166 | Closes the websocket connection. 167 | 168 | code and reason are documented under WebSocketHandler.close. 169 | 170 | New in version 3.2. 171 | 172 | Changed in version 4.0: Added the code and reason arguments. 173 | 174 | ## 15. write_message(message, binary=False)[source] 175 | Sends a message to the WebSocket server. 176 | 177 | ## 16. read_message(callback=None)[source] 178 | Reads a message from the WebSocket server. 179 | 180 | If on_message_callback was specified at WebSocket initialization, this function will never return messages 181 | 182 | Returns a future whose result is the message, or None if the connection is closed. If a callback argument is given it will be called with the future when it is ready. 183 | --------------------------------------------------------------------------------