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 |
43 |
44 |
54 |
55 |
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 |
--------------------------------------------------------------------------------